1 module jar;
2 
3 import std.array;
4 import std.typecons;
5 
6 /// a container for registered types
7 class Jar {
8     private Object[][TypeInfo] _instance_registry;
9 
10     /// register a type instance
11     public T register(T)(T instance) {
12         auto type = typeid(instance);
13         if (type !in _instance_registry) {
14             _instance_registry[type] = new Object[0];
15         }
16         _instance_registry[type] ~= instance;
17         return instance;
18     }
19 
20     /// resolve all matching type instances
21     public T[] resolve_all(T)() {
22         auto type = typeid(T);
23         if (type in _instance_registry) {
24             Appender!(T[]) resolved;
25             foreach (item; _instance_registry[type]) {
26                 resolved ~= cast(T) item;
27             }
28             return resolved.data;
29         }
30         return new T[0];
31     }
32 
33     /// resolve first matching type instance
34     public Nullable!T resolve(T)() {
35         auto items = resolve_all!T();
36         if (items.length > 0) {
37             return Nullable!T(items[0]);
38         }
39         return Nullable!T.init;
40     }
41 }
42 
43 unittest {
44     class Cookie {
45         bool delicious = true;
46     }
47 
48     auto jar = new Jar();
49 
50     auto c1 = new Cookie();
51     jar.register(c1);
52     auto r1 = jar.resolve!Cookie();
53     assert(!r1.isNull, "resolved item was null");
54     assert(r1.get() == c1, "resolved item did not match");
55 
56     auto c2 = new Cookie();
57     jar.register(c2);
58 
59     const auto cookies = jar.resolve_all!Cookie();
60     assert(cookies.length == 2, "mismatch in number of registered items");
61 }