1 /++
2 Bits and bobs to register plugins to be instantiated on program startup/connect.
3 4 This should really only have to be used internally.
5 6 Example:
7 ---
8 import kameloso.plugins;
9 import kameloso.plugins.common.core;
10 11 final class MyPlugin : IRCPlugin
12 {
13 mixin IRCPluginImpl;
14 }
15 16 mixin ModuleRegistration;
17 ---
18 19 Example:
20 ---
21 import kameloso.plugins;
22 23 IRCPluginState state;
24 // state setup...
25 26 IRCPlugin[] plugins = instantiatePlugins(state);
27 ---
28 29 Copyright: [JR](https://github.com/zorael)
30 License: [Boost Software License 1.0](https://www.boost.org/users/license.html)
31 32 Authors:
33 [JR](https://github.com/zorael)
34 +/35 modulekameloso.plugins;
36 37 private:
38 39 importkameloso.plugins.common.core : IRCPlugin, IRCPluginState;
40 41 42 // PluginRegistrationEntry43 /++
44 An entry in [registeredPlugins] corresponding to a plugin registered to be
45 instantiated on program startup/connect.
46 +/47 structPluginRegistrationEntry48 {
49 // priority50 /++
51 Priority at which to instantiate the plugin. A lower priority makes it
52 get instantiated before other plugins.
53 +/54 Prioritypriority;
55 56 // ctor57 /++
58 Function pointer to a "constructor"/builder that instantiates the relevant plugin.
59 +/60 IRCPluginfunction(IRCPluginState) ctor;
61 62 // this63 /++
64 Constructor.
65 66 Params:
67 priority = [kameloso.plugins.Priority|Priority] at which
68 to instantiate the plugin. A lower priority value makes it get
69 instantiated before other plugins.
70 ctor = Function pointer to a "constructor"/builder that instantiates
71 the relevant plugin.
72 +/73 this(
74 constPrioritypriority,
75 typeof(this.ctor) ctor) pure @safenothrow @nogc76 {
77 this.priority = priority;
78 this.ctor = ctor;
79 }
80 }
81 82 83 // registeredPlugins84 /++
85 Array of registered plugins, represented by [PluginRegistrationEntry]/-ies,
86 to be instantiated on program startup/connect.
87 +/88 sharedPluginRegistrationEntry[] registeredPlugins;
89 90 91 // module constructor92 /++
93 Module constructor that merely reserves space for [registeredPlugins] to grow into.
94 95 Only include this if the compiler is based on 2.095 or later, as the call to
96 [object.reserve|reserve] fails with those prior to that.
97 +/98 staticif (__VERSION__ >= 2095L)
99 sharedstaticthis()
100 {
101 enuminitialSize = 64;
102 (cast()registeredPlugins).reserve(initialSize);
103 }
104 105 106 public:
107 108 109 // registerPlugin110 /++
111 Registers a plugin to be instantiated on program startup/connect by creating
112 a [PluginRegistrationEntry] and appending it to [registeredPlugins].
113 114 Params:
115 priority = Priority at which to instantiate the plugin. A lower priority
116 makes it get instantiated before other plugins.
117 ctor = Function pointer to a "constructor"/builder that instantiates
118 the relevant plugin.
119 +/120 voidregisterPlugin(
121 constPrioritypriority,
122 IRCPluginfunction(IRCPluginState) ctor)
123 {
124 registeredPlugins ~= PluginRegistrationEntry(
125 priority,
126 ctor);
127 }
128 129 130 // instantiatePlugins131 /++
132 Instantiates all plugins represented by a [PluginRegistrationEntry] in
133 [registeredPlugins].
134 135 Plugin modules may register their plugin classes by mixing in [PluginRegistration].
136 137 Params:
138 state = The current plugin state on which to base new plugin instances.
139 140 Returns:
141 An array of instantiated [kameloso.plugins.common.core.IRCPlugin|IRCPlugin]s.
142 +/143 autoinstantiatePlugins(/*const*/IRCPluginStatestate)
144 {
145 importstd.algorithm.sorting : sort;
146 147 IRCPlugin[] plugins;
148 plugins.length = registeredPlugins.length;
149 uinti;
150 151 autosortedPluginRegistrations = registeredPlugins152 .sort!((a,b) => a.priority.value < b.priority.value);
153 154 foreach (registration; sortedPluginRegistrations)
155 {
156 plugins[i++] = registration.ctor(state);
157 }
158 159 returnplugins;
160 }
161 162 163 // PluginRegistration164 /++
165 Mixes in a module constructor that registers the supplied [IRCPlugin] subclass
166 to be instantiated on program startup/connect.
167 168 Params:
169 Plugin = Plugin class of module.
170 priority = Priority at which to instantiate the plugin. A lower priority
171 makes it get instantiated before other plugins. Defaults to `0.priority`.
172 module_ = String name of the module. Only used in case an error message is needed.
173 +/174 mixintemplatePluginRegistration(
175 Plugin,
176 Prioritypriority = 0.priority,
177 stringmodule_ = __MODULE__)
178 {
179 // module constructor180 /++
181 Mixed-in module constructor that registers the passed [Plugin] class
182 to be instantiated on program startup.
183 +/184 sharedstaticthis()
185 {
186 importkameloso.plugins.common.core : IRCPluginState;
187 188 staticif (__traits(compiles, newPlugin(IRCPluginState.init)))
189 {
190 importkameloso.plugins : registerPlugin;
191 192 staticautoctor(IRCPluginStatestate)
193 {
194 returnnewPlugin(state);
195 }
196 197 registerPlugin(priority, &ctor);
198 }
199 else200 {
201 importstd.format : format;
202 203 enumpattern = "`%s.%s` constructor does not compile";
204 enummessage = pattern.format(module_, Plugin.stringof);
205 staticassert(0, message);
206 }
207 }
208 }
209 210 211 // Priority212 /++
213 Embodies the notion of a priority at which a plugin should be instantiated,
214 and as such, the order in which they will be called to handle events.
215 216 This also affects in what order they appear in the configuration file.
217 +/218 structPriority219 {
220 /++
221 Numerical priority value. Lower is higher.
222 +/223 intvalue;
224 225 /++
226 Helper `opUnary` to allow for `-10.priority`, instead of having to do the
227 (more correct) `(-10).priority`.
228 229 Example:
230 ---
231 mixin PluginRegistration!(MyPlugin, -10.priority);
232 ---
233 234 Params:
235 op = Operator.
236 237 Returns:
238 A new [Priority] with a [Priority.value|value] equal to the negative of this one's.
239 +/240 autoopUnary(stringop: "-")() const241 {
242 returnPriority(-value);
243 }
244 }
245 246 247 // priority248 /++
249 Helper alias to use the proper style guide and still be able to instantiate
250 [Priority] instances with UFCS.
251 252 Example:
253 ---
254 mixin PluginRegistration!(MyPlugin, 50.priority);
255 ---
256 +/257 aliaspriority = Priority;