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