1 module des.stdx.pdata; 2 3 import std.traits; 4 import std..string; 5 6 import des.ts; 7 8 /// isn't array and has no unshared aliasings 9 template isPureData(T) { enum isPureData = !hasUnsharedAliasing!T && !isArray!T; } 10 11 /// 12 unittest 13 { 14 static assert( isPureData!int ); 15 static assert( isPureData!float ); 16 static assert( isPureData!creal ); 17 18 static struct Vec { float x,y,z; } 19 static assert( isPureData!Vec ); 20 21 static struct Arr { int[3] data; } 22 static assert( isPureData!Arr ); 23 24 static struct Some { float f; Vec v; Arr a; } 25 static assert( isPureData!Some ); 26 27 static assert( !isPureData!string ); 28 29 static struct Bad { int[] data; } 30 static assert( !isPureData!Bad ); 31 } 32 33 /// if `T` is array returns `isPureType!(ForeachType!T)`, if `T` isn't array returns `isPureData!T` 34 template isPureType(T) 35 { 36 static if( isArray!T ) 37 enum isPureType = isPureType!(ForeachType!T); 38 else 39 enum isPureType = isPureData!T; 40 } 41 42 /// 43 unittest 44 { 45 static assert( isPureType!int ); 46 static assert( isPureType!(int[]) ); 47 static assert( isPureType!float ); 48 static assert( isPureType!(float[]) ); 49 50 static struct Vec { float x,y,z; } 51 static assert( isPureType!Vec ); 52 53 static struct Arr { int[3] data; } 54 static assert( isPureType!Arr ); 55 56 static struct Some { float f; Vec v; Arr a; } 57 static assert( isPureType!Some ); 58 59 static assert( isPureType!string ); 60 61 static assert( isPureType!(const(string)) ); 62 static assert( isPureType!(string[]) ); 63 64 static struct Bad { int[] data; } 65 static assert( !isPureType!Bad ); 66 } 67 68 /// is a `PData` 69 template isPData(T) { enum isPData = is( typeof( (( PData a ){})( T.init ) ) ); } 70 71 /// 72 struct PData 73 { 74 /// 75 immutable(void)[] data; 76 /// 77 alias data this; 78 79 pure: 80 81 /// 82 this( in Unqual!(typeof(this)) pd ) { data = pd.data; } 83 84 /// 85 this(T)( in T val ) if( isPureData!T ) { data = pureDump(val); } 86 /// 87 this(T)( in T[] val ) if( isPureType!T ) { data = pureDump(val); } 88 89 /// 90 auto opAssign(T)( in T val ) if( isPureData!T ) { data = pureDump(val); return val; } 91 /// 92 auto opAssign(T)( in T[] val ) if( isPureType!T ) { data = pureDump(val); return val; } 93 94 @property 95 { 96 /// 97 auto as(T)() const { return pureConv!T(data); } 98 /// 99 auto as(T)() shared const { return pureConv!T(data); } 100 /// 101 auto as(T)() immutable { return pureConv!T(data); } 102 } 103 } 104 105 unittest 106 { 107 static assert( isPData!PData ); 108 static assert( isPData!(const(PData)) ); 109 static assert( isPData!(immutable(PData)) ); 110 static assert( isPData!(shared(PData)) ); 111 static assert( isPData!(shared const(PData)) ); 112 static assert( isPureData!PData ); 113 static assert( isPureType!PData ); 114 } 115 116 unittest 117 { 118 creationTest( "hello" ); 119 creationTest( 12.5 ); 120 creationTest( 12 ); 121 creationTest( [1,2,3] ); 122 creationTest( [.1,.2,.3] ); 123 124 static struct Vec { float x,y,z; } 125 creationTest( Vec(1,2,3) ); 126 127 static struct Arr { int[3] data; } 128 creationTest( Arr([1,2,3]) ); 129 130 static struct Some 131 { float f=8; Vec v=Vec(3,4,5); Arr a=Arr([4,3,2]); } 132 creationTest( Some.init ); 133 } 134 135 unittest 136 { 137 static struct Msg { string data; } 138 auto msg = Msg("ok"); 139 140 auto a = shared PData( PData( msg ) ); 141 assertEq( a.as!Msg, msg ); 142 143 auto b = immutable PData( PData( [msg] ) ); 144 assertEq( b.as!(Msg[]), [msg] ); 145 } 146 147 unittest 148 { 149 static struct Bad { int[] data; } 150 static assert( !__traits(compiles, PData( Bad([1,2]) ) ) ); 151 static assert( !__traits(compiles, PData( [Bad([1,2])] ) ) ); 152 } 153 154 /// 155 unittest 156 { 157 auto a = PData( [.1,.2,.3] ); 158 assertEq( a.as!(double[]), [.1,.2,.3] ); 159 a = "hello"; 160 assertEq( a.as!string, "hello" ); 161 } 162 163 unittest // Known problems 164 { 165 static struct Msg { string data; } 166 // shared or immutable PData can't create from structs or arrays with strings 167 enum arr = ["a","b","c"]; 168 enum msg = Msg("abc"); 169 170 static assert( __traits(compiles, PData( arr ) ) ); 171 static assert( __traits(compiles, PData( msg ) ) ); 172 static assert( __traits(compiles, PData( [arr] ) ) ); 173 static assert( __traits(compiles, PData( [msg] ) ) ); 174 static assert( __traits(compiles, const PData( arr ) ) ); 175 static assert( __traits(compiles, const PData( msg ) ) ); 176 177 static assert( !__traits(compiles, shared PData( arr ) ) ); 178 static assert( !__traits(compiles, shared PData( msg ) ) ); 179 static assert( !__traits(compiles, shared PData( [arr] ) ) ); 180 static assert( !__traits(compiles, shared PData( [msg] ) ) ); 181 static assert( __traits(compiles, shared PData( PData( arr ) ) ) ); 182 static assert( __traits(compiles, shared PData( PData( msg ) ) ) ); 183 184 static assert( !__traits(compiles, shared const PData( arr ) ) ); 185 static assert( !__traits(compiles, shared const PData( msg ) ) ); 186 static assert( !__traits(compiles, shared const PData( [arr] ) ) ); 187 static assert( !__traits(compiles, shared const PData( [msg] ) ) ); 188 static assert( __traits(compiles, shared const PData( PData( arr ) ) ) ); 189 static assert( __traits(compiles, shared const PData( PData( msg ) ) ) ); 190 191 static assert( !__traits(compiles, immutable PData( arr ) ) ); 192 static assert( !__traits(compiles, immutable PData( msg ) ) ); 193 static assert( !__traits(compiles, immutable PData( [arr] ) ) ); 194 static assert( !__traits(compiles, immutable PData( [msg] ) ) ); 195 static assert( __traits(compiles, immutable PData( PData( arr ) ) ) ); 196 static assert( __traits(compiles, immutable PData( PData( msg ) ) ) ); 197 } 198 199 private version(unittest) 200 { 201 void asTest(A,B)( in A val, in B orig ) 202 { 203 if( isPData!B ) return; 204 205 assertEq( (PData(val)).as!B, orig ); 206 assertEq( (const PData(val)).as!B, orig ); 207 assertEq( (immutable PData(val)).as!B, orig ); 208 assertEq( (shared PData(val)).as!B, orig ); 209 assertEq( (shared const PData(val)).as!B, orig ); 210 } 211 212 void creationTest(T)( in T val ) 213 { 214 asTest( val, val ); 215 216 auto a = PData( val ); 217 auto ac = const PData( val ); 218 auto ai = immutable PData( val ); 219 auto as = shared PData( val ); 220 auto asc = shared const PData( val ); 221 222 asTest( a, val ); 223 asTest( ac, val ); 224 asTest( ai, val ); 225 asTest( as, val ); 226 asTest( asc, val ); 227 } 228 } 229 230 auto pureConv(T)( in immutable(void)[] data ) pure 231 { 232 static if( isPureData!T ) 233 return (cast(T[])(data.dup))[0]; 234 else static if( isPureType!T ) 235 return cast(T)(data.dup); 236 else static assert( 0, format( "unsuported type %s", T.stringof ) ); 237 } 238 239 immutable(void)[] pureDump(T)( in T val ) pure 240 { 241 static assert( !is( T == void[] ) ); 242 static if( isArray!T ) return (cast(void[])val).idup; 243 else return (cast(void[])[val]).idup; 244 }