1 /** 2 * Mixin for retrieving values from the parsed tree by path 3 * 4 * Copyright: © 2017 Andrey Kabylin 5 * License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 */ 7 8 module rpdl.accessors; 9 10 /** 11 * Mixin for retrieving values from the parsed tree by path. 12 * To access to variables you can use `get` or `opt` methods e.g. `getParameter` will 13 * return `rpdl.node.Parameter`, i.e. function name builds from prefix (get or opt) and 14 * type name. If method starts with `get`, then method can throw an exception 15 * if value will not find by the path. If you use `opt`, then exception will not thrown 16 * if value didn't found, also you can set default value for value which not found. 17 * If value found but has wrong type you will get `WrongNodeType` exception. 18 */ 19 mixin template Accessors() { 20 alias getObjectNode = getTypedNode!(ObjectNode); 21 alias getParameterNode = getTypedNode!(Parameter); 22 alias getValueNode = getTypedNode!(Value); 23 alias getNumberValueNode = getTypedNode!(NumberValue); 24 alias getStringValueNode = getTypedNode!(StringValue); 25 alias getIdentifierValueNode = getTypedNode!(IdentifierValue); 26 alias getBooleanValueNode = getTypedNode!(BooleanValue); 27 alias getArrayValueNode = getTypedNode!(ArrayValue); 28 29 alias optObjectNode = optTypedNode!(ObjectNode); 30 alias optParameterNode = optTypedNode!(Parameter); 31 alias optValueNode = optTypedNode!(Value); 32 alias optNumberValueNode = optTypedNode!(NumberValue); 33 alias optStringValueNode = optTypedNode!(StringValue); 34 alias optIdentifierValueNode = optTypedNode!(IdentifierValue); 35 alias optBooleanValueNode = optTypedNode!(BooleanValue); 36 alias optArrayValueNode = optTypedNode!(ArrayValue); 37 38 alias getNumber = getTypedValue!(float, NumberValue); 39 alias getBoolean = getTypedValue!(bool, BooleanValue); 40 alias getString = getTypedValue!(string, StringValue); 41 alias getIdentifier = getTypedValue!(string, IdentifierValue); 42 43 alias optNumber = optTypedValue!(float, NumberValue); 44 alias optBoolean = optTypedValue!(bool, BooleanValue); 45 alias optString = optTypedValue!(string, StringValue); 46 alias optIdentifier = optTypedValue!(string, IdentifierValue); 47 48 dstring getUTF32String(in string path) { 49 return getTypedNode!(StringValue)(path).utf32Value; 50 } 51 52 int getInteger(in string path) { 53 return to!int(getNumber(path)); 54 } 55 56 dstring optUTF32String(in string path, dstring defaultVal = dstring.init) { 57 StringValue node = optTypedNode!(StringValue)(path, null); 58 59 if (node is null) 60 return defaultVal; 61 62 return node.utf32Value; 63 } 64 65 int optInteger(in string path, int defaultVal = 0) { 66 return to!int(optNumber(path, to!float(defaultVal))); 67 } 68 69 alias getVec2f = getVecValue!(float, 2); 70 alias getVec3f = getVecValue!(float, 3); 71 alias getVec4f = getVecValue!(float, 4); 72 alias getVec2i = getVecValue!(int, 2); 73 alias getVec3i = getVecValue!(int, 3); 74 alias getVec4i = getVecValue!(int, 4); 75 alias getVec2ui = getVecValue!(uint, 2); 76 alias getVec3ui = getVecValue!(uint, 3); 77 alias getVec4ui = getVecValue!(uint, 4); 78 79 alias optVec2f = optVecValue!(float, 2); 80 alias optVec3f = optVecValue!(float, 3); 81 alias optVec4f = optVecValue!(float, 4); 82 alias optVec2i = optVecValue!(int, 2); 83 alias optVec3i = optVecValue!(int, 3); 84 alias optVec4i = optVecValue!(int, 4); 85 alias optVec2ui = optVecValue!(uint, 2); 86 alias optVec3ui = optVecValue!(uint, 3); 87 alias optVec4ui = optVecValue!(uint, 4); 88 89 /** 90 * Retrieve normilized color to 1 i.e. r/255, g/255, b/255, a/100. 91 * 92 * Returns: 93 * `vec4f` value contains inside the node 94 * if `rpdl.node.Node` has 3 components, then `alpha` will set to 1. 95 */ 96 vec4 getNormColor(in string path) { 97 vec4 color; 98 99 try { 100 color = getVec4f(path); 101 } catch(WrongNodeType) { 102 try { 103 vec3 color3 = getVec3f(path); 104 color = vec4(color3, 100.0f); 105 } catch(WrongNodeType) { 106 throw new WrongNodeType(path, "color(vec4 or vec3)"); 107 } 108 } 109 110 color = vec4(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 100.0f); 111 return color; 112 } 113 114 /** 115 * Retrieve enum with type `T` value from found node by `path` 116 * See_also: `optEnum`, `ufcsGetEnum`, `ufcsOptEnum` 117 */ 118 T getEnum(T)(in string path) { 119 const string val = getIdentifier(path); 120 121 foreach (immutable enumItem; [EnumMembers!T]) { 122 if (to!string(enumItem) == val) { 123 return enumItem; 124 } 125 } 126 127 throw new WrongNodeType(path, T.stringof); 128 } 129 130 /** 131 * Retrieve optional enum with type `T` value from found node by `path` 132 * if node was not found then it will return `defaultVal` 133 * See_also: `getEnum`, `ufcsGetEnum`, `ufcsOptEnum` 134 */ 135 T optEnum(T)(in string path, in T defaultVal = T.init) { 136 try { 137 return getEnum!(T)(path); 138 } catch (NotFoundException) { 139 return defaultVal; 140 } 141 } 142 143 // Helper methods for access to nodes and values by path ------------------------------------------- 144 145 /** 146 * Find typed node by `path`, node should be inherited from `T`. 147 * See_also: `optTypedNode`, `getTypedValue`, `optTypedValue` 148 */ 149 private T getTypedNode(T : Node)(in string path) { 150 Node node = findNodeByPath(path, getRootNode()); 151 152 if (node is null) 153 throw new NotFoundException("Node with path \"" ~ path ~ "\" not found"); 154 155 T object = cast(T)(node); 156 157 if (object is null) 158 throw new WrongNodeType(path, T.stringof); 159 160 return cast(T)(node); 161 } 162 163 /** 164 * Get node by `path` and retrieve value from this node. 165 * Node should be ingerited from `N` and value should be inherited from `T`. 166 * See_also: `optTypedNode`, `getTypedNode`, `optTypedValue` 167 */ 168 private T getTypedValue(T, N : Node)(in string path) { 169 return getTypedNode!N(path).value; 170 } 171 172 /** 173 * Get node by `path`, node should be inherited from `T`. 174 * If node was not found then it will return `defaultVal`. 175 * See_also: `optTypedNode`, `getTypedValue`, `optTypedValue` 176 */ 177 private T optTypedNode(T : Node)(in string path, T defaultVal) { 178 Node node = findNodeByPath(path, getRootNode()); 179 180 if (node is null) 181 return defaultVal; 182 183 T object = cast(T)(node); 184 185 if (object is null) 186 throw new WrongNodeType(path, T.stringof); 187 188 return cast(T)(node); 189 } 190 191 /** 192 * Get node by `path` and retrieve value from this node. 193 * Node should be ingerited from `N` and value should be inherited from `T`. 194 * If node was not found then it will return `defaultVal`. 195 * See_also: `getTypedValue`, `getTypedNode`, `optTypedNode` 196 */ 197 private T optTypedValue(T, N : Node)(in string path, T defaultVal = T.init) { 198 N node = optTypedNode!N(path, null); 199 200 if (node is null) 201 return defaultVal; 202 203 return node.value; 204 } 205 206 /** 207 * This method retrieves vector value from node by `path`, size of vector is `n` 208 * and type of their components is `T`. 209 * 210 * See_also: `getVecValueFromNode`, `optVecValue` 211 */ 212 private Vector!(T, n) getVecValue(T, int n)(in string path) { 213 Node node = getNode(path); 214 215 if (node is null) 216 throw new NotFoundException("Node with path \"" ~ path ~ "\" not found"); 217 218 return getVecValueFromNode!(T, n)(path, node); 219 } 220 221 /** 222 * This method retrieves vector value from particular `node`. Size of vector is `n` 223 * and type of their components is `T`. 224 * If node was not found then method will return `defaultVal`. 225 * See_also: `getVecValue`, `optVecValue` 226 */ 227 private Vector!(T, n) getVecValueFromNode(T, int n)(in string path, Node node) { 228 if (node.length != n) 229 throw new WrongNodeType(path, T.stringof); 230 231 NumberValue[n] vectorComponents; 232 T[n] values; 233 234 for (int i = 0; i < n; ++i) { 235 vectorComponents[i] = cast(NumberValue) node.getAtIndex(i); 236 237 if (vectorComponents[i] is null) 238 throw new WrongNodeType(path, T.stringof); 239 240 values[i] = to!T(vectorComponents[i].value); 241 } 242 243 return Vector!(T, n)(values); 244 } 245 246 /** 247 * This method retrieves vector value from node by `path`, size of vector is `n` 248 * and type of their components is `T`. 249 * If node was not found then method will return `defaultVal`. 250 * See_also: `getVecValue`, `getVecValueFromNode` 251 */ 252 private Vector!(T, n) optVecValue(T, int n)(in string path, 253 Vector!(T, n) defaultVal = Vector!(T, n).init) 254 { 255 Node node = findNodeByPath(path, getRootNode()); 256 257 if (node is null) 258 return defaultVal; 259 260 return getVecValueFromNode!(T, n)(path, node); 261 } 262 } 263 264 import rpdl.exception; 265 import rpdl.node; 266 267 /// UFCS method for `Accessors.getEnum` 268 T ufcsGetEnum(T)(Node node, in string path) { 269 return node.getEnum!(T)(path); 270 } 271 272 /// UFCS method for `Accessors.optEnum` 273 T ufcsOptEnum(T)(Node node, in string path, in T defaultVal = T.init) { 274 return node.optEnum!(T)(path, defaultVal); 275 }