1 /// 2 module sbin.serialize; 3 4 import std.array : appender; 5 6 import sbin.type; 7 import sbin.vluint; 8 import sbin.zigzag; 9 import sbin.repr; 10 11 /++ Serialize to output ubyte range 12 13 Params: 14 val - serializible value 15 r - output range 16 +/ 17 void sbinSerialize(RH=EmptyReprHandler, R, string file=__FILE__, size_t line=__LINE__, Ts...) 18 (auto ref R r, auto ref const Ts vals) if (isOutputRange!(R, ubyte) && Ts.length && isReprHandler!RH) 19 { 20 void impl(T)(auto ref R r, auto ref const T val) 21 { 22 static if (hasRepr!(RH, T)) 23 { 24 impl(r, RH.repr(val)); 25 } 26 else static if (is(T == enum)) 27 { 28 put(r, getEnumNum(val).pack[]); 29 } 30 else static if (is(T == vluint)) 31 { 32 dumpVLUInt(r, val.value); 33 } 34 else static if (is(T == vlint)) 35 { 36 dumpVLUInt(r, zzEncode(val.value)); 37 } 38 else static if (is(T : double) || is(T : long)) 39 { 40 put(r, val.pack[]); 41 } 42 else static if (isVoidArray!T) 43 { 44 static if (isDynamicArray!T) 45 dumpVLUInt(r, val.length); 46 put(r, (() @trusted => cast(ubyte[])val[])()); 47 } 48 else static if (isStaticArray!T) 49 { 50 foreach (ref v; val) 51 impl(r, v); 52 } 53 else static if (isSomeString!T) 54 { 55 dumpVLUInt(r, val.length); 56 put(r, (() @trusted => cast(ubyte[])val)()); 57 } 58 else static if (isDynamicArray!T) 59 { 60 dumpVLUInt(r, val.length); 61 foreach (ref v; val) 62 impl(r, v); 63 } 64 else static if (isAssociativeArray!T) 65 { 66 dumpVLUInt(r, val.length); 67 foreach (k, ref v; val) 68 { 69 impl(r, k); 70 impl(r, v); 71 } 72 } 73 else static if (isTagged!(T).any) 74 { 75 impl(r, getTaggedTag(val)); 76 val.taggedMatch!( 77 (v) { 78 static if (!is(Unqual!(typeof(v)) == typeof(null))) 79 impl(r, v); 80 } 81 ); 82 } 83 else static if (hasCustomRepr!(T, RH)) 84 { 85 // for @safe sbinSerialize sbinCustomRepr must be @trusted or @safe 86 impl(r, val.sbinCustomRepr()); 87 } 88 else static if (is(T == struct)) 89 { 90 version (allowRawUnions) 91 { 92 import std : Nullable; 93 static if (is(T == Nullable!A, A)) 94 pragma(msg, file, "(", cast(int)line, "): ", "\033[33mWarning:\033[0m ", 95 T, " serialize as union, use NullableAsSumTypeRH for proper serialize!"); 96 } 97 98 import std.traits : hasUDA; 99 foreach (i, ref v; val.tupleof) 100 static if (!hasUDA!(T.tupleof[i], sbinSkip)) 101 impl(r, v); 102 } 103 else static if (is(T == union)) 104 { 105 version (allowRawUnions) 106 impl(r, (() @trusted => cast(void[T.sizeof])((cast(void*)&val)[0..T.sizeof]))()); 107 else 108 static assert(0, "raw unions are not allowed, for allow build "~ 109 "with configuration 'allow-raw-unions'"); 110 } 111 else static assert(0, "unsupported type: " ~ T.stringof); 112 } 113 114 static if (vals.length == 1) impl(r, vals[0]); 115 else foreach (ref v; vals) impl(r, v); 116 } 117 118 /++ Serialize to ubyte[] 119 120 using `appender!(ubyte[])` as output range 121 122 Params: 123 val = serializible value 124 125 Returns: 126 serialized data 127 +/ 128 ubyte[] sbinSerialize(RH=EmptyReprHandler, T, string file=__FILE__, size_t line=__LINE__) 129 (auto ref const T val) if (isReprHandler!RH) 130 { 131 auto buf = appender!(ubyte[]); 132 sbinSerialize!(RH, typeof(buf), file, line)(buf, val); 133 return buf.data; 134 }