Skip to content

Commit

Permalink
Fix #179 - invalid defaulting of union in record (#182)
Browse files Browse the repository at this point in the history
  • Loading branch information
naegelejd authored Oct 3, 2024
1 parent 3dac31e commit 3e9a724
Show file tree
Hide file tree
Showing 21 changed files with 385 additions and 37 deletions.
34 changes: 32 additions & 2 deletions cpp/test/generated/binary/protocols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ struct IsTriviallySerializable<tuples::Tuple<T1, T2>> {
offsetof(__T__, v1) < offsetof(__T__, v2);
};

template <>
struct IsTriviallySerializable<basic_types::RecordWithString> {
using __T__ = basic_types::RecordWithString;
static constexpr bool value =
std::is_standard_layout_v<__T__> &&
IsTriviallySerializable<decltype(__T__::i)>::value &&
(sizeof(__T__) == (sizeof(__T__::i)));
};

template <>
struct IsTriviallySerializable<basic_types::RecordWithUnions> {
using __T__ = basic_types::RecordWithUnions;
Expand All @@ -33,8 +42,9 @@ struct IsTriviallySerializable<basic_types::RecordWithUnions> {
IsTriviallySerializable<decltype(__T__::null_or_int_or_string)>::value &&
IsTriviallySerializable<decltype(__T__::date_or_datetime)>::value &&
IsTriviallySerializable<decltype(__T__::null_or_fruits_or_days_of_week)>::value &&
(sizeof(__T__) == (sizeof(__T__::null_or_int_or_string) + sizeof(__T__::date_or_datetime) + sizeof(__T__::null_or_fruits_or_days_of_week))) &&
offsetof(__T__, null_or_int_or_string) < offsetof(__T__, date_or_datetime) && offsetof(__T__, date_or_datetime) < offsetof(__T__, null_or_fruits_or_days_of_week);
IsTriviallySerializable<decltype(__T__::record_or_int)>::value &&
(sizeof(__T__) == (sizeof(__T__::null_or_int_or_string) + sizeof(__T__::date_or_datetime) + sizeof(__T__::null_or_fruits_or_days_of_week) + sizeof(__T__::record_or_int))) &&
offsetof(__T__, null_or_int_or_string) < offsetof(__T__, date_or_datetime) && offsetof(__T__, date_or_datetime) < offsetof(__T__, null_or_fruits_or_days_of_week) && offsetof(__T__, null_or_fruits_or_days_of_week) < offsetof(__T__, record_or_int);
};

template <typename T0, typename T1>
Expand Down Expand Up @@ -908,6 +918,24 @@ template<typename T, yardl::binary::Reader<T> ReadT>
yardl::binary::ReadVector<T, ReadT>(stream, value);
}

[[maybe_unused]] void WriteRecordWithString(yardl::binary::CodedOutputStream& stream, basic_types::RecordWithString const& value) {
if constexpr (yardl::binary::IsTriviallySerializable<basic_types::RecordWithString>::value) {
yardl::binary::WriteTriviallySerializable(stream, value);
return;
}

yardl::binary::WriteString(stream, value.i);
}

[[maybe_unused]] void ReadRecordWithString(yardl::binary::CodedInputStream& stream, basic_types::RecordWithString& value) {
if constexpr (yardl::binary::IsTriviallySerializable<basic_types::RecordWithString>::value) {
yardl::binary::ReadTriviallySerializable(stream, value);
return;
}

yardl::binary::ReadString(stream, value.i);
}

