1 /**
2     Iz is is - reason for choosing iz is because is is a keyword. Answers the qustions "is this 'thing' ____ ?"
3 */
4 module bolts.iz;
5 
6 import bolts.internal;
7 
8 /**
9     `Iz` is a helper template that allows you to inspect a type or an alias.
10 
11     It takes a single element as an argument. The reason the template parameters is
12     types as a variable arg sequence is becure if D does not allow (pre version 2.087)
13     to say "I want either a type or alias over here, I don't care, I'll figure it out".
14     But it does allow it when you use a $(I template sequence parameter)
15 
16     $(TABLE
17     $(TR $(TH method) $(TH Description))
18     $(TR
19         $(TD $(DDOX_NAMED_REF bolts.iz.iz.of, `of`))
20         $(TD True if the resolved type is the same as another resolved type)
21         )
22     $(TR
23         $(TD $(DDOX_NAMED_REF bolts.iz.iz.sameAs, `sameAs`))
24         $(TD True if T and U are the same "thing" (type, alias, literal value))
25         )
26     $(TR
27         $(TD $(DDOX_NAMED_REF bolts.iz.iz.nullType, `nullType`))
28         $(TD True if the resolved type is typeof(null))
29         )
30     $(TR
31         $(TD $(DDOX_NAMED_REF bolts.iz.iz.unaryOver, `unaryOver`))
32         $(TD True if the resolved type a unary funtion over some other types)
33         )
34     $(TR
35         $(TD $(DDOX_NAMED_REF bolts.iz.iz.binaryOver, `binaryOver`))
36         $(TD True if the resolved type a binary funtion over some other types)
37         )
38     $(TR
39         $(TD $(DDOX_NAMED_REF bolts.iz.iz.functionOver, `functionOver`))
40         $(TD True if the resolved type an n-ary funtion over n types)
41         )
42     $(TR
43         $(TD $(DDOX_NAMED_REF bolts.iz.iz.refType, `refType`))
44         $(TD True if the resolved type a reference type)
45         )
46     $(TR
47         $(TD $(DDOX_NAMED_REF bolts.iz.iz.valueType, `valueType`))
48         $(TD True if the resolved type a value type)
49         )
50     $(TR
51         $(TD $(DDOX_NAMED_REF bolts.iz.iz.literalOf, `literalOf`))
52         $(TD True if the resolved type is a literal of a type of T)
53         )
54     $(TR
55         $(TD $(DDOX_NAMED_REF bolts.iz.iz.literal, `literal`))
56         $(TD True if the resolved type is a literal)
57         )
58     $(TR
59         $(TD $(DDOX_NAMED_REF bolts.iz.iz.copyConstructable, `copyConstructable`))
60         $(TD True if resolved type is copy constructable)
61         )
62     $(TR
63         $(TD $(DDOX_NAMED_REF bolts.iz.iz.nonTriviallyCopyConstructable, `nonTriviallyCopyConstructable`))
64         $(TD True if resolved type is non-trivially copy constructable)
65         )
66     $(TR
67         $(TD $(DDOX_NAMED_REF bolts.iz.iz.triviallyCopyConstructable, `triviallyCopyConstructable`))
68         $(TD True if resolved is trivially copy constructable)
69         )
70     $(TR
71         $(TD $(DDOX_NAMED_REF bolts.iz.iz.equatableTo, `equatableTo`))
72         $(TD True if resolved type is equatabel to other)
73         )
74     $(TR
75         $(TD $(DDOX_NAMED_REF bolts.iz.iz.nullTestable, `nullTestable`))
76         $(TD True if resolved type can be checked against null)
77         )
78     $(TR
79         $(TD $(DDOX_NAMED_REF bolts.iz.iz.nullSettable, `nullSettable`))
80         $(TD True if resolved type can be set to null)
81         )
82     $(TR
83         $(TD $(DDOX_NAMED_REF bolts.iz.iz.refDecl, `refDecl`))
84         $(TD True if resolved type is declred with ref or is a function that returns ref)
85         )
86     )
87 
88     See_also:
89         - https://dlang.org/spec/template.html#variadic-templates
90 */
91 template iz(Aliases...) if (Aliases.length == 1) {
92     import bolts.traits.symbols: TypesOf;
93 
94     alias ResolvedType = TypesOf!Aliases[0];
95 
96     /// See: `bolts.traits.symbols.isOf`
97     static template of(Other...) if (Other.length == 1) {
98         enum of = from.bolts.traits.isOf!(Aliases[0], Other[0]);
99     }
100 
101     // TODO: Remove on major bump
102     deprecated("use nullTestable")
103     enum nullable = from.bolts.traits.isNullable!ResolvedType;
104 
105     /// See: `bolts.traits.types.isNullType`
106     enum nullType = from.bolts.traits.isNullType!ResolvedType;
107 
108     /// See: `bolts.traits.symbols.isSame`
109     static template sameAs(Other...) if (Other.length == 1) {
110         enum sameAs = from.bolts.traits.isSame!(Aliases[0], Other[0]);
111     }
112 
113     /// See: `bolts.traits.functions.isFunctionOver`
114     enum functionOver(U...) = from.bolts.traits.isFunctionOver!(Aliases[0], U);
115 
116     /// See: `bolts.traits.functions.isUnaryOver`
117     enum unaryOver(U...) = from.bolts.traits.isUnaryOver!(Aliases[0], U);
118 
119     /// See: `bolts.traits.functions.isBinaryOver`
120     enum binaryOver(U...) = from.bolts.traits.isBinaryOver!(Aliases[0], U);
121 
122     /// See: `bolts.traits.types.isRefType`
123     enum refType = from.bolts.traits.isRefType!ResolvedType;
124 
125     /// See: `bolts.traits.types.isValueType`
126     enum valueType = from.bolts.traits.isValueType!ResolvedType;
127 
128     /// See: `bolts.traits.symbols.isLiteralOf`
129     enum literalOf(T) = from.bolts.traits.isLiteralOf!(Aliases[0], T);
130 
131     /// See: `bolts.traits.symbols.isLiteral`
132     enum literal = from.bolts.traits.isLiteral!(Aliases[0]);
133 
134     /// See: `bolts.traits.types.isCopyConstructable`
135     enum copyConstructable = from.bolts.traits.isCopyConstructable!ResolvedType;
136 
137     /// See: `bolts.traits.types.isNonTriviallyCopyConstructable`
138     enum nonTriviallyCopyConstructable = from.bolts.traits.isNonTriviallyCopyConstructable!ResolvedType;
139 
140     /// See: `bolts.traits.types.isTriviallyCopyConstructable`
141     enum triviallyCopyConstructable = from.bolts.traits.isTriviallyCopyConstructable!ResolvedType;
142 
143     /// See: `bolts.traits.types.areEquatable`
144     static template equatableTo(Other...) if (Other.length == 1) {
145         enum equatableTo = from.bolts.traits.areEquatable!(Aliases[0], Other[0]);
146     }
147 
148     /// See: `bolts.traits.types.isNullTestable`
149     enum nullTestable = from.bolts.traits.isNullTestable!Aliases;
150 
151     /// See: `bolts.traits.types.isNullSettable`
152     enum nullSettable = from.bolts.traits.isNullSettable!Aliases;
153 
154     /// See: `bolts.traits.symbols.isRefDecl`
155     enum refDecl = from.bolts.traits.isRefDecl!Aliases;
156 }
157 
158 ///
159 unittest {
160     int i = 3;
161     int j = 4;
162     int *pi = null;
163 
164     // Is it resolved to the same type as another?
165     static assert( iz!i.of!int);
166     static assert(!iz!i.of!(int*));
167     static assert( iz!3.of!i);
168     static assert(!iz!int.of!pi);
169 
170     // Is it the same as another?
171     static assert( iz!i.sameAs!i);
172     static assert(!iz!i.sameAs!j);
173     static assert( iz!1.sameAs!1);
174     static assert(!iz!1.sameAs!2);
175 
176     // Using std.meta algorithm with iz
177     import std.meta: allSatisfy, AliasSeq;
178     static assert(allSatisfy!(iz!int.of, 3, 4, int, i));
179 
180     /// Is it a function over
181     static assert( iz!(a => a).unaryOver!int);
182     static assert( iz!((a, b) => a).binaryOver!(int, int));
183     static assert( iz!((a, b, c, d) => a).functionOver!(int, int, int, int));
184 
185     // Is this thing a value or reference type?
186     struct SValueType {}
187     class CRefType {}
188     static assert( iz!SValueType.valueType);
189     static assert(!iz!CRefType.valueType);
190     static assert(!iz!SValueType.refType);
191     static assert( iz!CRefType.refType);
192 
193     static assert( iz!"hello".literalOf!string);
194     static assert(!iz!3.literalOf!string);
195 
196     // Is this thing copy constructable?
197     static struct SDisabledCopyConstructor { @disable this(ref typeof(this)); }
198     static assert(!iz!SDisabledCopyConstructor.copyConstructable);
199     static assert( iz!int.copyConstructable);
200 
201     // Does this thing define a custom copy constructor (i.e. non-trivial copy constructor)
202     static struct SCopyConstructor { this(ref typeof(this)) {} }
203     static assert( iz!SCopyConstructor.nonTriviallyCopyConstructable);
204     static assert(!iz!SCopyConstructor.triviallyCopyConstructable);
205     static assert(!iz!int.nonTriviallyCopyConstructable);
206     static assert( iz!int.triviallyCopyConstructable);
207 
208     // Can we equate these things?
209     static assert( iz!int.equatableTo!3);
210     static assert(!iz!3.equatableTo!string);
211 
212     // What null-semantics does the type have
213 
214     // Is it settable to null?
215     static struct SNullSettable { void opAssign(int*) {} }
216     static assert( iz!pi.nullSettable);
217     static assert( iz!SNullSettable.nullSettable);
218     static assert(!iz!i.nullSettable);
219 
220     // Is it checable with null? (i.e. if (this is null) )
221     static assert( iz!pi.nullTestable);
222     static assert(!iz!SNullSettable.nullTestable);
223     static assert(!iz!i.nullTestable);
224 
225     // Is it typeof(null)?
226     static assert(!iz!int.nullType);
227     static assert( iz!null.nullType);
228     static assert( iz!(typeof(null)).nullType);
229 }