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.subscribable_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.alias_aware; 36 import aermicioi.aedi.storage.storage; 37 import aermicioi.aedi.factory.factory; 38 import aermicioi.aedi.exception.not_found_exception; 39 import aermicioi.util.traits; 40 import std.meta; 41 import std.traits; 42 43 import std.range.interfaces; 44 import std.typecons; 45 46 interface Subscribable(T) { 47 48 public { 49 50 Subscribable subscribe( 51 T type, 52 void delegate() subscriber 53 ); 54 } 55 } 56 57 enum ContainerInstantiationEventType { 58 pre, 59 post, 60 } 61 62 template SubscribableContainer(T) { 63 64 /** 65 Set which the switchable container will decorate for T. By default 66 Locator!() and Subscribable!ContainerInstantiationEventType is included. 67 **/ 68 alias InheritanceSet = AliasSeq!(Filter!( 69 templateOr!( 70 partialSuffixed!( 71 isDerived, 72 Storage!(ObjectFactory, string) 73 ), 74 partialSuffixed!( 75 isDerived, 76 AliasAware!string 77 ), 78 partialSuffixed!( 79 isDerived, 80 FactoryLocator!ObjectFactory 81 ) 82 ), 83 InterfacesTuple!T), 84 Container, 85 Subscribable!ContainerInstantiationEventType, 86 MutableDecorator!T 87 ); 88 89 class SubscribableContainer : InheritanceSet { 90 private { 91 void delegate()[][ContainerInstantiationEventType] subscribers; 92 T decorated_; 93 } 94 95 public { 96 97 this() { 98 subscribers[ContainerInstantiationEventType.pre] = null; 99 subscribers[ContainerInstantiationEventType.post] = null; 100 } 101 102 @property { 103 SubscribableContainer decorated(T container) @safe nothrow { 104 this.decorated_ = container; 105 106 return this; 107 } 108 109 T decorated() @safe nothrow { 110 return this.decorated_; 111 } 112 } 113 114 Object get(string key) { 115 return this.decorated.get(key); 116 } 117 118 bool has(in string key) inout { 119 return this.decorated_.has(key); 120 } 121 122 SubscribableContainer subscribe( 123 ContainerInstantiationEventType event, 124 void delegate() subscriber 125 ) { 126 this.subscribers[event] ~= subscriber; 127 128 return this; 129 } 130 131 SubscribableContainer instantiate() { 132 foreach (preProcessor; this.subscribers[ContainerInstantiationEventType.pre]) { 133 preProcessor(); 134 } 135 136 this.decorated.instantiate(); 137 138 foreach (postProcessor; this.subscribers[ContainerInstantiationEventType.post]) { 139 postProcessor(); 140 } 141 142 return this; 143 } 144 145 static if (is(T : Storage!(ObjectFactory, string))) { 146 147 SubscribableContainer!T set(ObjectFactory element, string identity) { 148 decorated.set(element, identity); 149 150 return this; 151 } 152 153 SubscribableContainer!T remove(string identity) { 154 decorated.remove(identity); 155 156 return this; 157 } 158 } 159 160 static if (is(T : AliasAware!string)) { 161 SubscribableContainer!T link(string identity, string alias_) { 162 decorated.link(identity, alias_); 163 164 return this; 165 } 166 167 SubscribableContainer!T unlink(string alias_) { 168 decorated.unlink(alias_); 169 170 return this; 171 } 172 173 const(string) resolve(in string alias_) const { 174 return decorated_.resolve(alias_); 175 } 176 } 177 178 static if (is(T : FactoryLocator!ObjectFactory)) { 179 180 ObjectFactory getFactory(string identity) { 181 return this.decorated.getFactory(identity); 182 } 183 184 InputRange!(Tuple!(ObjectFactory, string)) getFactories() { 185 return this.decorated.getFactories(); 186 } 187 } 188 } 189 } 190 } 191