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}