1 module mecca.runtime.services; 2 3 // Licensed under the Boost license. Full copyright information in the AUTHORS file 4 5 6 private __gshared void delegate()[] _atExitCallbacks; 7 8 public void registerAtExit(void function() fn) { 9 import std.functional: toDelegate; 10 _atExitCallbacks ~= toDelegate(fn); 11 } 12 public void registerAtExit(void delegate() dg) { 13 _atExitCallbacks ~= dg; 14 } 15 16 package void runAtExitCallbacks() { 17 foreach(dg; _atExitCallbacks) { 18 dg(); 19 } 20 _atExitCallbacks.length = 0; 21 } 22 23 struct ServiceInterface { 24 enum State { 25 DOWN, 26 SETUP, 27 UP, 28 DISABLED, 29 TEARDOWN, 30 } 31 32 string[] deps; 33 bool delegate() setup; 34 void delegate() teardown; 35 State state = State.DOWN; 36 } 37 38 mixin template registerService() { 39 __gshared static typeof(this) instance; 40 41 shared static this() { 42 import std..string; 43 import std.traits; 44 import mecca.runtime.services: ServiceInterface, _registeredServices; 45 46 string svcName; 47 ServiceInterface svcCbs; 48 49 static if (__traits(hasMember, typeof(this), "SVC_NAME")) { 50 svcName = typeof(this).SVC_NAME; 51 } 52 else if (typeof(this).stringof.toLower.endsWith("service")) { 53 svcName = typeof(this).stringof[0 .. $-6]; 54 } 55 else { 56 svcName = typeof(this).stringof; 57 } 58 59 static if (__traits(hasMember, typeof(this), "getDeps")) { 60 svcCbs.deps = instance.getDeps(); 61 } 62 static if (__traits(hasMember, typeof(this), "SVC_DEPS")) { 63 static if (is(typeof(instance.SVC_DEPS == string))) { 64 svcCbs.deps = [instance.SVC_DEPS]; 65 } 66 else { 67 svcCbs.deps = instance.SVC_DEPS; 68 } 69 } 70 else { 71 svcCbs.deps = null; 72 } 73 74 static if (__traits(hasMember, typeof(this), "setup")) { 75 svcCbs.setup = &instance.setup; 76 } 77 else static if (__traits(hasMember, typeof(this), "mainFib")) { 78 svcCbs.setup = (){ 79 import mecca.reactor: theReactor; 80 theReactor.spawnFiber(&instance.mainFib); 81 return true; 82 }; 83 } 84 85 static if (__traits(hasMember, typeof(this), "teardown")) { 86 svcCbs.teardown = &instance.teardown; 87 } 88 else { 89 svcCbs.teardown = (){}; 90 } 91 92 _registeredServices[svcName] = svcCbs; 93 } 94 } 95 96 __gshared ServiceInterface[string] _registeredServices; 97 package __gshared void function()[][string] _serviceGlobalsInitFuncs; 98 99 template ServiceGlobal(string svc, T, string mod=__MODULE__, size_t line=__LINE__) { 100 __gshared T* obj = null; 101 shared static this() { 102 perServiceInitFuncs[svc] ~= () { 103 assert (obj is null); 104 import std.traits: isStaticArray; 105 static if (isStaticArray!T) { 106 struct S { 107 T data; 108 } 109 obj = &(new S).data; 110 } 111 else { 112 obj = new T; 113 } 114 }; 115 } 116 @property ref T ServiceGlobal() @trusted nothrow @nogc { 117 assert (obj !is null); 118 return *obj; 119 } 120 } 121 122 /+version (unittest) { 123 private: 124 alias utLong = ServiceGlobal!("UT", long); 125 alias utBiggy = ServiceGlobal!("UT", long[10000]); 126 127 unittest { 128 foreach(fn; perServiceInitFuncs["UT"]) { 129 fn(); 130 } 131 132 assert (utLong == 0); 133 utLong = 17; 134 assert (utLong == 17); 135 assert (utBiggy[1888] == 0); 136 utBiggy[1888] = 9999; 137 assert (utBiggy[1888] == 9999); 138 } 139 } 140 +/ 141 142 143