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 
36 /**
37  Interface for objects that can serevr Type elements.
38 **/
39 interface Locator(Type = Object, KeyType = string) {
40     
41     public {
42         
43 		/**
44 		Get an Type that is associated with key.
45 		
46 		Params:
47 			identity = the element id.
48 			
49 		Throws:
50 			NotFoundException in case if the element wasn't found.
51 		
52 		Returns:
53 			Type element if it is available.
54 		**/
55         Type get(KeyType identity);
56         
57         /**
58         Check if an element is present in Locator by key id.
59         
60         Note:
61         	This check should be done for elements that locator actually contains, and
62         	not in chained locator (when locator is also a DelegatingLocator) for example.
63         Params:
64         	identity = identity of element.
65         	
66     	Returns:
67     		bool true if an element by key is present in Locator.
68         **/
69         bool has(in KeyType identity) inout;
70     }
71 }
72 
73 /**
74 Exposes the list of locators contained in it.
75 **/
76 interface AggregateLocator(Type = Object, KeyType = string, LocatorKeyType = KeyType) : 
77     Locator!(Type, KeyType) {
78     
79     import std.range.interfaces;
80     import std.typecons;
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!(Tuple!(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 interface MutableAggregateLocator(Type = Object, KeyType = string, LocatorKeyType = KeyType) : AggregateLocator!(Type, KeyType, LocatorKeyType), Storage!(Locator!(Type, KeyType), LocatorKeyType) {
114     
115 }
116 
117 /**
118 Given a locator, locates an object and attempts to convert to T type.
119 
120 Given a locator, locates an object and attempts to convert to T type.
121 When an object of T type is located, it is simply casted to T type.
122 When an value of T type is located, the func attempts to cast the requested object to
123 Wrapper!T, and will return it, instead of T directly.
124 In case of failure an InvalidCastException is thrown in debug environment.
125 
126 Params:
127 	locator = the locator that contains the data with id as identity
128 	id = identity of object contained in locator
129 
130 Throws:
131 	InvalidCastException in debug mode when actual type of object is not of type that is requested.
132 
133 Returns:
134 	Object casted to desired type.
135 **/
136 @trusted auto ref locate(T : Object)(Locator!(Object, string) locator, string id) {
137     import aermicioi.aedi.exception.invalid_cast_exception;
138     
139     auto result = cast(T) locator.get(id);
140     
141     if (result is null) {
142         throw new InvalidCastException("Requested object " ~ id ~ " is not of type " ~ typeid(T).toString());
143     }
144     
145     return result;
146 }
147 
148 @trusted auto ref locate(T)(Locator!(Object, string) locator, string id) 
149     if (is(T == interface)) {
150     import aermicioi.aedi.exception.invalid_cast_exception;
151     import aermicioi.aedi.storage.wrapper;
152     
153     auto casted = cast(T) locator.get(id);
154     
155     if (casted !is null) {
156         return casted;
157     }
158     
159     auto wrapper = cast(Wrapper!T) locator.get(id);
160     
161     if (wrapper !is null) {
162         return wrapper;
163     }
164     
165     throw new InvalidCastException("Requested object " ~ id ~ " is not of type " ~ typeid(T).toString());
166 }
167 
168 /**
169 ditto
170 **/
171 @trusted auto ref locate(T)(Locator!(Object, string) locator, string id) 
172     if(!is(T == interface)) {
173     import aermicioi.aedi.exception.invalid_cast_exception;
174     import aermicioi.aedi.storage.wrapper;
175     
176     auto wrapper = (cast(Wrapper!T) locator.get(id));
177     
178     if (wrapper is null) {
179         throw new InvalidCastException("Requested object " ~ id ~ " is not of type " ~ typeid(T).toString());
180     }
181     
182     return wrapper;
183 }
184 
185 /**
186 ditto
187 **/
188 @trusted auto ref locate(T)(Locator!(Object, string) locator) {
189     import aermicioi.aedi.factory.reference : name;
190     
191     return locate!T(locator, name!T);
192 }