[[maybe_unused]] void WriteRecordWithUnions(yardl::binary::CodedOutputStream& stream, basic_types::RecordWithUnions const& value) {
if constexpr (yardl::binary::IsTriviallySerializable<basic_types::RecordWithUnions>::value) {
yardl::binary::WriteTriviallySerializable(stream, value);
Expand All @@ -917,6 +945,7 @@ template<typename T, yardl::binary::Reader<T> ReadT>
WriteUnion<std::monostate, yardl::binary::WriteMonostate, int32_t, yardl::binary::WriteInteger, std::string, yardl::binary::WriteString>(stream, value.null_or_int_or_string);
WriteUnion<yardl::Time, yardl::binary::WriteTime, yardl::DateTime, yardl::binary::WriteDateTime>(stream, value.date_or_datetime);
basic_types::binary::WriteGenericNullableUnion2<basic_types::Fruits, yardl::binary::WriteEnum<basic_types::Fruits>, basic_types::DaysOfWeek, yardl::binary::WriteFlags<basic_types::DaysOfWeek>>(stream, value.null_or_fruits_or_days_of_week);
WriteUnion<basic_types::RecordWithString, basic_types::binary::WriteRecordWithString, int32_t, yardl::binary::WriteInteger>(stream, value.record_or_int);
}

[[maybe_unused]] void ReadRecordWithUnions(yardl::binary::CodedInputStream& stream, basic_types::RecordWithUnions& value) {
Expand All @@ -928,6 +957,7 @@ template<typename T, yardl::binary::Reader<T> ReadT>
ReadUnion<std::monostate, yardl::binary::ReadMonostate, int32_t, yardl::binary::ReadInteger, std::string, yardl::binary::ReadString>(stream, value.null_or_int_or_string);
ReadUnion<yardl::Time, yardl::binary::ReadTime, yardl::DateTime, yardl::binary::ReadDateTime>(stream, value.date_or_datetime);
basic_types::binary::ReadGenericNullableUnion2<basic_types::Fruits, yardl::binary::ReadEnum<basic_types::Fruits>, basic_types::DaysOfWeek, yardl::binary::ReadFlags<basic_types::DaysOfWeek>>(stream, value.null_or_fruits_or_days_of_week);
ReadUnion<basic_types::RecordWithString, basic_types::binary::ReadRecordWithString, int32_t, yardl::binary::ReadInteger>(stream, value.record_or_int);
}

template<typename T0, yardl::binary::Writer<T0> WriteT0, typename T1, yardl::binary::Writer<T1> WriteT1>
Expand Down
26 changes: 25 additions & 1 deletion cpp/test/generated/hdf5/protocols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,23 +413,39 @@ namespace {
return t;
}

struct _Inner_RecordWithString {
_Inner_RecordWithString() {}
_Inner_RecordWithString(basic_types::RecordWithString const& o)
: i(o.i) {
}

void ToOuter (basic_types::RecordWithString& o) const {
yardl::hdf5::ToOuter(i, o.i);
}

yardl::hdf5::InnerVlenString i;
};

struct _Inner_RecordWithUnions {
_Inner_RecordWithUnions() {}
_Inner_RecordWithUnions(basic_types::RecordWithUnions const& o)
: null_or_int_or_string(o.null_or_int_or_string),
date_or_datetime(o.date_or_datetime),
null_or_fruits_or_days_of_week(o.null_or_fruits_or_days_of_week) {
null_or_fruits_or_days_of_week(o.null_or_fruits_or_days_of_week),
record_or_int(o.record_or_int) {
}

void ToOuter (basic_types::RecordWithUnions& o) const {
yardl::hdf5::ToOuter(null_or_int_or_string, o.null_or_int_or_string);
yardl::hdf5::ToOuter(date_or_datetime, o.date_or_datetime);
yardl::hdf5::ToOuter(null_or_fruits_or_days_of_week, o.null_or_fruits_or_days_of_week);
yardl::hdf5::ToOuter(record_or_int, o.record_or_int);
}

::InnerUnion2<int32_t, int32_t, yardl::hdf5::InnerVlenString, std::string> null_or_int_or_string;
::InnerUnion2<yardl::Time, yardl::Time, yardl::DateTime, yardl::DateTime> date_or_datetime;
::InnerUnion2<basic_types::Fruits, basic_types::Fruits, basic_types::DaysOfWeek, basic_types::DaysOfWeek> null_or_fruits_or_days_of_week;
::InnerUnion2<basic_types::hdf5::_Inner_RecordWithString, basic_types::RecordWithString, int32_t, int32_t> record_or_int;
};

template <typename _T0_Inner, typename T0, typename _T1_Inner, typename T1>
Expand All @@ -446,12 +462,20 @@ struct _Inner_GenericRecordWithComputedFields {
::InnerUnion2<_T0_Inner, T0, _T1_Inner, T1> f1;
};

[[maybe_unused]] H5::CompType GetRecordWithStringHdf5Ddl() {
using RecordType = basic_types::hdf5::_Inner_RecordWithString;
H5::CompType t(sizeof(RecordType));
t.insertMember("i", HOFFSET(RecordType, i), yardl::hdf5::InnerVlenStringDdl());
return t;
}

[[maybe_unused]] H5::CompType GetRecordWithUnionsHdf5Ddl() {
using RecordType = basic_types::hdf5::_Inner_RecordWithUnions;
H5::CompType t(sizeof(RecordType));
t.insertMember("nullOrIntOrString", HOFFSET(RecordType, null_or_int_or_string), ::InnerUnion2Ddl<int32_t, int32_t, yardl::hdf5::InnerVlenString, std::string>(true, H5::PredType::NATIVE_INT32, "int32", yardl::hdf5::InnerVlenStringDdl(), "string"));
t.insertMember("dateOrDatetime", HOFFSET(RecordType, date_or_datetime), ::InnerUnion2Ddl<yardl::Time, yardl::Time, yardl::DateTime, yardl::DateTime>(false, yardl::hdf5::TimeTypeDdl(), "time", yardl::hdf5::DateTimeTypeDdl(), "datetime"));
t.insertMember("nullOrFruitsOrDaysOfWeek", HOFFSET(RecordType, null_or_fruits_or_days_of_week), ::InnerUnion2Ddl<basic_types::Fruits, basic_types::Fruits, basic_types::DaysOfWeek, basic_types::DaysOfWeek>(true, basic_types::hdf5::GetFruitsHdf5Ddl(), "T1", H5::PredType::NATIVE_INT32, "T2"));
t.insertMember("recordOrInt", HOFFSET(RecordType, record_or_int), ::InnerUnion2Ddl<basic_types::hdf5::_Inner_RecordWithString, basic_types::RecordWithString, int32_t, int32_t>(false, basic_types::hdf5::GetRecordWithStringHdf5Ddl(), "RecordWithString", H5::PredType::NATIVE_INT32, "int32"));
return t;
}

Expand Down
24 changes: 24 additions & 0 deletions cpp/test/generated/model.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,17 @@
}
}
},
{
"record": {
"name": "RecordWithString",
"fields": [
{
"name": "i",
"type": "string"
}
]
}
},
{
"record": {
"name": "RecordWithUnions",
Expand Down Expand Up @@ -232,6 +243,19 @@
"BasicTypes.DaysOfWeek"
]
}
},
{
"name": "recordOrInt",
"type": [
{
"tag": "RecordWithString",
"type": "BasicTypes.RecordWithString"
},
{
"tag": "int32",
"type": "int32"
}
]
}
]
}
Expand Down
41 changes: 41 additions & 0 deletions cpp/test/generated/ndjson/protocols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ void from_json(ordered_json const& j, basic_types::DaysOfWeek& value);
void to_json(ordered_json& j, basic_types::TextFormat const& value);
void from_json(ordered_json const& j, basic_types::TextFormat& value);

