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.container.gc_registering_container;
31 
32 import aermicioi.aedi.container.container;
33 import aermicioi.aedi.storage.object_storage;
34 import aermicioi.aedi.storage.decorator;
35 import aermicioi.aedi.storage.locator : LocatorMixin;
36 import aermicioi.aedi.storage.alias_aware;
37 import aermicioi.aedi.storage.storage;
38 import aermicioi.aedi.factory.factory;
39 import aermicioi.aedi.exception.not_found_exception;
40 import aermicioi.aedi.util.traits;
41 import std.meta;
42 import std.traits;
43 
44 import std.range.interfaces;
45 
46 /**
47 Decorating container that will decorate all passed factories with gc registering factory.
48 This decorated will inherit following interfaces only and only if the
49 T also implements them:
50   $(OL
51       $(LI Storage!(ObjectFactory, string))
52       $(LI Container)
53       $(LI AliasAware!string)
54   )
55 Decorated container must implement following interfaces:
56     $(OL
57         $(LI Container)
58         $(LI MutableDecorator!T)
59         $(LI Subscribable!ContainerInstantiationEventType)
60         $(LI Decorator!Container)
61     )
62 
63 Params:
64     T = The decorated that switchable decorated will decorate.
65 **/
66 template GcRegisteringContainer(T)
67 {
68 
69     /**
70     Set which the switchable container will decorate for T. By default
71     Locator!() and Subscribable!ContainerInstantiationEventType is included.
72     **/
73     alias InheritanceSet = NoDuplicates!(Filter!(
74         templateOr!(
75             partialSuffixed!(
76                 isDerived,
77                 Storage!(ObjectFactory, string)
78             ),
79             partialSuffixed!(
80                 isDerived,
81                 AliasAware!string
82             ),
83             partialSuffixed!(
84                 isDerived,
85                 FactoryLocator!ObjectFactory
86             )
87         ),
88         InterfacesTuple!T),
89         Container,
90         Decorator!Container
91     );
92 
93     @safe class GcRegisteringContainer : InheritanceSet
94     {
95 
96         public
97         {
98 
99             /**
100             Default constructor for GcRegisteringContainer
101             **/
102             this()
103             {
104             }
105 
106             mixin MutableDecoratorMixin!(T);
107             mixin LocatorMixin!(typeof(this));
108             mixin ContainerMixin!(typeof(this));
109 
110             static if (is(T : Storage!(ObjectFactory, string)))
111             {
112 
113                 /**
114                 Set object factory
115 
116                 Params:
117                     element = factory for a object that is to be managed by prototype container.
118                     identity = identity of factory
119                 Returns:
120                     typeof(this)
121                 **/
122                 GcRegisteringContainer!T set(ObjectFactory element, string identity)
123                 {
124                     decorated.set(new GcRegisteringFactoryDecorator(element), identity);
125 
126                     return this;
127                 }
128 
129                 /**
130                 Remove an object factory from container.
131 
132                 Params:
133                     identity = identity of factory to be removed
134                 Returns:
135                     typeof(this)
136                 **/
137                 GcRegisteringContainer!T remove(string identity)
138                 {
139                     decorated.remove(identity);
140 
141                     return this;
142                 }
143             }
144 
145             static if (is(T : AliasAware!string))
146             {
147 
148                 mixin AliasAwareMixin!(typeof(this));
149             }
150 
151             static if (is(T : FactoryLocator!ObjectFactory))
152             {
153 
154                 mixin FactoryLocatorMixin!(typeof(this));
155             }
156         }
157     }
158 }
159 
160 private @safe class GcRegisteringFactoryDecorator : Factory!Object {
161     import aermicioi.aedi.storage.locator_aware : LocatorAwareMixin;
162     import aermicioi.aedi.storage.allocator_aware : AllocatorAwareMixin;
163 
164     mixin LocatorAwareMixin!GcRegisteringFactoryDecorator;
165     mixin AllocatorAwareMixin!GcRegisteringFactoryDecorator;
166     mixin MutableDecoratorMixin!(Factory!Object);
167 
168     public {
169         this(Factory!Object decorated) {
170             this.decorated = decorated;
171         }
172 
173         /**
174 		Instantiates component of type Object.
175 
176 		Returns:
177 			Object instantiated component.
178 		**/
179 		Object factory() @trusted {
180             import core.memory : GC;
181 
182             Object object = this.decorated.factory();
183             GC.addRange(cast(void*) object, this.type.initializer.length, object.classinfo);
184 
185             return object;
186         }
187 
188         /**
189         Destructs a component of type T.
190 
191         Params:
192             component = component that is to ve destroyed.
193         **/
194         void destruct(ref Object component) @trusted {
195             import core.memory : GC;
196             GC.removeRange(cast(void*) component);
197 
198             this.decorated.destruct(component);
199         }
200 
201 		@property {
202 
203 		    /**
204     		Get the type info of T that is created.
205 
206     		Returns:
207     			TypeInfo object of created component.
208     		**/
209     		TypeInfo type() @safe nothrow const {
210                 return this.decorated.type();
211             }
212 		}
213     }
214 }