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, Ts...)(auto ref R r, auto ref const Ts vals) 18 if (isOutputRange!(R, ubyte) && Ts.length && isReprHandler!RH) 19 { 20 static if (Ts.length == 1) 21 { 22 alias T = Unqual!(Ts[0]); 23 alias val = vals[0]; 24 25 static if (hasRepr!(RH, T)) 26 { 27 sbinSerialize!RH(r, RH.repr(val)); 28 } 29 else static if (is(T == enum)) 30 { 31 put(r, getEnumNum(val).pack[]); 32 } 33 else static if (is(T == vluint)) 34 { 35 dumpVLUInt(r, val.value); 36 } 37 else static if (is(T == vlint)) 38 { 39 dumpVLUInt(r, zzEncode(val.value)); 40 } 41 else static if (is(T : double) || is(T : long)) 42 { 43 put(r, val.pack[]); 44 } 45 else static if (isVoidArray!T) 46 { 47 static if (isDynamicArray!T) 48 dumpVLUInt(r, val.length); 49 put(r, (() @trusted => cast(ubyte[])val[])()); 50 } 51 else static if (isStaticArray!T) 52 { 53 foreach (ref v; val) 54 sbinSerialize!RH(r, v); 55 } 56 else static if (isSomeString!T) 57 { 58 dumpVLUInt(r, val.length); 59 put(r, (() @trusted => cast(ubyte[])val)()); 60 } 61 else static if (isDynamicArray!T) 62 { 63 dumpVLUInt(r, val.length); 64 foreach (ref v; val) 65 sbinSerialize!RH(r, v); 66 } 67 else static if (isAssociativeArray!T) 68 { 69 dumpVLUInt(r, val.length); 70 foreach (k, ref v; val) 71 { 72 sbinSerialize!RH(r, k); 73 sbinSerialize!RH(r, v); 74 } 75 } 76 else static if (isTagged!(T).any) 77 { 78 sbinSerialize!RH(r, getTaggedTag(val)); 79 val.taggedMatch!( 80 (v) { 81 static if (!is(Unqual!(typeof(v)) == typeof(null))) 82 sbinSerialize!RH(r, v); 83 } 84 ); 85 } 86 else static if (hasCustomRepr!(T, RH)) 87 { 88 // for @safe sbinSerialize sbinCustomRepr must be @trusted or @safe 89 sbinSerialize!RH(r, val.sbinCustomRepr()); 90 } 91 else static if (is(T == struct)) 92 { 93 import std.traits : hasUDA; 94 foreach (i, ref v; val.tupleof) 95 static if (!hasUDA!(T.tupleof[i], sbinSkip)) 96 sbinSerialize!RH(r, v); 97 } 98 else static if (is(T == union)) 99 { 100 sbinSerialize!RH(r, (() @trusted => cast(void[T.sizeof])((cast(void*)&val)[0..T.sizeof]))()); 101 } 102 else static assert(0, "unsupported type: " ~ T.stringof); 103 } 104 else foreach (ref v; vals) sbinSerialize!RH(r, v); 105 } 106 107 /++ Serialize to ubyte[] 108 109 using `appender!(ubyte[])` as output range 110 111 Params: 112 val = serializible value 113 114 Returns: 115 serialized data 116 +/ 117 ubyte[] sbinSerialize(RH=EmptyReprHandler, T)(auto ref const T val) if (isReprHandler!RH) 118 { 119 auto buf = appender!(ubyte[]); 120 sbinSerialize!RH(buf, val); 121 return buf.data; 122 }