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