Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions med/choice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,7 @@ struct choice_enc : choice_if
}
else
{
//tag of this IE isn't in header
if constexpr (!explicit_meta_in<mi, typename TO::header_type>())
{
using tag_t = get_info_t<meta::list_first_t<mi>>;
tag_t const tag{};
//TODO: how to not modify?
const_cast<TO&>(to).header().set_tag(tag.get());
}
if(!to.header().is_tag_set()) { MED_THROW_EXCEPTION(unknown_tag, name<TO>(), to.index()); }
med::encode(encoder, to.header());
//skip 1st TAG meta-info as it's encoded in header
sl::ie_encode<type_context<IE_CHOICE, meta::list_rest_t<mi>>>(encoder, to.template as<IE>());
Expand Down Expand Up @@ -256,6 +249,9 @@ struct choice_header
template <AHasGetTag HEADER>
struct choice_header<HEADER>
{
// each compound header for a choice must have bool is_tag_set() method together with get_tag()
static_assert(std::is_same<bool, decltype(std::declval<HEADER>().is_tag_set())>());

static constexpr bool plain_header = false; //compound header e.g. a sequence

using header_type = HEADER;
Expand Down Expand Up @@ -319,6 +315,17 @@ class choice : public IE<IE_CHOICE>
m_index = idx;
new (&m_storage) type{};
}
if constexpr (!choice::plain_header)
{
// we must not do it on a decode stage when the header tag has been already set
if(!this->header().is_tag_set())
{
using TAG_TYPE = get_meta_tag_t<get_meta_info_t<type>>;
static_assert(!std::is_void<TAG_TYPE>());
TAG_TYPE tag;
this->header().set_tag(tag.get());
}
}
return *ie;
}

Expand Down
81 changes: 81 additions & 0 deletions ut/choice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ struct UNKNOWN : med::sequence<
struct U8 : med::value<uint8_t>{};
struct U16 : med::value<uint16_t>{};
struct U32 : med::value<uint32_t>{};
struct string : med::ascii_string<> {};

//choice based on plain value selector
struct plain : med::choice<
Expand All @@ -124,6 +125,31 @@ struct plain : med::choice<

using PLAIN = M<L, plain>;

struct hdr : med::sequence<
M<U8>,
O<U16>
>
{
bool is_tag_set() const { return get<U8>().is_set(); }
auto get_tag() const { return get<U8>().get(); }
void set_tag(uint8_t v) { return ref<U8>().set(v); }
};

//choice based on a compound header selector
struct compound : med::choice< hdr,
M< C<0x00>, U8 >,
M< C<0x02>, U16 >,
M< C<0x04>, string >
>
{};

struct SEQ : med::sequence<
O< U32 >
, M< U16 >
, M< compound >
>
{};

} //end: namespace cho

using namespace std::string_view_literals;
Expand Down Expand Up @@ -214,4 +240,59 @@ TEST(choice, nibble_tag)
EXPECT_FALSE(pf->is_set());
}
#endif
TEST(choice, tag_in_compound)
{
uint8_t buffer[128];
med::encoder_context ctx{ buffer };

cho::compound msg;
msg.ref<string>().set("12345678"sv);
ASSERT_TRUE(msg.header().is_tag_set());

msg.header().clear();
ASSERT_FALSE(msg.header().is_tag_set());

msg.ref<string>();
ASSERT_TRUE(msg.header().is_tag_set());

msg.header().clear();
msg.ref<string>().set("12345678"sv);
ASSERT_TRUE(msg.header().is_tag_set());

msg.header().ref<U16>().set(0xff);

encode(med::octet_encoder{ctx}, msg);
EXPECT_STREQ(
"04 00 FF 31 32 33 34 35 36 37 38 ",
as_string(ctx.buffer())
);

msg.clear();
ASSERT_FALSE(msg.header().is_tag_set());

med::decoder_context dctx;
dctx.reset(ctx.buffer().get_start(), ctx.buffer().get_offset());
decode(med::octet_decoder{dctx}, msg);

auto* pf = msg.get<string>();
ASSERT_NE(nullptr, pf);
ASSERT_TRUE(msg.header().is_tag_set());
}

TEST(choice, m_choice_in_seq)
{
uint8_t buffer[128];
med::encoder_context ctx{ buffer };

SEQ msg;

msg.ref<U16>().set(1);
msg.ref<compound>().ref<string>().set("12345678"sv);

encode(med::octet_encoder{ctx}, msg);
EXPECT_STREQ(
"00 01 04 31 32 33 34 35 36 37 38 ",
as_string(ctx.buffer())
);
}
//NOTE: choice compound is tested in length.cpp ppp::proto
1 change: 1 addition & 0 deletions ut/copy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct hdr : med::sequence<
M<word>
>
{
bool is_tag_set() const { return get<byte>().is_set(); }
auto get_tag() const { return get<byte>().get(); }
void set_tag(uint8_t v) { return ref<byte>().set(v); }
};
Expand Down
1 change: 1 addition & 0 deletions ut/diameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct header : med::sequence<
M<end_to_end_id>
>
{
bool is_tag_set() const { return get<cmd_code>().is_set(); }
std::size_t get_tag() const { return get<cmd_code>().get() + (flags().request() ? REQUEST : 0); }
void set_tag(std::size_t tag) { ref<cmd_code>().set(tag & 0xFFFFFF); flags().request(tag & REQUEST); }

Expand Down
1 change: 1 addition & 0 deletions ut/length.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ struct hdr : med::sequence<
M<id>
>
{
bool is_tag_set() const { return get<code>().is_set(); }
auto get_tag() const { return get<code>().get(); }
void set_tag(uint8_t v) { return ref<code>().set(v); }

Expand Down