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 }