1 module sbin.repr; 2 3 import std.traits : Unqual; 4 import std.meta : allSatisfy; 5 6 import sbin.serialize; 7 import sbin.deserialize; 8 9 struct EmptyReprHandler { enum sbinReprHandler; } 10 11 template isReprHandler(RH) 12 { 13 enum isReprHandler = is(RH == struct) && __traits(hasMember, RH, "sbinReprHandler"); 14 } 15 16 unittest 17 { 18 static struct Foo { } 19 20 static assert(isReprHandler!EmptyReprHandler); 21 static assert(!isReprHandler!Foo); 22 } 23 24 template hasRepr(RH, T) if (isReprHandler!RH) 25 { 26 static if (hasSerializeRepr!(RH, T)) 27 enum hasRepr = hasDeserializeRepr!(RH, T, serializeRepr!(RH, T)); 28 else 29 enum hasRepr = false; 30 } 31 32 enum hasSerializeRepr(RH, T) = is(typeof(sbinSerialize!RH(RH.repr(T.init)))); 33 34 enum hasDeserializeRepr(RH, T, Repr) = 35 is( typeof( 36 RH.fromRepr(sbinDeserialize!(RH, Repr)((ubyte[]).init)) 37 ) == Unqual!T); 38 39 template serializeRepr(RH, T) if (hasSerializeRepr!(RH, T)) 40 { alias serializeRepr = typeof(RH.repr(T.init)); } 41 42 unittest 43 { 44 static class Foo {} 45 static struct Bar {} 46 static assert (!hasRepr!(EmptyReprHandler, int)); 47 static assert (!hasRepr!(EmptyReprHandler, Foo)); 48 static assert (!hasRepr!(EmptyReprHandler, Bar)); 49 } 50 51 unittest 52 { 53 import std.datetime : SysTime; 54 55 static struct CRH 56 { 57 enum sbinReprHandler; 58 59 static: 60 61 long repr()(auto ref const SysTime st) { return st.stdTime; } 62 SysTime fromRepr()(auto ref const long v) { return SysTime(v); } 63 } 64 65 static assert (isReprHandler!CRH); 66 static assert (!hasRepr!(EmptyReprHandler, SysTime)); 67 static assert (hasSerializeRepr!(CRH, SysTime)); 68 static assert (is(serializeRepr!(CRH, SysTime) == long)); 69 static assert (hasDeserializeRepr!(CRH, SysTime, long)); 70 static assert (hasRepr!(CRH, SysTime)); 71 } 72 73 struct CombineReprHandler(RHS...) 74 if (allSatisfy!(isReprHandler, RHS)) 75 { 76 enum sbinReprHandler; 77 78 static foreach (RH; RHS) 79 { 80 alias repr = RH.repr; 81 alias fromRepr = RH.fromRepr; 82 } 83 } 84 85 @safe unittest 86 { 87 import std : SysTime, Duration, dur; 88 89 static struct SysTimeAsLongRH 90 { 91 enum sbinReprHandler; 92 static: 93 struct R { long value; } 94 R repr(in SysTime v) { return R(v.stdTime); } 95 SysTime fromRepr(in R r) { return SysTime(r.value); } 96 } 97 98 static struct DurationAsLongRH 99 { 100 enum sbinReprHandler; 101 static: 102 struct R { long value; } 103 R repr(in Duration v) { return R(v.total!"hnsecs"); } 104 Duration fromRepr(in R r) { return dur!"hnsecs"(r.value); } 105 } 106 107 alias RH = CombineReprHandler!(SysTimeAsLongRH, DurationAsLongRH); 108 109 static assert (isReprHandler!RH); 110 111 static assert (hasSerializeRepr!(RH, SysTime)); 112 static assert (hasDeserializeRepr!(RH, SysTime, SysTimeAsLongRH.R)); 113 static assert (is(serializeRepr!(RH, SysTime) == SysTimeAsLongRH.R)); 114 static assert (hasRepr!(RH, SysTime)); 115 116 static assert (hasSerializeRepr!(RH, Duration)); 117 static assert (hasDeserializeRepr!(RH, Duration, DurationAsLongRH.R)); 118 static assert (is(serializeRepr!(RH, Duration) == DurationAsLongRH.R)); 119 static assert (hasRepr!(RH, Duration)); 120 }