1 /**
2 	Various functions to determine types at runtime.
3 	Originally found in my raijin library and has been backported here.
4 
5 	Authors: Paul Crane
6 */
7 
8 module typeutils;
9 
10 import std.typecons;
11 import std.traits;
12 import std.conv;
13 import std.algorithm : count;
14 
15 alias AllowNumericBooleanValues = Flag!"allowNumericBooleanValues";
16 
17 /**
18 	Determines if value is a true value
19 
20 	Params:
21 		value = The value to check for a true value
22 		allowInteger = Set to allowNumericBooleanValues.yes if a true value can be a numeric 1
23 
24 	Returns:
25 		true if the value is true false otherwise.
26 */
27 bool isTrue(T)(const T value, const AllowNumericBooleanValues allowInteger = AllowNumericBooleanValues.yes) @trusted
28 {
29 	static if(isIntegral!T)
30 	{
31 		return(value == 1);
32 	}
33 	else
34 	{
35 		if(allowInteger)
36 		{
37 			return(value == "1" || value == "true");
38 		}
39 
40 		return (value == "true");
41 	}
42 }
43 
44 ///
45 unittest
46 {
47 	assert(isTrue("true") == true);
48 	assert(isTrue("false") == false);
49 	assert(isTrue("1") == true);
50 	assert(isTrue("0") == false);
51 	assert(isTrue("12345") == false);
52 	assert(isTrue("trues") == false);
53 
54 	assert("1".isTrue(AllowNumericBooleanValues.no) == false);
55 }
56 
57 /**
58 	Determines if value is a false value
59 
60 	Params:
61 		value = The value to check for a false value
62 		allowInteger = Set to allowNumericBooleanValues.yes if a false value can be a numeric 0
63 
64 	Returns:
65 		true if the value is false false otherwise.
66 */
67 bool isFalse(T)(const T value, const AllowNumericBooleanValues allowInteger = AllowNumericBooleanValues.yes) @trusted
68 {
69 	static if(isIntegral!T)
70 	{
71 		return(value == 0);
72 	}
73 	else
74 	{
75 		if(allowInteger)
76 		{
77 			return(value == "0" || value == "false");
78 		}
79 
80 		return (value == "false");
81 	}
82 }
83 
84 ///
85 unittest
86 {
87 	assert(isFalse("false") == true);
88 	assert(isFalse("true") == false);
89 	assert(isFalse("1") == false);
90 	assert(isFalse("0") == true);
91 	assert(isFalse("12345") == false);
92 	assert(isFalse("trues") == false);
93 
94 	assert("0".isFalse(AllowNumericBooleanValues.no) == false);
95 }
96 
97 /**
98 	Determines if a value is of type boolean using 0, 1, true and false as qualifiers.
99 
100 	Params:
101 		value = number or boolean string to use. Valid values of 0, 1, "0", "1", "true", "false"
102 		allowInteger = Set to allowNumericBooleanValues.yes if a true/false value can be a numeric 0 or 1
103 
104 	Returns:
105 		true if the value is a boolean false otherwise.
106 */
107 bool isBoolean(T)(const T value, const AllowNumericBooleanValues allowInteger = AllowNumericBooleanValues.yes) @trusted
108 {
109 	return(isTrue(value, allowInteger) || isFalse(value, allowInteger));
110 }
111 
112 ///
113 unittest
114 {
115 	assert("0".isBoolean == true);
116 	assert("1".isBoolean == true);
117 	assert("2".isBoolean == false);
118 
119 	assert("true".isBoolean == true);
120 	assert("false".isBoolean == true);
121 	assert("trues".isBoolean == false);
122 
123 	assert("0".isBoolean(AllowNumericBooleanValues.no) == false);
124 	assert("1".isBoolean(AllowNumericBooleanValues.no) == false);
125 
126 	assert(0.isBoolean == true);
127 	assert(1.isBoolean == true);
128 	assert(2.isBoolean == false);
129 }
130 
131 /**
132 	Determines if a string is a decimal value
133 
134 	Params:
135 		value = string to use.
136 
137 	Returns:
138 		true if the value is a decimal false otherwise.
139 */
140 bool isDecimal(const string value) pure @safe
141 {
142 	import std.string : isNumeric;
143 	return (isNumeric(value) && value.count(".") == 1) ? true : false;
144 }
145 
146 ///
147 unittest
148 {
149 	assert("13".isDecimal == false);
150 	assert("13.333333".isDecimal == true);
151 	assert("zzzz".isDecimal == false);
152 }
153 /**
154 	Determines if a string is an integer value.
155 
156 	Params:
157 		value = string to use.
158 
159 	Returns:
160 		true if the value is a integer false otherwise.
161 */
162 bool isInteger(const string value) pure @safe
163 {
164 	import std.string : isNumeric;
165 	return (isNumeric(value) && value.count(".") == 0) ? true : false;
166 }
167 
168 ///
169 unittest
170 {
171 	assert("13".isInteger == true);
172 	assert("13.333333".isInteger == false);
173 	assert("zzzz".isInteger == false);
174 }