Skip to content

fix impossibility of a compound choice inside a set/sequence #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
@@ -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>());
@@ -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;
@@ -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;
}

81 changes: 81 additions & 0 deletions ut/choice.cpp
Original file line number Diff line number Diff line change
@@ -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<
@@ -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;
@@ -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
@@ -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); }
};
1 change: 1 addition & 0 deletions ut/diameter.cpp
Original file line number Diff line number Diff line change
@@ -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); }

1 change: 1 addition & 0 deletions ut/length.cpp
Original file line number Diff line number Diff line change
@@ -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); }