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 }