spirit/extension.rs
1//! Interfaces for extending the [`Spirit`] and [`Builder`] with callbacks.
2//!
3//! Both the [`Spirit`] and [`Builder`] types allow registering callbacks. The [`Extensible`] trait
4//! describes the interface for registering them.
5//!
6//! Furthermore, [`Extensible`] is also implemented for `Result`s containing them. This allows
7//! chaining the building without manually handling the errors. The error then can be handled by
8//! [`Builder::run`][crate::Builder::run] and logged, without making a distinction if it comes from
9//! the setup or application run.
10//!
11//! Some libraries might want to provide bits of functionality that need to register several
12//! different callbacks at once to work properly. This is described by the [`Extension`] trait.
13//!
14//! In addition, the module contains few useful extensions that may be plugged in.
15//!
16//! [`Spirit`]: crate::Spirit
17//! [`Builder`]: crate::Builder
18//! [`Extension`]: crate::extension::Extension
19
20use std::any::Any;
21use std::fmt::Display;
22use std::sync::Arc;
23
24use log::warn;
25
26use crate::bodies::{HookWrapper, InnerBody};
27use crate::validation::Action;
28use crate::{AnyError, Spirit};
29
30/// An internal trait to make working uniformly with the [`Builder`] and `Result<Builder, Error>`
31/// possible.
32///
33/// You should not need to interact with the trait directly.
34///
35/// The idea is that both the [`Builder`] and the `Result<Builder, Error>` can be turned into
36/// `Result<Builder, Error>`.
37///
38/// [`Builder`]: crate::Builder
39pub trait IntoResult<T>: Sized {
40 /// Turns self into the result.
41 fn into_result(self) -> Result<T, AnyError>;
42}
43
44impl<T> IntoResult<T> for Result<T, AnyError> {
45 fn into_result(self) -> Result<T, AnyError> {
46 self
47 }
48}
49
50impl<T> IntoResult<T> for T {
51 fn into_result(self) -> Result<T, AnyError> {
52 Ok(self)
53 }
54}
55
56/// Selection of the way the background thread is handled at the end of the [`run`] method.
57///
58/// Note that this is a non-exhaustive enum. More variants may be added without considering it a
59/// breaking change.
60///
61/// [`run`]: crate::app::App::run
62#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
63#[non_exhaustive]
64pub enum Autojoin {
65 /// Terminate the application and join the background thread.
66 TerminateAndJoin,
67 /// Only join the background thread.
68 ///
69 /// It is up to the caller to ensure the background thread will actually terminate, so the
70 /// program doesn't deadlock.
71 Join,
72 /// Leave the background thread running and proceed.
73 ///
74 /// It is up to the caller to either join the thread manually or to make sure not doing proper
75 /// shutdown is OK. In particular, if the thread is left running on application termination,
76 /// the [guards][Extensible::keep_guard] need not to be dropped.
77 Abandon,
78}
79
80/// An interface allowing to extend something with callbacks.
81///
82/// This describes the interface to registering various callbacks. This unifies the interaction
83/// with [`Builder`] and [`Spirit`], so there's little difference between registering a callback
84/// when setting things up and when everything is already running (but see notes at various
85/// methods, sometimes there are subtle differences ‒ specifically, it is not possible to do some
86/// things when the application already started).
87///
88/// In addition, this is also implemented on `Result<Extensible, AnyError>`. This allows the caller
89/// to postpone all error handling for later or even leave it up to the
90/// [`Builder::run`][crate::SpiritBuilder::run`] to handle them.
91///
92/// # Deadlocks
93///
94/// In general, it is not possible to register callbacks from within callbacks. Internally, the
95/// structures holding them are protected by a mutex which needs to be locked both when
96/// manipulating and running them. Such attempt to register a callback from within a callback will
97/// lead to a deadlock (this restriction might be lifted in the future).
98///
99/// # Examples
100///
101/// ```rust
102/// use spirit::{Empty, Spirit};
103/// use spirit::prelude::*;
104///
105/// // This creates a Builder
106/// Spirit::<Empty, Empty>::new()
107/// // This returns Result<Builder, AnyError>. But we don't handle the error here, it propagates
108/// // further in the call chain.
109/// .run_before(|_spirit| Ok(()))
110/// // This run_before is on the Result<Builder, AnyError>. If the first one returned an error,
111/// // nothing would happen and the error would thread on. So, this works like implicit .and_then,
112/// // but without the inconvenience.
113/// //
114/// // (This also returns Result<Builder, AnyError>, not Result<Result<Builder, AnyError>,
115/// // AnyError>). .run_before(|_spirit| Ok(()))
116/// //
117/// // This .run can handle both the errors from above and from inside, logging them and
118/// // terminating if they happen.
119/// .run(|spirit| {
120/// // And this callback is registered onto the Spirit. Here, the run_before is started
121/// // right away.
122/// //
123/// // Here it is more convenient to just propagate the error, because the .run will handle
124/// // it.
125/// spirit.run_before(|_spirit| Ok(()))?;
126///
127/// Ok(())
128/// });
129/// ```
130///
131/// [`Builder`]: crate::Builder
132/// [`Spirit`]: crate::Spirit
133pub trait Extensible: Sized {
134 /// The command line options structure tied to this instance.
135 ///
136 /// A lot of the callbacks take command line structure as specified by the caller. This makes
137 /// the type available for users of the trait.
138 type Opts;
139
140 /// The configuration structure.
141 ///
142 /// Similar to [`Opts`][Extensible::Opts], this makes the type used to load configuration
143 /// available to the users of the trait.
144 type Config;
145
146 /// The Ok variant used when returning a result.
147 ///
148 /// Part of the trick to treat both `Extensible` and `Result<Extensible, AnyError>` in an
149 /// uniform way. This specifies what the OK variant of a result is ‒ it is either the Ok
150 /// variant of `Self` if we are `Result`, or `Self` if we are the `Extensible` proper.
151 type Ok;
152
153 /// Has the application already started?
154 ///
155 /// This makes it possible to distinguish between the [`Builder`][crate::Builder] and
156 /// [`Spirit`][crate::Spirit] in generic extension code.
157 ///
158 /// In general, this should not be needed as most of the method act in a sane way relevant to
159 /// the given type, but some special handling may be still needed.
160 const STARTED: bool;
161
162 /// A callback that is run after the building started and the command line is parsed, but even
163 /// before the first configuration is loaded. The configuration provided is either the one
164 /// provided to the builder, or a default one when called on the builder, but current
165 /// configuration when run on [`Spirit`].
166 ///
167 /// This is run right away if called on [`Spirit`], unless it is already terminated. In such
168 /// case, the callback is dropped.
169 ///
170 /// [`Spirit`]: crate::Spirit
171 fn before_config<F>(self, cback: F) -> Result<Self::Ok, AnyError>
172 where
173 F: FnOnce(&Self::Config, &Self::Opts) -> Result<(), AnyError> + Send + 'static;
174
175 /// Adds another config validator to the chain.
176 ///
177 /// The validators are there to check and possibly refuse a newly loaded configuration.
178 ///
179 /// The callback is passed three parameters:
180 ///
181 /// * The old configuration.
182 /// * The new configuration.
183 /// * The command line options.
184 ///
185 /// The new configuration is handled in this order:
186 ///
187 /// * First, [config mutators][Extensible::config_mutator] are called (in order of their
188 /// registration).
189 /// * Then all the config validators are called, in order of their registration. If any of them
190 /// fails, the configuration is refused and failure actions returned by the successful
191 /// validators are run.
192 /// * If successful, the success actions returned by validators are run.
193 /// * New configuration is stored.
194 /// * Config hooks are called, in order of registration.
195 ///
196 /// # The actions
197 ///
198 /// Sometimes, the only way to validate a piece of config is to try it out ‒ like when you want
199 /// to open a listening socket, you don't know if the port is free. But you can't activate and
200 /// apply just yet, because something further down the configuration might still fail.
201 ///
202 /// So, you open the socket (or create an error result) and store it into the success action to
203 /// apply it later on. If something fails, the action is dropped and the socket closed.
204 ///
205 /// The failure action lets you roll back (if it isn't done by simply dropping the thing).
206 ///
207 /// If the validation and application steps can be separated (you can check if something is OK
208 /// by just „looking“ at it ‒ like with a regular expression and using it can't fail), you
209 /// don't have to use them, just use verification and [`on_config`](#method.on_config)
210 /// separately.
211 ///
212 /// If called on the already started [`Spirit`][crate::Spirit], it is run right away. If it is
213 /// called on terminated one, it is dropped.
214 ///
215 /// # Examples
216 ///
217 /// TODO
218 fn config_validator<F>(self, f: F) -> Result<Self::Ok, AnyError>
219 where
220 F: FnMut(&Arc<Self::Config>, &Arc<Self::Config>, &Self::Opts) -> Result<Action, AnyError>
221 + Send
222 + 'static;
223
224 /// Adds a callback able to mutate the configuration while being loaded.
225 ///
226 /// Config mutators are run (in order of their registration) before [config
227 /// validators](#method.config_validator) and allow the callback to modify the configuration.
228 /// Note that by the time it is called it is not yet determined if this configuration is
229 /// valid. A config mutator should not use the configuration in any way, only tweak it (and
230 /// possibly warn about having done so), but the tweaked configuration should be used by
231 /// something else down the line.
232 ///
233 /// If run on an already started [`Spirit`][crate::Spirit], this only registers the callback
234 /// but doesn't call it. If run on terminated one, it is dropped.
235 fn config_mutator<F>(self, f: F) -> Self
236 where
237 F: FnMut(&mut Self::Config) + Send + 'static;
238
239 /// Adds a callback for notification about new configurations.
240 ///
241 /// The callback is called once a new configuration is loaded and successfully validated, so it
242 /// can be directly used.
243 ///
244 /// It is run right away on a started [`Spirit`][crate::Spirit], but it is dropped if it was
245 /// already terminated.
246 fn on_config<F>(self, hook: F) -> Self
247 where
248 F: FnMut(&Self::Opts, &Arc<Self::Config>) + Send + 'static;
249
250 /// Adds a callback for reacting to a signal.
251 ///
252 /// The [`Spirit`][crate::Spirit] reacts to some signals itself, in its own service
253 /// thread. However, it is also possible to hook into any signals directly (well, any except
254 /// the ones that are [off limits][signal_hook::consts::FORBIDDEN]).
255 ///
256 /// These are not run inside the real signal handler, but are delayed and run in the service
257 /// thread. Therefore, restrictions about async-signal-safety don't apply to the hook.
258 ///
259 /// It is dropped if called on already terminated spirit.
260 ///
261 /// # Panics
262 ///
263 /// This may panic in case the application runs without the background signal thread. See
264 /// [`SpiritBuilder::build`][crate::SpiritBuilder::build].
265 ///
266 /// TODO: Threads, deadlocks
267 fn on_signal<F>(self, signal: libc::c_int, hook: F) -> Result<Self::Ok, AnyError>
268 where
269 F: FnMut() + Send + 'static;
270
271 /// Adds a callback executed once the [`Spirit`] decides to terminate.
272 ///
273 /// This is called either when someone calls [`terminate`][crate::Spirit::terminate]
274 /// or when a termination signal is received.
275 ///
276 /// Note that there are ways the application may terminate without calling these hooks ‒ for
277 /// example terminating the main thread, or aborting.
278 ///
279 /// If called on already started and *terminated* [`Spirit`], it is run right away.
280 ///
281 /// [`Spirit`]: crate::Spirit.
282 fn on_terminate<F>(self, hook: F) -> Self
283 where
284 F: FnOnce() + Send + 'static;
285
286 /// Add a closure run before the main body.
287 ///
288 /// The [`run`][crate::SpiritBuilder::run] will first execute all closures submitted through
289 /// this method before running the real body. They are run in the order of registration.
290 ///
291 /// The purpose of this is mostly integration with extensions ‒ they often need some last minute
292 /// preparation.
293 ///
294 /// In case of using only [`build`][crate::SpiritBuilder::build], the bodies are composed into
295 /// one object and returned as part of the [`App`][crate::app::App].
296 ///
297 /// If called on an already started [`Spirit`][crate::Spirit], it is run immediately and any
298 /// error returned from it is propagated.
299 ///
300 /// If submitted to the [`Builder`][crate::Builder], the first body to fail terminates the
301 /// processing and further bodies (including the main one) are skipped.
302 ///
303 /// # Examples
304 ///
305 /// ```
306 /// # use spirit::{Empty, Spirit};
307 /// # use spirit::prelude::*;
308 /// Spirit::<Empty, Empty>::new()
309 /// .run_before(|_spirit| {
310 /// println!("Run first");
311 /// Ok(())
312 /// }).run(|_spirit| {
313 /// println!("Run second");
314 /// Ok(())
315 /// });
316 /// ```
317 fn run_before<B>(self, body: B) -> Result<Self::Ok, AnyError>
318 where
319 B: FnOnce(&Arc<Spirit<Self::Opts, Self::Config>>) -> Result<(), AnyError> + Send + 'static;
320
321 /// Wrap the body run by the [`run`][crate::SpiritBuilder::run] into this closure.
322 ///
323 /// It is expected the wrapper executes the inner body as part of itself and propagates any
324 /// returned error.
325 ///
326 /// In case of multiple wrappers, the ones submitted later on are placed inside the sooner
327 /// ones ‒ the first one is the outermost.
328 ///
329 /// In case of using only [`build`][crate::SpiritBuilder::build], all the wrappers composed
330 /// together are returned as part of the result.
331 ///
332 /// # Panics
333 ///
334 /// If called on the already started [`crate::Spirit`], this panics. It is part of the
335 /// interface to make it possible to write extensions that register a body wrapper as part of
336 /// an singleton, but assume the singleton would be plugged in by the time it is already
337 /// started.
338 ///
339 /// # Examples
340 ///
341 /// ```rust
342 /// # use spirit::{Empty, Spirit};
343 /// # use spirit::prelude::*;
344 /// Spirit::<Empty, Empty>::new()
345 /// .run_around(|_spirit, inner| {
346 /// println!("Run first");
347 /// inner()?;
348 /// println!("Run third");
349 /// Ok(())
350 /// }).run(|_spirit| {
351 /// println!("Run second");
352 /// Ok(())
353 /// });
354 /// ```
355 fn run_around<W>(self, wrapper: W) -> Result<Self::Ok, AnyError>
356 where
357 W: FnOnce(&Arc<Spirit<Self::Opts, Self::Config>>, InnerBody) -> Result<(), AnyError>
358 + Send
359 + 'static;
360
361 /// Wrap the hooks inside the provided closure.
362 ///
363 /// This is in a sense similar to the principle of [`run_around`][Extensible::run_around], but
364 /// for all the hooks that are plugged into the spirit and run in the spirit thread. The other
365 /// difference is, these may be run multiple times (eg. there may be multiple enters and leaves
366 /// of the wrappers).
367 ///
368 /// * This is run during the initial configuration load from [`build`][crate::Builder::build].
369 /// * This is run during configuration reloading and signal handling from the background
370 /// thread.
371 /// * If a new one is added to an already configured and running spirit, it'll become effective
372 /// during the next event handled by the background thread.
373 /// * This is *not* run as part of the/around the usual [`run`][crate::Builder::run] (it is run
374 /// as part of the initial configuration loading, but not around the actual application body;
375 /// that one has its own [`run_around`][Extensible::run_around]).
376 /// * This is *not* run as part of user-invoked methods such as
377 /// [`config_reload`][crate::Spirit::config_reload].
378 ///
379 /// This is meant to set up global/thread local context for the hooks in a similar way as
380 /// [`run_around`][Extensible::run_around] is for the application itself. It is expected
381 /// similar setup will go into both in case the context is needed not only for the application,
382 /// but for the callbacks/hooks/pipelines.
383 ///
384 /// Same as with [`run_around`][Extensible::run_around], later submitted wrappers are inserted
385 /// inside the older ones.
386 ///
387 /// # Expected functionality
388 ///
389 /// * The wrapper is a function/closure of the form `FnMut(Box<dyn FnOnce() + '_>)`.
390 /// That is, it is passed an inner closure without parameters or return value. The lifetime
391 /// of the inner closure may be arbitrarily short (it's impossible to store it for later).
392 /// * The wrapper must call the inner closure. Failing to call it will lead to panics during
393 /// runtime.
394 /// * The wrapper must be prepared to survive a panic from the inner body. It may be called
395 /// again even after such panic happened.
396 ///
397 /// # Warning
398 ///
399 /// * Calling this from within a callback might cause a deadlock.
400 /// * These are *not* dropped at [`terminate`][crate::Spirit::terminate], like most other
401 /// callbacks.
402 fn around_hooks<W>(self, wrapper: W) -> Self
403 where
404 W: HookWrapper;
405
406 /// Apply an [`Extension`].
407 ///
408 /// An extension is allowed to register arbitrary amount of callbacks.
409 fn with<E>(self, ext: E) -> Result<Self::Ok, AnyError>
410 where
411 E: Extension<Self::Ok>;
412
413 /// Check if this is the first call with the given type.
414 ///
415 /// Some helpers share common part. This common part makes sense to register just once, so this
416 /// can be used to check that. The first call with given type returns `true`, any future ones
417 /// with the same type return `false`.
418 ///
419 /// The method has no direct effect on the future spirit constructed from the builder and
420 /// works only as a note for future helpers that want to manipulate the builder.
421 ///
422 /// A higher-level interface is the [`with_singleton`](#method.with_singleton) method.
423 ///
424 /// Singletons registered into a [`Builder`][crate::Builder] are then inherited into the
425 /// [`Spirit`][crate::Spirit], therefore they can be registered once during the whole lifetime.
426 ///
427 /// # Examples
428 ///
429 /// ```rust
430 /// use spirit::{Empty, Spirit};
431 /// use spirit::prelude::*;
432 ///
433 /// let mut builder = Spirit::<Empty, Empty>::new();
434 ///
435 /// struct X;
436 /// struct Y;
437 ///
438 /// assert!(builder.singleton::<X>());
439 /// assert!(!builder.singleton::<X>());
440 /// assert!(builder.singleton::<Y>());
441 /// ```
442 fn singleton<T: 'static>(&mut self) -> bool;
443
444 /// Applies the first [`Extension`] of the same type.
445 ///
446 /// This applies the passed extension, but only if an extension with the type same hasn't yet
447 /// been applied (or the [`singleton`](#method.singleton) called manually).
448 ///
449 /// Note that different instances of the same type of an extension can act differently, but are
450 /// still considered the same type. This means the first instance wins. This is considered a
451 /// feature ‒ many other extensions need some environment to run in (like `tokio` runtime). The
452 /// extensions try to apply a default configuration, but the user can apply a specific
453 /// configuration first.
454 fn with_singleton<T>(self, singleton: T) -> Result<Self::Ok, AnyError>
455 where
456 T: Extension<Self::Ok> + 'static;
457
458 /// Keeps a guard object until destruction.
459 ///
460 /// Sometimes, some things (like, a logger that needs flushing, metrics collector handle) need
461 /// a guard that is destroyed at the end of application lifetime. However, the [`run`] body
462 /// may terminate sooner than the application, therefore destroying the guards too soon.
463 ///
464 /// By passing the ownership to [`Spirit`], the guard is destroyed together with the [`Spirit`]
465 /// itself.
466 ///
467 /// Note that you may need to [wait for the background thread] or [autojoin
468 /// it][Extensible::autojoin_bg_thread].
469 ///
470 /// The guards can be only added (there's no way to remove or overwrite them later on).
471 ///
472 /// [`run`]: crate::SpiritBuilder::run
473 /// [`Spirit`]: crate::Spirit
474 /// [wait for the background thread]: crate::Spirit::join_bg_thread
475 fn keep_guard<G: Any + Send>(self, guard: G) -> Self;
476
477 /// Specifies if and when the background thread should be joined automatically.
478 ///
479 /// The default is to terminate and autojoin at the end of the [`run`] method.
480 ///
481 /// [`run`]: crate::SpiritBuilder::run
482 fn autojoin_bg_thread(self, autojoin: Autojoin) -> Self;
483}
484
485impl<C> Extensible for Result<C, AnyError>
486where
487 C: Extensible<Ok = C>,
488{
489 type Opts = C::Opts;
490 type Config = C::Config;
491 type Ok = C;
492 const STARTED: bool = C::STARTED;
493
494 fn before_config<F>(self, cback: F) -> Result<<Self as Extensible>::Ok, AnyError>
495 where
496 F: FnOnce(&Self::Config, &Self::Opts) -> Result<(), AnyError> + Send + 'static,
497 {
498 self.and_then(|c| c.before_config(cback))
499 }
500
501 fn config_mutator<F>(self, f: F) -> Self
502 where
503 F: FnMut(&mut Self::Config) + Send + 'static,
504 {
505 self.map(|c| c.config_mutator(f))
506 }
507
508 fn config_validator<F>(self, f: F) -> Result<<Self as Extensible>::Ok, AnyError>
509 where
510 F: FnMut(&Arc<Self::Config>, &Arc<Self::Config>, &Self::Opts) -> Result<Action, AnyError>
511 + Send
512 + 'static,
513 {
514 self.and_then(|c| c.config_validator(f))
515 }
516
517 fn on_config<F>(self, hook: F) -> Self
518 where
519 F: FnMut(&Self::Opts, &Arc<Self::Config>) + Send + 'static,
520 {
521 self.map(|c| c.on_config(hook))
522 }
523
524 fn on_signal<F>(
525 self,
526 signal: libc::c_int,
527 hook: F,
528 ) -> Result<<Self as Extensible>::Ok, AnyError>
529 where
530 F: FnMut() + Send + 'static,
531 {
532 self.and_then(|c| c.on_signal(signal, hook))
533 }
534
535 fn on_terminate<F>(self, hook: F) -> Self
536 where
537 F: FnOnce() + Send + 'static,
538 {
539 self.map(|c| c.on_terminate(hook))
540 }
541
542 fn run_before<B>(self, body: B) -> Result<<Self as Extensible>::Ok, AnyError>
543 where
544 B: FnOnce(&Arc<Spirit<Self::Opts, Self::Config>>) -> Result<(), AnyError> + Send + 'static,
545 {
546 self.and_then(|c| c.run_before(body))
547 }
548
549 fn run_around<W>(self, wrapper: W) -> Result<<Self as Extensible>::Ok, AnyError>
550 where
551 W: FnOnce(&Arc<Spirit<Self::Opts, Self::Config>>, InnerBody) -> Result<(), AnyError>
552 + Send
553 + 'static,
554 {
555 self.and_then(|c| c.run_around(wrapper))
556 }
557
558 fn around_hooks<W>(self, wrapper: W) -> Self
559 where
560 W: HookWrapper,
561 {
562 self.map(|c| c.around_hooks(wrapper))
563 }
564
565 fn with<E>(self, ext: E) -> Result<<Self as Extensible>::Ok, AnyError>
566 where
567 E: Extension<<Self as Extensible>::Ok>,
568 {
569 self.and_then(|c| c.with(ext))
570 }
571
572 fn singleton<T: 'static>(&mut self) -> bool {
573 // If we are errored out, this doesn't really matter, but usually false means less work to
574 // do.
575 self.as_mut()
576 .map(Extensible::singleton::<T>)
577 .unwrap_or_default()
578 }
579
580 fn with_singleton<T>(self, singleton: T) -> Result<<Self as Extensible>::Ok, AnyError>
581 where
582 T: Extension<<Self as Extensible>::Ok> + 'static,
583 {
584 self.and_then(|c| c.with_singleton(singleton))
585 }
586
587 fn keep_guard<G: Any + Send>(self, guard: G) -> Self {
588 self.map(|s| s.keep_guard(guard))
589 }
590
591 fn autojoin_bg_thread(self, autojoin: Autojoin) -> Self {
592 self.map(|me| me.autojoin_bg_thread(autojoin))
593 }
594}
595
596/// The basic extension trait.
597///
598/// It allows being plugged into a [`Builder`][crate::Builder] or [`Spirit`][crate::Spirit] and
599/// modifying it in an arbitrary way.
600///
601/// It is more common to apply the helper by the
602/// [`with`][Extensible::with] or [`with_singleton`][Extensible::with_singleton] method than
603/// directly.
604///
605/// There's an implementation of `Extension` for `FnOnce(Extensible) -> Result<Extensible, AnyError>`,
606/// so extensions can be either custom types or just closures (which are often more convenient than
607/// defining an empty type and the implementation).
608///
609/// It is better to define the extension in a generic way (eg. accepting any type that is
610/// [`Extensible`]) instead of eg. a [`Builder`][crate::Builder] directly. Note that sometimes it
611/// is needed to restrict the acceptable [`Extensible`]s to the base ones, with `Ok = E`, like in
612/// the example below. They'll still be possible to apply to `Result`s.
613///
614/// # Examples
615///
616/// ```rust
617/// use spirit::{AnyError ,Empty, Spirit};
618/// use spirit::extension::{Extension, Extensible};
619/// use spirit::prelude::*;
620///
621/// struct CfgPrint;
622///
623/// impl<E: Extensible<Ok = E>> Extension<E> for CfgPrint {
624/// fn apply(self, ext: E) -> Result<E, AnyError> {
625/// Ok(ext.on_config(|_opts, _config| println!("Config changed")))
626/// }
627/// }
628///
629/// Spirit::<Empty, Empty>::new()
630/// .with(CfgPrint)
631/// .run(|_spirit| {
632/// println!("Running...");
633/// Ok(())
634/// })
635/// ```
636///
637/// ```rust
638/// use spirit::{Empty, Extensible, Spirit};
639/// use spirit::prelude::*;
640///
641/// fn cfg_print<E: Extensible<Ok = E>>(ext: E) -> E {
642/// ext.on_config(|_opts, _config| println!("Config changed"))
643/// }
644///
645/// Spirit::<Empty, Empty>::new()
646/// .with(cfg_print)
647/// .run(|_spirit| {
648/// println!("Running...");
649/// Ok(())
650/// })
651/// ```
652pub trait Extension<B> {
653 /// Perform the transformation on the given extensible.
654 ///
655 /// And yes, it is possible to do multiple primitive transformations inside one extension (this
656 /// is what makes extensions useful for 3rd party crates, they can integrate with just one call
657 /// of [`with`][Extensible::with]).
658 fn apply(self, builder: B) -> Result<B, AnyError>;
659}
660
661impl<B, F, R> Extension<B> for F
662where
663 F: FnOnce(B) -> R,
664 R: IntoResult<B>,
665{
666 fn apply(self, builder: B) -> Result<B, AnyError> {
667 self(builder).into_result()
668 }
669}
670
671/// An extension for one-time initial configuration.
672///
673/// Sometimes, some configuration values can't be reasonably updated at runtime (libraries don't
674/// support reconfiguration, there's no time to implement that, ...). This callback tries to
675/// improve the situation around these configurations.
676///
677/// The `extractor` extracts a fragment of configuration every time a configuration is loaded. The
678/// first time this happens, `init` is called with this extracted configuration. Upon any future
679/// configuration reloads, a warning is issued (with the given `name`) if the configuration
680/// contains a different value than the one it was originally initialized (and is silent if it is
681/// the same).
682///
683/// # See also
684///
685/// * [`immutable_cfg`]
686///
687/// # Examples
688///
689/// ```
690/// use serde::Deserialize;
691/// use spirit::{Empty, Spirit};
692/// use spirit::prelude::*;
693/// use spirit::extension;
694///
695/// #[derive(Clone, Debug, Default, Deserialize)]
696/// struct Cfg {
697/// #[serde(default)]
698/// msg: String,
699/// }
700///
701/// impl Cfg {
702/// fn msg(&self) -> &String {
703/// &self.msg
704/// }
705/// }
706///
707/// fn print_msg(msg: &String) {
708/// println!("{}", msg);
709/// }
710///
711/// fn main() {
712/// Spirit::<Empty, Cfg>::new()
713/// // The first version of `msg` is printed at the initial configuration load. If however
714/// // the configuration changes into some other message, a warning is printed (because
715/// // there's no way to modify the already printed message
716/// .with(extension::immutable_cfg_init(Cfg::msg, print_msg, "message"))
717/// .run(|_| Ok(()));
718/// }
719/// ```
720pub fn immutable_cfg_init<Ext, R, E, F, N>(extractor: E, init: F, name: N) -> impl Extension<Ext>
721where
722 Ext: Extensible,
723 E: for<'a> Fn(&'a Ext::Config) -> &R + Send + 'static,
724 F: FnOnce(&R) + Send + 'static,
725 R: Clone + PartialEq + Send + 'static,
726 N: Display + Send + 'static,
727{
728 let mut first = None;
729 let mut init = Some(init);
730 let on_cfg = move |_o: &Ext::Opts, c: &Arc<Ext::Config>| {
731 let extracted = extractor(c);
732 if first.is_none() {
733 first = Some(extracted.clone());
734 (init.take().expect("Init called multiple times"))(extracted);
735 } else if first.as_ref() != Some(extracted) {
736 warn!("Configuration {} can't be changed at runtime", name);
737 }
738 };
739 |ext: Ext| ext.on_config(on_cfg)
740}
741
742/// An extension to warn about changes to configuration that can't be updated at runtime.
743///
744/// This is similar to [`immutable_cfg_init`] except that there's no callback called at the first
745/// load.
746///
747/// # Examples
748///
749/// ```
750/// use serde::Deserialize;
751/// use spirit::{Empty, Spirit};
752/// use spirit::prelude::*;
753/// use spirit::extension;
754///
755/// #[derive(Clone, Debug, Default, Deserialize)]
756/// struct Cfg {
757/// #[serde(default)]
758/// msg: String,
759/// }
760///
761/// impl Cfg {
762/// fn msg(&self) -> &String {
763/// &self.msg
764/// }
765/// }
766///
767/// fn main() {
768/// Spirit::<Empty, Cfg>::new()
769/// // This prints a warning if the message is ever changed during runtime ‒ we can't take
770/// // it back and change it after it got printed in the body.
771/// .with(extension::immutable_cfg(Cfg::msg, "message"))
772/// .run(|spirit| {
773/// println!("{}", spirit.config().msg);
774/// Ok(())
775/// });
776/// }
777/// ```
778pub fn immutable_cfg<Ext, R, E, N>(extractor: E, name: N) -> impl Extension<Ext>
779where
780 Ext: Extensible,
781 E: for<'a> Fn(&'a Ext::Config) -> &R + Send + 'static,
782 R: Clone + PartialEq + Send + 'static,
783 N: Display + Send + 'static,
784{
785 immutable_cfg_init(extractor, |_| (), name)
786}