void to_json(ordered_json& j, basic_types::RecordWithString const& value);
void from_json(ordered_json const& j, basic_types::RecordWithString& value);

void to_json(ordered_json& j, basic_types::RecordWithUnions const& value);
void from_json(ordered_json const& j, basic_types::RecordWithUnions& value);

Expand Down Expand Up @@ -353,6 +356,25 @@ struct adl_serializer<std::variant<std::monostate, basic_types::Fruits, basic_ty
}
};

template <>
struct adl_serializer<std::variant<basic_types::RecordWithString, int32_t>> {
static void to_json(ordered_json& j, std::variant<basic_types::RecordWithString, int32_t> const& value) {
std::visit([&j](auto const& v) {j = v;}, value);
}

static void from_json(ordered_json const& j, std::variant<basic_types::RecordWithString, int32_t>& value) {
if ((j.is_object())) {
value = j.get<basic_types::RecordWithString>();
return;
}
if ((j.is_number())) {
value = j.get<int32_t>();
return;
}
throw std::runtime_error("Invalid union value");
}
};

template <>
struct adl_serializer<std::variant<std::unordered_map<std::string, int32_t>, int32_t>> {
static void to_json(ordered_json& j, std::variant<std::unordered_map<std::string, int32_t>, int32_t> const& value) {
Expand Down Expand Up @@ -1125,6 +1147,19 @@ void from_json(ordered_json const& j, basic_types::TextFormat& value) {
}
}

void to_json(ordered_json& j, basic_types::RecordWithString const& value) {
j = ordered_json::object();
if (yardl::ndjson::ShouldSerializeFieldValue(value.i)) {
j.push_back({"i", value.i});
}
}

void from_json(ordered_json const& j, basic_types::RecordWithString& value) {
if (auto it = j.find("i"); it != j.end()) {
it->get_to(value.i);
}
}

void to_json(ordered_json& j, basic_types::RecordWithUnions const& value) {
j = ordered_json::object();
if (yardl::ndjson::ShouldSerializeFieldValue(value.null_or_int_or_string)) {
Expand All @@ -1136,6 +1171,9 @@ void to_json(ordered_json& j, basic_types::RecordWithUnions const& value) {
if (yardl::ndjson::ShouldSerializeFieldValue(value.null_or_fruits_or_days_of_week)) {
j.push_back({"nullOrFruitsOrDaysOfWeek", value.null_or_fruits_or_days_of_week});
}
if (yardl::ndjson::ShouldSerializeFieldValue(value.record_or_int)) {
j.push_back({"recordOrInt", value.record_or_int});
}
}

void from_json(ordered_json const& j, basic_types::RecordWithUnions& value) {
Expand All @@ -1148,6 +1186,9 @@ void from_json(ordered_json const& j, basic_types::RecordWithUnions& value) {
if (auto it = j.find("nullOrFruitsOrDaysOfWeek"); it != j.end()) {
it->get_to(value.null_or_fruits_or_days_of_week);
}
if (auto it = j.find("recordOrInt"); it != j.end()) {
it->get_to(value.record_or_int);
}
}

template <typename T0, typename T1>
Expand Down
2 changes: 1 addition & 1 deletion cpp/test/generated/protocols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4221,7 +4221,7 @@ void UnionsReaderBaseInvalidState(uint8_t attempted, uint8_t current) {

} // namespace

std::string UnionsWriterBase::schema_ = R"({"protocol":{"name":"Unions","sequence":[{"name":"intOrSimpleRecord","type":[{"tag":"int32","type":"int32"},{"tag":"SimpleRecord","type":"TestModel.SimpleRecord"}]},{"name":"intOrRecordWithVlens","type":[{"tag":"int32","type":"int32"},{"tag":"RecordWithVlens","type":"TestModel.RecordWithVlens"}]},{"name":"monosotateOrIntOrSimpleRecord","type":[null,{"tag":"int32","type":"int32"},{"tag":"SimpleRecord","type":"TestModel.SimpleRecord"}]},{"name":"recordWithUnions","type":"BasicTypes.RecordWithUnions"}]},"types":[{"name":"DaysOfWeek","values":[{"symbol":"monday","value":1},{"symbol":"tuesday","value":2},{"symbol":"wednesday","value":4},{"symbol":"thursday","value":8},{"symbol":"friday","value":16},{"symbol":"saturday","value":32},{"symbol":"sunday","value":64}]},{"name":"Fruits","values":[{"symbol":"apple","value":1},{"symbol":"banana","value":2},{"symbol":"pear","value":3}]},{"name":"GenericNullableUnion2","typeParameters":["T1","T2"],"type":[null,{"tag":"T1","type":"T1"},{"tag":"T2","type":"T2"}]},{"name":"RecordWithUnions","fields":[{"name":"nullOrIntOrString","type":[null,{"tag":"int32","type":"int32"},{"tag":"string","type":"string"}]},{"name":"dateOrDatetime","type":[{"tag":"time","type":"time"},{"tag":"datetime","type":"datetime"}]},{"name":"nullOrFruitsOrDaysOfWeek","type":{"name":"BasicTypes.GenericNullableUnion2","typeArguments":["BasicTypes.Fruits","BasicTypes.DaysOfWeek"]}}]},{"name":"RecordWithVlens","fields":[{"name":"a","type":{"vector":{"items":"TestModel.SimpleRecord"}}},{"name":"b","type":"int32"},{"name":"c","type":"int32"}]},{"name":"SimpleRecord","fields":[{"name":"x","type":"int32"},{"name":"y","type":"int32"},{"name":"z","type":"int32"}]}]})";
std::string UnionsWriterBase::schema_ = R"({"protocol":{"name":"Unions","sequence":[{"name":"intOrSimpleRecord","type":[{"tag":"int32","type":"int32"},{"tag":"SimpleRecord","type":"TestModel.SimpleRecord"}]},{"name":"intOrRecordWithVlens","type":[{"tag":"int32","type":"int32"},{"tag":"RecordWithVlens","type":"TestModel.RecordWithVlens"}]},{"name":"monosotateOrIntOrSimpleRecord","type":[null,{"tag":"int32","type":"int32"},{"tag":"SimpleRecord","type":"TestModel.SimpleRecord"}]},{"name":"recordWithUnions","type":"BasicTypes.RecordWithUnions"}]},"types":[{"name":"DaysOfWeek","values":[{"symbol":"monday","value":1},{"symbol":"tuesday","value":2},{"symbol":"wednesday","value":4},{"symbol":"thursday","value":8},{"symbol":"friday","value":16},{"symbol":"saturday","value":32},{"symbol":"sunday","value":64}]},{"name":"Fruits","values":[{"symbol":"apple","value":1},{"symbol":"banana","value":2},{"symbol":"pear","value":3}]},{"name":"GenericNullableUnion2","typeParameters":["T1","T2"],"type":[null,{"tag":"T1","type":"T1"},{"tag":"T2","type":"T2"}]},{"name":"RecordWithString","fields":[{"name":"i","type":"string"}]},{"name":"RecordWithUnions","fields":[{"name":"nullOrIntOrString","type":[null,{"tag":"int32","type":"int32"},{"tag":"string","type":"string"}]},{"name":"dateOrDatetime","type":[{"tag":"time","type":"time"},{"tag":"datetime","type":"datetime"}]},{"name":"nullOrFruitsOrDaysOfWeek","type":{"name":"BasicTypes.GenericNullableUnion2","typeArguments":["BasicTypes.Fruits","BasicTypes.DaysOfWeek"]}},{"name":"recordOrInt","type":[{"tag":"RecordWithString","type":"BasicTypes.RecordWithString"},{"tag":"int32","type":"int32"}]}]},{"name":"RecordWithVlens","fields":[{"name":"a","type":{"vector":{"items":"TestModel.SimpleRecord"}}},{"name":"b","type":"int32"},{"name":"c","type":"int32"}]},{"name":"SimpleRecord","fields":[{"name":"x","type":"int32"},{"name":"y","type":"int32"},{"name":"z","type":"int32"}]}]})";

std::vector<std::string> UnionsWriterBase::previous_schemas_ = {
};
Expand Down
16 changes: 15 additions & 1 deletion cpp/test/generated/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,29 @@ using GenericNullableUnion2 = std::variant<std::monostate, T1, T2>;
template <typename T>
using GenericVector = std::vector<T>;

struct RecordWithString {
std::string i{};

bool operator==(const RecordWithString& other) const {
return i == other.i;
}

bool operator!=(const RecordWithString& other) const {
return !(*this == other);
}
};

struct RecordWithUnions {
std::variant<std::monostate, int32_t, std::string> null_or_int_or_string{};
std::variant<yardl::Time, yardl::DateTime> date_or_datetime{};
basic_types::GenericNullableUnion2<basic_types::Fruits, basic_types::DaysOfWeek> null_or_fruits_or_days_of_week{};
std::variant<basic_types::RecordWithString, int32_t> record_or_int{};

bool operator==(const RecordWithUnions& other) const {
return null_or_int_or_string == other.null_or_int_or_string &&
date_or_datetime == other.date_or_datetime &&
null_or_fruits_or_days_of_week == other.null_or_fruits_or_days_of_week;
null_or_fruits_or_days_of_week == other.null_or_fruits_or_days_of_week &&
record_or_int == other.record_or_int;
}

bool operator!=(const RecordWithUnions& other) const {
Expand Down
24 changes: 24 additions & 0 deletions matlab/generated/+basic_types/+binary/RecordWithStringSerializer.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
% This file was generated by the "yardl" tool. DO NOT EDIT.

classdef RecordWithStringSerializer < yardl.binary.RecordSerializer
methods
function self = RecordWithStringSerializer()
field_serializers{1} = yardl.binary.StringSerializer;
[email protected]('basic_types.RecordWithString', field_serializers);
end

function write(self, outstream, value)
arguments
self
outstream (1,1) yardl.binary.CodedOutputStream
value (1,1) basic_types.RecordWithString
end
self.write_(outstream, value.i);
end

function value = read(self, instream)
fields = self.read_(instream);
value = basic_types.RecordWithString(i=fields{1});
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
field_serializers{1} = yardl.binary.UnionSerializer('basic_types.Int32OrString', {yardl.binary.NoneSerializer, yardl.binary.Int32Serializer, yardl.binary.StringSerializer}, {yardl.None, @basic_types.Int32OrString.Int32, @basic_types.Int32OrString.String});
field_serializers{2} = yardl.binary.UnionSerializer('basic_types.TimeOrDatetime', {yardl.binary.TimeSerializer, yardl.binary.DatetimeSerializer}, {@basic_types.TimeOrDatetime.Time, @basic_types.TimeOrDatetime.Datetime});
field_serializers{3} = yardl.binary.UnionSerializer('basic_types.GenericNullableUnion2', {yardl.binary.NoneSerializer, yardl.binary.EnumSerializer('basic_types.Fruits', @basic_types.Fruits, yardl.binary.Int32Serializer), yardl.binary.EnumSerializer('basic_types.DaysOfWeek', @basic_types.DaysOfWeek, yardl.binary.Int32Serializer)}, {yardl.None, @basic_types.GenericNullableUnion2.T1, @basic_types.GenericNullableUnion2.T2});
field_serializers{4} = yardl.binary.UnionSerializer('basic_types.RecordWithStringOrInt32', {basic_types.binary.RecordWithStringSerializer(), yardl.binary.Int32Serializer}, {@basic_types.RecordWithStringOrInt32.RecordWithString, @basic_types.RecordWithStringOrInt32.Int32});
[email protected]('basic_types.RecordWithUnions', field_serializers);
end

Expand All @@ -15,12 +16,12 @@ function write(self, outstream, value)
outstream (1,1) yardl.binary.CodedOutputStream
value (1,1) basic_types.RecordWithUnions
end
self.write_(outstream, value.null_or_int_or_string, value.date_or_datetime, value.null_or_fruits_or_days_of_week);
self.write_(outstream, value.null_or_int_or_string, value.date_or_datetime, value.null_or_fruits_or_days_of_week, value.record_or_int);
end

function value = read(self, instream)
fields = self.read_(instream);
value = basic_types.RecordWithUnions(null_or_int_or_string=fields{1}, date_or_datetime=fields{2}, null_or_fruits_or_days_of_week=fields{3});
value = basic_types.RecordWithUnions(null_or_int_or_string=fields{1}, date_or_datetime=fields{2}, null_or_fruits_or_days_of_week=fields{3}, record_or_int=fields{4});
end
end
end
Loading

0 comments on commit 3e9a724

Please sign in to comment.