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 aermicioi 29 **/ 30 module aermicioi.aedi.storage.decorator; 31 32 import std.range.primitives : isInputRange, isForwardRange, ElementType; 33 34 /** 35 Provides the underlying decorated object. 36 **/ 37 @safe interface Decorator(T) { 38 39 public { 40 @property { 41 42 /** 43 Get the decorated object. 44 45 Returns: 46 T decorated object 47 **/ 48 inout(T) decorated() @safe nothrow inout; 49 } 50 } 51 } 52 53 /** 54 Allows to get and set decorated object. 55 **/ 56 @safe interface MutableDecorator(T) : Decorator!T { 57 public { 58 @property { 59 60 alias decorated = Decorator!T.decorated; 61 /** 62 Set the decorated object for decorator. 63 64 Params: 65 decorated = decorated component 66 67 Returns: 68 this 69 **/ 70 typeof(this) decorated(T decorated) @safe nothrow; 71 } 72 } 73 } 74 75 /** 76 Treat component as a chain of decorated entities and express this as a range of decorators. 77 78 Params: 79 ComponentType = The original type of component attempted to interpret as a range of decorators. 80 DecoratorType = type each decorator in decorator chain. 81 component = component to express as a range of decorators. 82 83 Returns: 84 DecoratorChain!(ComponentType, DecoratorType) the range. 85 **/ 86 DecoratorChain!(ComponentType, DecoratorType) decorators(DecoratorType, ComponentType)(ComponentType component) { 87 return DecoratorChain!(ComponentType, DecoratorType)(component); 88 } 89 90 /** 91 ditto 92 **/ 93 @safe struct DecoratorChain(ComponentType, DecoratorType) 94 if (is(ComponentType == class) || is(ComponentType == interface)) { 95 import std.traits : Unqual, QualifierOf; 96 import std.typecons : Rebindable; 97 98 private alias QualifierOfComponentType = QualifierOf!ComponentType; 99 private alias QualifiedDecoratorType = QualifierOfComponentType!(Decorator!DecoratorType); 100 101 private Rebindable!(QualifiedDecoratorType) current; 102 103 /** 104 Constructor for decorator chain 105 106 Params: 107 initial = starting point of decorated component 108 **/ 109 this(ComponentType initial) @trusted { 110 current = cast(QualifiedDecoratorType) initial; 111 } 112 113 private this(QualifiedDecoratorType copy) { 114 current = copy; 115 } 116 117 /** 118 Whether empty or not 119 120 Returns: 121 true if empty false otherwise 122 **/ 123 bool empty() { 124 return current is null; 125 } 126 127 /** 128 The first decorator in chain of decorators. 129 130 Returns: 131 Decorated component with storage class preserved. 132 **/ 133 QualifiedDecoratorType front() { 134 return current; 135 } 136 137 /** 138 Move to next decorator in chain 139 **/ 140 void popFront() @trusted { 141 current = cast(QualifiedDecoratorType) current.decorated; 142 } 143 144 /** 145 Save decorator range. 146 147 Returns: 148 A copy of current range 149 **/ 150 typeof(this) save() { 151 return typeof(this)(current); 152 } 153 } 154 155 /** 156 Mixin implementing MutableDecorator for a decorated element of T. 157 **/ 158 @safe mixin template MutableDecoratorMixin(T) { 159 160 private { 161 T decorated_; 162 } 163 164 public { 165 /** 166 Set decorated 167 168 Params: 169 decorated = the element that is decorated by implementor 170 171 Returns: 172 typeof(this) 173 **/ 174 typeof(this) decorated(T decorated) @safe nothrow pure 175 in { 176 static if (is(T == class) || is(T == interface) || is(T == X*, X)) { 177 assert(decorated !is null, "Expected a decorated value, passed null."); 178 } 179 } 180 do { 181 this.decorated_ = decorated; 182 183 return this; 184 } 185 186 /** 187 Get decorated 188 189 Returns: 190 T 191 **/ 192 inout(T) decorated() @safe nothrow pure inout 193 out(result) { 194 static if (is(T == class) || is(T == interface) || is(T == X*, X)) { 195 assert(result !is null, "Attempted to return decorated instance, however none was configured in decorator itself."); 196 } 197 } 198 do { 199 return this.decorated_; 200 } 201 } 202 }