diff --git a/utils/math/mixed_radix.d b/utils/math/mixed_radix.d index 1dd04452..380be44a 100644 --- a/utils/math/mixed_radix.d +++ b/utils/math/mixed_radix.d @@ -158,6 +158,108 @@ unittest } } } + +template SerializationCoder(alias Coder, S) +{ + private alias I = typeof(Coder.Decoder.init.get(0)); + private alias E = typeof(Coder.RetroEncoder.init.finish()); + + private struct Serializer + { + Coder.RetroEncoder encoder; + + void put(T)(auto ref const T value) + { + static if (is(T : I) && is(typeof(T.max) : I)) + { + I max = T.max; + I card = max; card++; + assert(card > max, "Overflow"); + encoder.put(value, card); + } + else + static if (is(T == struct)) + foreach_reverse (const ref field; value.tupleof) + put(field); + else + static if (is(T == Q[N], Q, size_t N)) + foreach_reverse (ref item; value) + put(item); + else + static assert(false, "Don't know how to serialize " ~ T.stringof); + } + } + + E serialize()(auto ref const S s) + { + Serializer serializer; + serializer.put(s); + return serializer.encoder.finish(); + } + + private struct Deserializer + { + Coder.Decoder decoder; + + void get(T)(ref T value) + { + static if (is(T : I) && is(typeof(T.max) : I)) + { + I max = T.max; + I card = max; card++; + assert(card > max, "Overflow"); + value = cast(T)decoder.get(card); + } + else + static if (is(T == struct)) + foreach (ref field; value.tupleof) + get(field); + else + static if (is(T == Q[N], Q, size_t N)) + foreach (ref item; value) + get(item); + else + static assert(false, "Don't know how to deserialize " ~ T.stringof); + } + } + + S deserialize(E encoded) + { + Deserializer deserializer; + deserializer.decoder = Coder.Decoder(encoded); + S result; + deserializer.get(result); + static if (__traits(hasMember, deserializer.decoder, "empty")) + assert(deserializer.decoder.empty); + return result; + } +} + +unittest +{ + static struct WithMax(T, T max_) + { + T value; + alias value this; + enum T max = max_; + } + + enum E { a, b, c } + alias D6 = WithMax!(uint, 6); + + static struct S + { + ubyte a; + bool b; + E[3] e; + D6 d; + } + + alias Coder = SerializationCoder!(MixedRadixCoder!(uint, ulong, true), S); + auto s = S(1, true, [E.a, E.b, E.c], D6(4)); + assert(Coder.deserialize(Coder.serialize(s)) == s); +} + private struct MaybeDynamicArray(T, size_t size = -1) { static if (size == -1)