1 /** 2 License: 3 Boost Software License - Version 1.0 - August 17th, 2003 4 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 27 Authors: 28 Alexandru Ermicioi 29 **/ 30 module aermicioi.aedi_property_reader.core.placeholder; 31 32 import aermicioi.aedi : Wrapper; 33 import aermicioi.aedi_property_reader.core.traits : n; 34 import std.experimental.allocator; 35 import std.conv; 36 37 /** 38 Interface for objects that are aware of a type and can provide it. 39 **/ 40 interface TypeAware { 41 42 /** 43 Get the type that is stored in component. 44 45 Returns: 46 TypeInfo stored in component. 47 **/ 48 TypeInfo type() const nothrow @property @nogc; 49 } 50 51 /** 52 Interface for objects that can hold a value in. 53 **/ 54 interface Placeholder(T) : TypeAware { 55 56 @property { 57 58 /** 59 Get stored value. 60 61 Returns: 62 T value stored in component 63 **/ 64 ref inout(T) value() nothrow @safe inout @nogc; 65 66 /** 67 Store value in component. 68 69 Params: 70 value = value that will be stored in. 71 72 Returns: 73 Reference to stored value. 74 **/ 75 ref T value(ref T value) nothrow @safe; 76 77 /** 78 ditto 79 **/ 80 final ref T value(T value) nothrow @safe { 81 return this.value(value); 82 } 83 84 /** 85 Subtyping to stored value. 86 **/ 87 alias value this; 88 } 89 } 90 91 /** 92 Implementation of Placeholder!T. 93 **/ 94 class PlaceholderImpl(T) : Placeholder!T, Wrapper!T { 95 96 private { 97 T payload; 98 } 99 100 /** 101 Constructor for placeholder accepting stored value. 102 103 Params: 104 value = value that will be stored in. 105 **/ 106 this(ref T value) { 107 this.value = value; 108 } 109 110 /** 111 ditto 112 **/ 113 this(T value) { 114 this(value); 115 } 116 117 /** 118 Get the type of component that is stored in. 119 120 Returns: 121 TypeInfo of stored component. 122 **/ 123 TypeInfo type() const { 124 return typeid(T); 125 } 126 127 @property { 128 /** 129 Set value 130 131 Params: 132 value = value to be stored 133 134 Returns: 135 value 136 **/ 137 ref T value(ref T value) @safe nothrow { 138 this.payload = value; 139 140 return this.payload; 141 } 142 143 /** 144 Get value 145 146 Returns: 147 ref inout(T) 148 **/ 149 ref inout(T) value() @safe nothrow inout @nogc { 150 return this.payload; 151 } 152 } 153 } 154 155 /** 156 Wrap up a value in a placeholding object. 157 158 Params: 159 value = value that will be wrapped in placeholding object 160 allocator = allocator used to allocate placeholding object 161 162 Returns: 163 Placeholder!T with value as content. 164 **/ 165 auto placeholder(T)(auto ref T value, RCIAllocator allocator = theAllocator) { 166 static if (is(T : Object)) { 167 return value; 168 } else { 169 return allocator.make!(PlaceholderImpl!T)(value); 170 } 171 } 172 173 /** 174 Downcast object to type T, or unwrap it from Placeholder!T. 175 176 Downcast object to type T, or unwrap it from Placeholder!T. 177 If T is rooted in Object, downcast will be performed, otherwise 178 it is assumed that T is stored in Placeholder!T object, and therefore 179 object is downcast to Placeholder!T and then returned. 180 181 Params: 182 object = object from which to unwrap value of type T 183 Returns: 184 T if it is rooted in Object, or Placeholder!T if it is not. 185 **/ 186 auto unwrap(T)(inout(Object) object) nothrow { 187 import aermicioi.aedi_property_reader.core.traits : n; 188 static if (is(T : Object)) { 189 190 return cast(T) object; 191 } else { 192 193 auto wrapper = (cast(Placeholder!T) object); 194 195 assert(wrapper !is null, text(object.classinfo, " does not implement ", typeid(Placeholder!T), " ", typeid(T), " content cannot be extracted")).n; 196 197 return wrapper; 198 } 199 } 200 201 /** 202 Identify the type of object. 203 204 Identify the type of object. 205 The object will be downcasted to TypeAware first, in order 206 to test if object is holding information about some type. 207 If so, the type from TypeAware object will be returned, 208 otherwise classinfo of object itself. 209 210 Params: 211 object = component to be identified 212 Returns: 213 TypeInfo of stored type of object implements TypeAware, or classinfo of object itself. 214 **/ 215 TypeInfo identify(T : Object)(in T object) nothrow @nogc { 216 if (object is null) { 217 return typeid(null); 218 } 219 220 TypeAware p = cast(TypeAware) object; 221 222 if (p !is null) { 223 return p.type; 224 } 225 226 return object.classinfo; 227 } 228 229 /** 230 Get the type of component. 231 232 Params: 233 component = the component for which to return the type. 234 235 Returns: 236 TypeInfo the type of component 237 **/ 238 TypeInfo identify(T)(in T component) nothrow @nogc @safe 239 if (!is(T : Object)) { 240 241 return typeid(component); 242 }