1 /+ 2 The MIT License (MIT) 3 4 Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 +/ 24 25 module des.util.pdata; 26 27 import std.traits; 28 import std.string; 29 30 import des.util.testsuite; 31 32 alias immutable(void)[] data_t; 33 34 bool isPData(T)() { return is( Unqual!T == PData ); } 35 36 private pure data_t pureDumpData(T)( in T val ) 37 { 38 static if( isPData!T ) return val.data.idup; 39 else static if( isArray!T ) return val.idup; 40 else static if( !hasUnsharedAliasing!T ) return [val].idup; 41 else static assert( 0, format( "unsupported type '%s' for pure read data", T.stringof ) ); 42 } 43 44 @property @safe pure nothrow isPureDump(T)() 45 { return is( typeof( pureDumpData( T.init ) ) ); } 46 47 unittest 48 { 49 static assert( isPureDump!(data_t) ); 50 static assert( isPureDump!(string) ); 51 static assert( isPureDump!(double) ); 52 static assert( isPureDump!(PData) ); 53 static assert( isPureDump!(const(PData)) ); 54 static assert( isPureDump!(shared(PData)) ); 55 static assert( isPureDump!(immutable(PData)) ); 56 static assert( isPureDump!(double[]) ); 57 static assert( !isPureDump!(int[string]) ); 58 59 static struct TS { int[string] val; } 60 static assert( !isPureDump!(TS) ); 61 } 62 63 private T conv(T)( in data_t data ) 64 { 65 static if( isArray!T ) return cast(T)data.dup; 66 else static if( !hasUnsharedAliasing!T ) 67 { 68 if( data.length * void.sizeof != T.sizeof ) 69 throw new Exception( format( "PData unable convert to '%s': wrong data length", T.stringof ) ); 70 return (cast(T[])data.dup)[0]; 71 } 72 else static if( __traits(compiles, T.load(data)) ) 73 return T.load(data); 74 else static assert( 0, format( "unsupported type '%s'", T.stringof ) ); 75 } 76 77 struct PData 78 { 79 data_t data; 80 alias data this; 81 82 private void readData(T)( in T val ) 83 { 84 static if( isPureDump!T ) 85 data = pureDumpData( val ); 86 else static if( __traits(compiles, val.dump()) ) 87 data = val.dump().idup; 88 else static assert( 0, format( "unsupported type '%s'", T.stringof ) ); 89 } 90 91 pure this( in void[] dd ) { data = dd.idup; } 92 93 pure this(T)( in T val ) if( isPureDump!T ) 94 { data = pureDumpData( val ); } 95 96 this(T)( in T val ) if( !isPureDump!T ) 97 { readData( val ); } 98 99 T opAssign(T)( in T val ) 100 { 101 readData( val ); 102 return val; 103 } 104 105 @property 106 { 107 T as(T)() const { return conv!T( data ); } 108 T as(T)() shared const { return conv!T( data ); } 109 T as(T)() immutable { return conv!T( data ); } 110 } 111 } 112 113 unittest 114 { 115 static assert( isPureDump!PData ); 116 } 117 118 unittest 119 { 120 auto a = PData( [ .1, .2, .3 ] ); 121 assert( eq( a.as!(double[]), [ .1, .2, .3 ] ) ); 122 a = "hello"; 123 assert( eq( a.as!string, "hello" ) ); 124 125 static struct TestStruct 126 { double x, y; string info; immutable(int)[] data; } 127 auto ts = TestStruct( 10.1, 12.3, "hello", [1,2,3,4] ); 128 129 auto xx = PData( ts ); 130 131 auto xa = shared PData( xx ); 132 auto xb = const PData( xx ); 133 auto xc = shared const PData( xx ); 134 auto xd = immutable PData( xx ); 135 auto xe = shared immutable PData( xx ); 136 137 assert( xx == xa ); 138 assert( xx == xb ); 139 assert( xx == xc ); 140 assert( xx == xd ); 141 assert( xx == xe ); 142 143 assert( xa.as!TestStruct == ts ); 144 assert( xb.as!TestStruct == ts ); 145 assert( xc.as!TestStruct == ts ); 146 assert( xd.as!TestStruct == ts ); 147 assert( xe.as!TestStruct == ts ); 148 149 auto ax = PData( xa ); 150 auto bx = PData( xb ); 151 auto cx = PData( xc ); 152 auto dx = PData( xd ); 153 auto ex = PData( xe ); 154 155 assert( xx == ax ); 156 assert( xx == bx ); 157 assert( xx == cx ); 158 assert( xx == dx ); 159 assert( xx == ex ); 160 161 assert( ax.data == xx.data ); 162 assert( bx.data == xx.data ); 163 assert( cx.data == xx.data ); 164 assert( dx.data == xx.data ); 165 assert( ex.data == xx.data ); 166 167 assert( ax.as!TestStruct == ts ); 168 assert( bx.as!TestStruct == ts ); 169 assert( cx.as!TestStruct == ts ); 170 assert( dx.as!TestStruct == ts ); 171 assert( ex.as!TestStruct == ts ); 172 } 173 174 unittest 175 { 176 import std.conv; 177 static class TestClass 178 { 179 int[string] info; 180 181 static auto load( in void[] data ) 182 { 183 auto str = cast(string)data.dup; 184 auto elems = str.split(","); 185 int[string] buf; 186 foreach( elem; elems ) 187 { 188 auto key = elem.split(":")[0]; 189 auto val = to!int( elem.split(":")[1] ); 190 buf[key] = val; 191 } 192 return new TestClass( buf ); 193 } 194 195 this( in int[string] I ) 196 { 197 foreach( key, val; I ) 198 info[key] = val; 199 info.rehash(); 200 } 201 202 auto dump() const 203 { 204 string[] buf; 205 foreach( key, val; info ) buf ~= format( "%s:%s", key, val ); 206 return cast(void[])( buf.join(",").dup ); 207 } 208 } 209 210 auto tc = new TestClass( [ "ok":1, "no":3, "yes":5 ] ); 211 212 auto a = PData( tc ); 213 auto ta = a.as!TestClass; 214 assert( ta.info == tc.info ); 215 216 auto b = a; 217 b = "ok:1,no:3"; 218 auto tb = b.as!TestClass; 219 tc.info.remove( "yes" ); 220 221 assert( tb.info == tc.info ); 222 223 tc.info["yes"] = 5; 224 b = a; 225 tb = b.as!TestClass; 226 assert( tb.info == tc.info ); 227 } 228 229 unittest 230 { 231 auto fnc_a() { return cast(immutable(ubyte)[])("hello_a".idup); } 232 auto fnc_b() { return cast(ubyte[])("hello_b".dup); } 233 auto a = PData( fnc_a() ); 234 assert( a.as!string == "hello_a" ); 235 auto b = PData( fnc_b() ); 236 assert( b.as!string == "hello_b" ); 237 238 auto ca = const PData( fnc_a() ); 239 assert( ca.as!string == "hello_a" ); 240 auto cb = const PData( fnc_b() ); 241 assert( cb.as!string == "hello_b" ); 242 243 auto ia = immutable PData( fnc_a() ); 244 assert( ia.as!string == "hello_a" ); 245 auto ib = immutable PData( fnc_b() ); 246 assert( ib.as!string == "hello_b" ); 247 248 auto sa = shared PData( fnc_a() ); 249 assert( sa.as!string == "hello_a" ); 250 auto sb = shared PData( fnc_b() ); 251 assert( sb.as!string == "hello_b" ); 252 253 auto sca = shared const PData( fnc_a() ); 254 assert( sca.as!string == "hello_a" ); 255 auto scb = shared const PData( fnc_b() ); 256 assert( scb.as!string == "hello_b" ); 257 258 auto sia = shared immutable PData( fnc_a() ); 259 assert( sia.as!string == "hello_a" ); 260 auto sib = shared immutable PData( fnc_b() ); 261 assert( sib.as!string == "hello_b" ); 262 }