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