1 /**
2 Aedi, a dependency injection library.
3 
4 Aedi is a dependency injection library. It does provide a set of containers that do
5 IoC, and an interface to configure application components (structs, objects, etc.)
6 
7 Aim:
8 
9 The aim of library is to provide a dependency injection solution that is
10 feature rich, easy to use, easy to learn, and easy to extend up to your needs.
11 
12 D by default comes with garbage collector which is responsible for destruction and
13 deallocation of components that were used, and discarded by the application. Current implementation
14 of garbage collector can be inefficient for cases when many small objects are continously
15 created and destroyed by application. Therefore aedi framework allows users to select what
16 allocation strategy to use for managed components by using std.experimental.allocator library.
17 
18 To change the allocator used for components in a container, it is possible to
19 pass new allocator implementation to $(D_INLINECODE configure) method as third argument
20 just like in example below:
21 -------------
22 with (container.configure("singleton", Mallocator.instance.allocatorObject)) {
23     // ... registered components with Mallocator as allocator for them
24 }
25 -------------
26 
27 The allocator passed in $(D_INLINECODE configure) will be used as default implementation.
28 As alternative syntax it is possible to pass the allocator in a fluent syntax by chaining
29 $(D_INLINECODE along) to $(D_INLINECODE configure) with allocator as it's argument. Example
30 below shows such variant:
31 -------------
32 with (container.configure("prototype").along(MmapAllocator.instance.allocatorObject)) {
33     // ... registered components with Mallocator as allocator for them
34 }
35 -------------
36 
37 The default allocator strategy can be overriden per component by directly specifying the
38 allocator that should be used by registered component using $(D_INLINECODE allocator) property
39 for registered component. Example below shows such use case:
40 -------------
41 register!Size("size.sedan") // Register a size of a generic "sedan" into container
42     .set!"width"(200UL)
43     .set!"height"(150UL)
44     .set!"length"(500UL)
45     .allocator(MmapAllocator.instance.allocatorObject); // Change allocator object for this particular component to mmap allocator.
46 -------------
47 
48 As a consequence to using custom allocation strategies, for all containers, $(D_INLINECODE terminate)
49 method should be called when containers lifetime ends (whether at end of application, or during some other
50 event), otherwise it is not guaranteed that components are finalized correctly, even if they were allocated on
51 garbage collector.
52 
53 License:
54 	Boost Software License - Version 1.0 - August 17th, 2003
55 
56 	Permission is hereby granted, free of charge, to any person or organization
57 	obtaining a copy of the software and accompanying documentation covered by
58 	this license (the "Software") to use, reproduce, display, distribute,
59 	execute, and transmit the Software, and to prepare derivative works of the
60 	Software, and to permit third-parties to whom the Software is furnished to
61 	do so, all subject to the following:
62 
63 	The copyright notices in the Software and this entire statement, including
64 	the above license grant, this restriction and the following disclaimer,
65 	must be included in all copies of the Software, in whole or in part, and
66 	all derivative works of the Software, unless such copies or derivative
67 	works are solely in the form of machine-executable object code generated by
68 	a source language processor.
69 
70 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
73 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
74 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
75 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
76 	DEALINGS IN THE SOFTWARE.
77 
78 Authors:
79 	aermicioi
80 **/
81 
82 module memory_management;
83 
84 import aermicioi.aedi;
85 import std.experimental.allocator;
86 import std.experimental.allocator.mallocator;
87 import std.experimental.allocator.gc_allocator;
88 import std.experimental.allocator.mmap_allocator;
89 import std.stdio;
90 
91 /**
92 A struct that should be managed by container.
93 **/
94 struct Color {
95     ubyte r;
96     ubyte g;
97     ubyte b;
98 }
99 
100 /**
101 Size of a car.
102 **/
103 struct Size {
104 
105     ulong width;
106     ulong height;
107     ulong length;
108 }
109 
110 /**
111 Interface for engines.
112 
113 An engine should implement it, in order to be installable in a car.
114 **/
115 interface Engine {
116 
117     public {
118 
119         void turnOn();
120         void run();
121         void turnOff();
122     }
123 }
124 
125 /**
126 A concrete implementation of Engine that uses gasoline for propelling.
127 **/
128 class GasolineEngine : Engine {
129 
130     public {
131 
132         void turnOn() {
133             writeln("pururukVrooomVrrr");
134 
135         }
136 
137         void run() {
138             writeln("vrooom");
139         }
140 
141         void turnOff() {
142             writeln("vrrrPrrft");
143         }
144     }
145 }
146 
147 /**
148 A concrete implementation of Engine that uses diesel for propelling.
149 **/
150 class DieselEngine : Engine {
151 
152     public {
153 
154         void turnOn() {
155             writeln("pururukVruumVrrr");
156 
157         }
158 
159         void run() {
160             writeln("vruum");
161         }
162 
163         void turnOff() {
164             writeln("vrrrPft");
165         }
166     }
167 }
168 
169 /**
170 A concrete implementation of Engine that uses electricity for propelling.
171 **/
172 class ElectricEngine : Engine {
173     public {
174 
175         void turnOn() {
176             writeln("pzt");
177 
178         }
179 
180         void run() {
181             writeln("vvvvvvvvv");
182         }
183 
184         void turnOff() {
185             writeln("tzp");
186         }
187     }
188 }
189 
190 /**
191 Tire, what it can represent else?
192 **/
193 class Tire {
194     private {
195         int size_;
196         float pressure_;
197         string vendor_;
198     }
199 
200     public @property {
201         Tire size(int size) @safe nothrow {
202         	this.size_ = size;
203 
204         	return this;
205         }
206 
207         int size() @safe nothrow {
208         	return this.size_;
209         }
210 
211         Tire pressure(float pressure) @safe nothrow {
212         	this.pressure_ = pressure;
213 
214         	return this;
215         }
216 
217         float pressure() @safe nothrow {
218         	return this.pressure_;
219         }
220 
221         Tire vendor(string vendor) @safe nothrow {
222         	this.vendor_ = vendor;
223 
224         	return this;
225         }
226 
227         string vendor() @safe nothrow {
228         	return this.vendor_;
229         }
230     }
231 
232     public override string toString() {
233         import std.algorithm;
234         import std.range;
235         import std.conv;
236         import std.utf;
237 
238         return only("Tire(", this.size.to!string, " inch, ", this.pressure.to!string, " atm, ", this.vendor, ")")
239             .joiner
240             .byChar
241             .array;
242     }
243 }
244 
245 /**
246 A class representing a car.
247 **/
248 class Car {
249 
250     private {
251         Color color_; // Car color
252         Size size_; // Car size
253         Engine engine_; // Car engine
254 
255         Tire frontLeft_;
256         Tire frontRight_;
257         Tire backLeft_;
258         Tire backRight_;
259     }
260 
261     public {
262 
263         /**
264         Constructor of car.
265 
266         Constructs a car with a set of sizes. A car cannot of course have
267         undefined sizes, so we should provide it during construction.
268 
269         Params:
270             size = size of a car.
271         **/
272         this(Size size, Engine engine) {
273             this.size_ = size;
274             this.engine = engine;
275         }
276 
277         @property {
278 
279             /**
280             Set color of car
281 
282             Set color of car. A car can live with undefined color (physics allow it).
283 
284             Params:
285             	color = color of a car.
286 
287             Returns:
288             	Car
289             **/
290             Car color(Color color) @safe nothrow {
291             	this.color_ = color;
292 
293             	return this;
294             }
295 
296             Color color() @safe nothrow {
297             	return this.color_;
298             }
299 
300             Size size() @safe nothrow {
301             	return this.size_;
302             }
303 
304             /**
305             Set engine used in car.
306 
307             Params:
308             	engine = engine used in car to propel it.
309 
310             Returns:
311             	Car
312             **/
313             Car engine(Engine engine) @safe nothrow {
314             	this.engine_ = engine;
315 
316             	return this;
317             }
318 
319             Engine engine() @safe nothrow {
320             	return this.engine_;
321             }
322 
323             Car frontLeft(Tire frontLeft) @safe nothrow {
324             	this.frontLeft_ = frontLeft;
325 
326             	return this;
327             }
328 
329             Tire frontLeft() @safe nothrow {
330             	return this.frontLeft_;
331             }
332 
333             Car frontRight(Tire frontRight) @safe nothrow {
334             	this.frontRight_ = frontRight;
335 
336             	return this;
337             }
338 
339             Tire frontRight() @safe nothrow {
340             	return this.frontRight_;
341             }
342 
343             Car backLeft(Tire backLeft) @safe nothrow {
344             	this.backLeft_ = backLeft;
345 
346             	return this;
347             }
348 
349             Tire backLeft() @safe nothrow {
350             	return this.backLeft_;
351             }
352 
353             Car backRight(Tire backRight) @safe nothrow {
354             	this.backRight_ = backRight;
355 
356             	return this;
357             }
358 
359             Tire backRight() @safe nothrow {
360             	return this.backRight_;
361             }
362 
363         }
364 
365         void start() {
366             engine.turnOn();
367         }
368 
369         void run() {
370             engine.run();
371         }
372 
373         void stop() {
374             engine.turnOff();
375         }
376     }
377 }
378 
379 /**
380 A manufacturer of cars.
381 **/
382 class CarManufacturer {
383 
384     public {
385         Car manufacture(Size size) {
386             return new Car(size, new DieselEngine()); // Manufacture a car.
387         }
388     }
389 }
390 
391 void drive(Car car, string name) {
392     writeln("Uuh, what a nice car, ", name," with following specs:");
393     writeln("Size:\t", car.size());
394     writeln("Color:\t", car.color());
395     writeln("Engine:\t", car.engine());
396     writeln("Tire front left:\t", car.frontLeft(), "\t located at memory ", cast(void*) car.frontLeft());
397     writeln("Tire front right:\t", car.frontRight(), "\t located at memory ", cast(void*) car.frontRight());
398     writeln("Tire back left: \t", car.backLeft(), "\t located at memory ", cast(void*) car.backLeft());
399     writeln("Tire back right:\t", car.backRight(), "\t located at memory ", cast(void*) car.backRight());
400 }
401 
402 void main() {
403     auto container = aggregate( // Create a joint container hosting other two containers
404         singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity
405         prototype(), "prototype" // Create prototype container, and store it in joint container by "prototype" identity
406     );
407     scope (exit) container.terminate();
408 
409     with (container.configure("singleton", Mallocator.instance.allocatorObject)) { // Configure singleton container with mallocator instead of gc allocator.
410         register!Color; // Let's register a default implementation of Color
411 
412         register!Color("color.green") // Register "green" color into container.
413             .set!"r"(cast(ubyte) 0)
414             .set!"g"(cast(ubyte) 255)
415             .set!"b"(cast(ubyte) 0);
416 
417         register!Size // Let's register default implementation of a Size
418             .set!"width"(200UL)
419             .set!"height"(150UL)
420             .set!"length"(300UL);
421 
422         register!Size("size.sedan") // Register a size of a generic "sedan" into container
423             .set!"width"(200UL)
424             .set!"height"(150UL)
425             .set!"length"(500UL)
426             .allocator(MmapAllocator.instance.allocatorObject); // Change allocator object for this particular component to mmap allocator.
427 
428         register!(Engine, ElectricEngine);
429 
430         register!Car
431             .autowire
432             .autowire!"color"
433             .set!"frontLeft"(lref!Tire)
434             .set!"frontRight"(lref!Tire)
435             .set!"backLeft"(lref!Tire)
436             .set!"backRight"(lref!Tire);
437     }
438 
439     with (container.configure("prototype").along(MmapAllocator.instance.allocatorObject)) { // Configure prototype container with mmap allocator instead of gc allocator.
440 
441         register!Tire // Registering Tire into "prototype" container used by aggregate container
442             .set!"size"(17)
443             .set!"pressure"(3.0)
444             .set!"vendor"("divine tire");
445     }
446 
447     container.instantiate(); // Boot container (or prepare managed code/data).
448 
449     container.locate!Car.drive("Electric car");
450 
451 }