1 /**
2 
3 License:
4 	Boost Software License - Version 1.0 - August 17th, 2003
5 
6     Permission is hereby granted, free of charge, to any person or organization
7     obtaining a copy of the software and accompanying documentation covered by
8     this license (the "Software") to use, reproduce, display, distribute,
9     execute, and transmit the Software, and to prepare derivative works of the
10     Software, and to permit third-parties to whom the Software is furnished to
11     do so, all subject to the following:
12 
13     The copyright notices in the Software and this entire statement, including
14     the above license grant, this restriction and the following disclaimer,
15     must be included in all copies of the Software, in whole or in part, and
16     all derivative works of the Software, unless such copies or derivative
17     works are solely in the form of machine-executable object code generated by
18     a source language processor.
19 
20     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26     DEALINGS IN THE SOFTWARE.
27 
28 Authors:
29 	Alexandru Ermicioi
30 **/
31 
32 module aermicioi.aedi.storage.locator;
33 
34 import aermicioi.aedi.storage.storage;
35 import aermicioi.aedi.util.typecons : Pair, pair;
36 
37 /**
38  Interface for objects that can serevr Type elements.
39 **/
40 @safe interface Locator(Type = Object, KeyType = string) {
41 
42     public {
43 
44 		/**
45 		Get a Type that is associated with key.
46 
47 		Params:
48 			identity = the element id.
49 
50 		Throws:
51 			NotFoundException in case if the element wasn't found.
52 
53 		Returns:
54 			Type element if it is available.
55 		**/
56         Type get(KeyType identity);
57 
58         /**
59         Check if an element is present in Locator by key id.
60 
61         Note:
62         	This check should be done for elements that locator actually contains, and
63         	not in chained locator.
64         Params:
65         	identity = identity of element.
66 
67     	Returns:
68     		bool true if an element by key is present in Locator.
69         **/
70         bool has(in KeyType identity) inout;
71     }
72 }
73 
74 /**
75 Exposes the list of locators contained in it.
76 **/
77 @safe interface AggregateLocator(Type = Object, KeyType = string, LocatorKeyType = KeyType) :
78     Locator!(Type, KeyType) {
79 
80     import std.range.interfaces : InputRange;
81 
82     public {
83 
84         /**
85         Get a specific locator.
86 
87         Params:
88             key = the locator identity.
89         **/
90         Locator!(Type, KeyType) getLocator(LocatorKeyType key);
91 
92         /**
93         Get all locators in aggregate locator
94 
95         Returns:
96         	InputRange!(Tuple!(Locator!(Type, KeyType), LocatorKeyType)) a range of locator => identity
97         **/
98         InputRange!(Pair!(Locator!(Type, KeyType), LocatorKeyType)) getLocators();
99 
100         /**
101         Check if aggregate locator contains a specific locator.
102 
103         Params:
104         	key = the identity of locator in aggregate locator
105         **/
106         bool hasLocator(LocatorKeyType key) inout;
107     }
108 }
109 
110 /**
111 Exposes, and allows to set a list of containers into it.
112 **/
113 @safe interface MutableAggregateLocator(Type = Object, KeyType = string, LocatorKeyType = KeyType) :
114     AggregateLocator!(Type, KeyType, LocatorKeyType), Storage!(Locator!(Type, KeyType), LocatorKeyType) {
115 
116 }
117 
118 /**
119 Given a locator, locates an object and attempts to downcast to T type.
120 
121 See:
122     aermicioi.aedi.storage.wrapper : unwrap for downcasting semantics.
123 
124 Params:
125 	locator = the locator that contains the component with id as identity
126 	id = identity of object contained in locator
127 
128 Throws:
129 	InvalidCastException when actual type of object is not of type that is requested.
130 
131 Returns:
132 	Object casted to desired type.
133 **/
134 @trusted auto ref locate(T)(Locator!(Object, string) locator, string id) {
135     import aermicioi.aedi.storage.wrapper : unwrap;
136     return locator.get(id).unwrap!T;
137 }
138 
139 /**
140 ditto
141 **/
142 @trusted auto ref locate(T)(Locator!(Object, string) locator) {
143     import std.traits : fullyQualifiedName;
144     string id = typeid(T).toString;
145 
146     if (!locator.has(id)) {
147         id = fullyQualifiedName!T;
148     }
149 
150     return locator.locate!T(id);
151 }
152 
153 /**
154 Mix in locator interface implementation that delegates
155 the logic to decorated container.
156 **/
157 @safe mixin template LocatorMixin(T : Locator!(W, X), W, X) {
158     mixin LocatorMixin!(W, X);
159 }
160 
161 /**
162 ditto
163 **/
164 @safe mixin template LocatorMixin(W, X) {
165     /**
166     Get object created by a factory identified by key
167 
168     Params:
169         key = identity of factory
170     Returns:
171     Object
172     **/
173     W get(X key)
174     in(decorated !is null, "Cannot get component out of decorated component container, when no container to decorate is provided.")
175     {
176         return this.decorated.get(key);
177     }
178 
179     /**
180     Check if an object factory for it exists in container.
181 
182     Params:
183         key = identity of factory
184     Returns:
185         bool
186     **/
187     bool has(in X key) inout
188     in(decorated !is null, "Cannot check if component is in decorated component container, when no container to decorate is provided.")
189     {
190         return this.decorated_.has(key);
191     }
192 }