spirit 0.4.17

Helper to create well behaved daemons with runtime-reconfiguration support
Documentation
//! A collection of [`Driver`]s for use by [`Fragment`]s.
//!
//! This module contains the [`Driver`] trait, several implementations of that trait for general
//! use and some support types around them.
//!
//! [`Driver`]: crate::fragment::driver::Driver

use std::collections::HashMap;
use std::fmt::Debug;
use std::iter;
use std::marker::PhantomData;
use std::mem;

use either::Either;
use log::{trace, warn};

use super::{Fragment, Transformation};
use crate::AnyError;

// XXX: Logging and tests

/// Generator of IDs for the [`Driver`].
///
/// The [`Driver`] needs to identify the resources it created, so it can later on request their
/// removal. The [`CacheId`] is used for that. That is an opaque type, so the [`Driver`] can either
/// create a default (non-unique) one or use this generator to create unique IDs.
///
/// Note that a generator will never produce two equal IDs, but two different generators can both
/// produce the same one. The [`Driver`] must take care not to use IDs from two different
/// generators.
///
/// The IDs are produced using the [`Iterator`] trait.
///
/// The generator implements a very small set of traits. In particular, it isn't [`Clone`]. This is
/// on purpose, because cloning the generators could lead to surprising behaviours.
#[derive(Debug)]
pub struct IdGen(u128);

impl IdGen {
    fn new() -> Self {
        IdGen(1)
    }
}

impl Default for IdGen {
    fn default() -> Self {
        Self::new()
    }
}

impl Iterator for IdGen {
    type Item = CacheId;
    fn next(&mut self) -> Option<CacheId> {
        let id = self.0;
        self.0 = self
            .0
            .checked_add(1)
            .expect("WTF? Run out of 128bit cache IDs!?");
        Some(CacheId(id))
    }
}

/// ID used by the [`Driver`] to identify specific instance of the resource.
///
/// Only one ID can be created directly ([`CacheId::dummy`]). It can be used if the driver never
/// creates more than one instance of the resource at a time.
///
/// If unique IDs are needed, the [`Driver`] needs to keep and use an [`IdGen`] to generate them.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CacheId(u128);

impl CacheId {
    /// A dummy cache ID.
    pub fn dummy() -> Self {
        CacheId(0)
    }
}

/// One instruction from the [`Driver`].
///
/// The [`Driver`] issues instructions to the rest of the [`Pipeline`][super::pipeline::Pipeline].
/// They either ask it to install a new resource or to remove some previous resources.
pub enum Instruction<Resource> {
    /// Instruction for the [`Pipeline`][super::pipeline::Pipeline] to remove all active resources
    /// produced by this driver.
    ///
    /// This is legal to use even in cases when the set of active resources is empty (this drops
    /// nothing) or if the resources are not uniquely separately identifiable.
    DropAll,

    /// Instruction for the [`Pipeline`] to remove a specific resource.
    ///
    /// It is a contract violation if this ID doesn't correspond to exactly one active resource and
    /// the [`Pipeline`] may panic or misbehave under such circumstances. Specifically, it is not
    /// allowed to refer to resource that is no longer active (was dropped previously), never
    /// existed or to use a non-unique ID here.
    ///
    /// [`Pipeline`]: super::pipeline::Pipeline
    DropSpecific(CacheId),

    /// Installs another resource.
    ///
    /// The resource is identified with an `id`, so it can be referenced in the future. It *is*
    /// allowed to reuse a no longer used ID. It is *not* allowed to produce non-unique IDs for
    /// active resources.
    Install {
        /// The ID this resource will be identified as.
        id: CacheId,

        /// The resource to install.
        resource: Resource,
    },
}

impl<Resource> Instruction<Resource> {
    fn replace(resource: Resource) -> Vec<Self> {
        vec![
            Instruction::DropAll,
            Instruction::Install {
                id: CacheId::dummy(),
                resource,
            },
        ]
    }
}

/// The [`Driver`] of a [`Pipeline`].
///
/// The driver is the part of the [`Pipeline`] that decides when a cached/old version of a resource
/// is good enough to keep or when a new one needs to be created and the old one removed, and if
/// it should be recreated from scratch or the seed can be reused. It also can split the
/// [`Fragment`] into smaller [`Fragment`]s and drive the resources separately.
///
/// Any kind of caching (of either the old [`Fragment`], the [`Seed`][Fragment::Seed], the
/// [`Resource`][Fragment::Resource] or of anything else) is fully in the control of the [`Driver`]
/// itself.
///
/// Each time the configuration is reloaded, the [`Driver`] is fed with the new version of the
/// fragment. The driver can either return error (or multiple ones) or [`Instruction`]s how to
/// transition from the old state to the new one.
///
/// The [`Pipeline`] then either follows these [`Instruction`]s and calls [`confirm`], or drops the
/// instructions (for example if some other [`Pipeline`] failed) and calls [`abort`]. Exactly one
/// of these will be called after call of [`instructions`][Driver::instructions].
///
/// If [`abort`] is called, the [`Driver`] shall act in the same way as if the last
/// [`instructions`] has never been called ‒ eg. it should return to the *old* state and keep
/// caching the old data. If [`confirm`] is called, it can discard the old state and keep just the
/// new one.
///
/// The `F` generic parameter is the [`Fragment`] this driver will be provided. In contrast, the
/// [`SubFragment`] is the smaller fragment into which the [`Driver`] cuts the
/// original `F`. It may or may not be the same type.
///
/// If it cuts `F` into smaller ones, one resource for each [`SubFragment`] is to be created and
/// transformed.
///
/// The whole anatomy of how [`Pipeline`]s and [`Driver`]s work is described in the
/// [`fragment`][super] module.
///
/// [`Pipeline`]: super::pipeline::Pipeline
/// [`SubFragment`]: Driver::SubFragment
/// [`instructions`]: Driver::instructions
/// [`confirm`]: Driver::confirm
/// [`abort`]: Driver::abort
pub trait Driver<F: Fragment> {
    /// The smaller [`Fragment`] the driver cuts `F` into.
    ///
    /// This may be the same as `F` or it may be something smaller (eg. it may be the elements of
    /// `Vec<T>`.
    type SubFragment: Fragment;

    /// Issues the instructions how to transition to the new fragment.
    ///
    /// The driver needs to issue some valid sequence of instructions (see the [`Instruction`] for
    /// details what is valid) to make sure the [`Resource`] for the new [`Fragment`] is active.
    ///
    /// Note that the instructions are not automatically followed. The call of [`instructions`]
    /// will be followed by either a call to [`confirm`] or [`abort`], depending on if the whole
    /// new configuration is accepted or not. The [`Driver`] needs to take this into account when
    /// caching.
    ///
    /// Part of creation of the [`Resource`] is applying the [`Transformation`].
    ///
    /// In case there are no changes needed, empty sequence of instructions may be legally
    /// returned. The [`abort`] or [`confirm`] is called even in such case.
    ///
    /// If it is not possible to create the resource or resources (the driver *is* allowed to
    /// produce multiple), an error or errors shall be returned instead. In such case the internal
    /// cache must stay the same.
    ///
    /// [`Resource`]: Fragment::Resource
    /// [`instructions`]: Driver::instructions
    /// [`confirm`]: Driver::confirm
    /// [`abort`]: Driver::abort
    fn instructions<T, I>(
        &mut self,
        fragment: &F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<<Self::SubFragment as Fragment>::Resource, I, Self::SubFragment>;

    /// Call to this method informs the [`Driver`] that the instructions returned by the last call
    /// to [`instructions`] were followed and the changes have taken place.
    ///
    /// Therefore, the [`Driver`] should preserve the new state in its cache (if it does any
    /// caching).
    ///
    /// Alternatively, the [`abort`] may be called instead to inform of *not* applying the
    /// instructions.
    ///
    /// [`instructions`]: Driver::instructions
    /// [`abort`]: Driver::abort
    fn confirm(&mut self, name: &'static str);

    /// Call to this method informs the [`Driver`] that the instructions returned by the last call
    /// to [`instructions`] were *not* followed and were dropped.
    ///
    /// Therefore, the [`Driver`] should return its caches to the state before the call to
    /// [`instructions`] (if it does any caching at all).
    ///
    /// [`instructions`]: Driver::instructions
    fn abort(&mut self, name: &'static str);

    /// Informs if there's a chance the new fragment will use something in the [`Driver`]'s cache
    /// if applied.
    ///
    /// The driver shall return `true` if by using this instance of [`Driver`] (with the current
    /// state of caches) would somehow use its cache to create the resource from the provided
    /// `fragment` ‒ either by reusing it completely or by using the [`Seed`].
    ///
    /// This is used by higher-level drivers (for example the [`SeqDriver`]) to decide which slave
    /// driver should take care of which their [`SubFragment`].
    ///
    /// [`Seed`]: Fragment::Seed
    /// [`SubFragment`]: Driver::SubFragment
    fn maybe_cached(&self, frament: &F, name: &'static str) -> bool;
}

/// A trivial [`Driver`] that does no caching at all.
///
/// Every time the [`Driver`] is called, the resource is created anew and the old one replaced.
#[derive(Clone, Copy, Debug, Default)]
pub struct Trivial;

impl<F: Fragment> Driver<F> for Trivial {
    type SubFragment = F;
    fn instructions<T, I>(
        &mut self,
        fragment: &F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<F::Resource, I, F>,
    {
        trace!(
            "Creating resource {}, generating a replace instruction for any possible previous",
            name,
        );
        let resource = fragment
            .create(name)
            .and_then(|r| transform.transform(r, fragment, name))
            .map_err(|e| vec![e])?;
        Ok(Instruction::replace(resource))
    }
    fn confirm(&mut self, _name: &'static str) {}
    fn abort(&mut self, _name: &'static str) {}
    fn maybe_cached(&self, _: &F, _name: &'static str) -> bool {
        false
    }
}

/// A result of the [`Comparable`] trait.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Comparison {
    /// The compared [`Fragment`]s don't look similar at all.
    ///
    /// There's no chance of taking advantage of caching when creating the new [`Resource`] ‒ it
    /// would have to be created from scratch (eg. going through both stages of creation).
    ///
    /// [`Resource`]: Fragment::Resource
    Dissimilar,

    /// The compared [`Fragment`]s are somewhat similar, but not the same.
    ///
    /// It will be possible to use the same [`Seed`], but the second stage of resource creation
    /// needs to be done again.
    ///
    /// [`Seed`]: Fragment::Seed
    Similar,

    /// The [`Fragment`]s are exactly the same.
    ///
    /// The resource doesn't have to be changed, the old instance is good.
    Same,
}

/// [`Fragment`]s that can be compared for similarity.
///
/// This is used by the [`CacheSimilar`] [`Driver`].
pub trait Comparable<RHS = Self> {
    /// Compares two fragments.
    fn compare(&self, other: &RHS) -> Comparison;
}

#[derive(Debug)]
enum Proposition<F: Fragment + ToOwned> {
    Nothing,
    ReplaceFragment(F::Owned),
    ReplaceBoth { fragment: F::Owned, seed: F::Seed },
}

impl<F: Fragment + ToOwned> Proposition<F> {
    fn active(&self) -> bool {
        !matches!(self, Proposition::Nothing)
    }
}

/// A [`Driver`] that caches both created [`Resource`]s and their [`Seed`]s to create as little as
/// possible.
///
/// It uses the [`Comparable`] trait to decide if it needs to create the [`Resource`] complete from
/// scratch, if it can reuse the old [`Seed`] or if it can even keep the old instance. This is a
/// good driver for cases where the [`Seed`] is some kind of unique resource and changing the
/// resource by creating a completely new instance while the old one existed wouldn't work. An
/// example of this is the bound ports on listening sockets ‒ while we might want to attach
/// different configuration to the same socket, opening a new socket with the same port would not
/// work. Therefore, the socket is somewhere within the [`Seed`] and it is reused if the port
/// doesn't change.
///
/// [`Resource`]: Fragment::Resource
/// [`Seed`]: Fragment::Seed
#[derive(Debug)]
pub struct CacheSimilar<F: Fragment + ToOwned> {
    previous: Option<F::Owned>,
    seed: Option<F::Seed>,
    proposition: Proposition<F>,
}

impl<F: Fragment + ToOwned> Default for CacheSimilar<F> {
    fn default() -> Self {
        CacheSimilar {
            previous: None,
            seed: None,
            proposition: Proposition::Nothing,
        }
    }
}

impl<F> CacheSimilar<F>
where
    F: Debug + Fragment + ToOwned + Comparable<<F as ToOwned>::Owned>,
{
    fn compare(&self, fragment: &F) -> Comparison {
        self.previous
            .as_ref()
            .map(|prev| fragment.compare(prev))
            .unwrap_or(Comparison::Dissimilar)
    }
}

impl<F> Driver<F> for CacheSimilar<F>
where
    F: Debug + Fragment + ToOwned + Comparable<<F as ToOwned>::Owned>,
{
    type SubFragment = F;
    fn instructions<T, I>(
        &mut self,
        fragment: &F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<F::Resource, I, F>,
    {
        assert!(!self.proposition.active(), "Unclosed transaction");

        match self.compare(fragment) {
            Comparison::Dissimilar => {
                trace!(
                    "Completely new config {:?} for {}, recreating from scratch",
                    fragment,
                    name
                );
                let mut new_seed = fragment.make_seed(name).map_err(|e| vec![e])?;
                let resource = fragment
                    .make_resource(&mut new_seed, name)
                    .and_then(|r| transform.transform(r, fragment, name))
                    .map_err(|e| vec![e])?;
                self.proposition = Proposition::ReplaceBoth {
                    seed: new_seed,
                    fragment: fragment.to_owned(),
                };

                Ok(Instruction::replace(resource))
            }
            Comparison::Similar => {
                trace!(
                    "A similar config {:?} for {}, recreating from previous seed",
                    fragment,
                    name
                );
                let resource = fragment
                    .make_resource(self.seed.as_mut().expect("Missing previous seed"), name)
                    .and_then(|r| transform.transform(r, fragment, name))
                    .map_err(|e| vec![e])?;
                self.proposition = Proposition::ReplaceFragment(fragment.to_owned());

                Ok(Instruction::replace(resource))
            }
            Comparison::Same => {
                trace!(
                    "The {} stays the same on {:?}, keeping previous resource",
                    name,
                    fragment
                );
                Ok(Vec::new())
            }
        }
    }
    fn abort(&mut self, name: &'static str) {
        trace!("Aborting {}", name);
        self.proposition = Proposition::Nothing;
    }
    fn confirm(&mut self, name: &'static str) {
        trace!("Confirming {}", name);
        let mut proposition = Proposition::Nothing;
        mem::swap(&mut proposition, &mut self.proposition);
        match proposition {
            Proposition::Nothing => (),
            Proposition::ReplaceFragment(f) => self.previous = Some(f),
            Proposition::ReplaceBoth { fragment, seed } => {
                self.seed = Some(seed);
                self.previous = Some(fragment);
            }
        }
    }
    fn maybe_cached(&self, fragment: &F, _name: &'static str) -> bool {
        self.compare(fragment) != Comparison::Dissimilar
    }
}

/// A [`Driver`] that caches the [`Resource`] if the [`Fragment`] doesn't change at all.
///
/// Most of the time, the configuration is the same or almost the same ‒ so many [`Resource`]s
/// don't need to be changed. This driver keeps the old instance of the [`Fragment`] and if the new
/// one compares equal, it does nothing (eg. keeps the old instance of the [`Resource`]).
///
/// [`Resource`]: Fragment::Resource
#[derive(Debug)]
pub struct CacheEq<Fragment: ToOwned> {
    previous: Option<Fragment::Owned>,
    proposition: Option<Fragment::Owned>,
}

impl<F: ToOwned> Default for CacheEq<F> {
    fn default() -> Self {
        CacheEq {
            previous: None,
            proposition: None,
        }
    }
}

impl<F> Driver<F> for CacheEq<F>
where
    F: Debug + Fragment + ToOwned + PartialEq<<F as ToOwned>::Owned>,
{
    type SubFragment = F;
    fn instructions<T, I>(
        &mut self,
        fragment: &F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<F::Resource, I, F>,
    {
        assert!(self.proposition.is_none(), "Unclosed transaction");
        // maybe_cached means *is* cached for us
        if self.maybe_cached(fragment, name) {
            trace!(
                "The {} stays the same on {:?}, keeping previous",
                name,
                fragment
            );
            Ok(Vec::new())
        } else {
            trace!("New config {:?} for {}, recreating", fragment, name);
            self.proposition = Some(fragment.to_owned());
            // We just delegate to the trivial driver in such case
            // (we know it has no state at all, so we can simply create a new one).
            <Trivial as Driver<F>>::instructions(&mut Trivial, fragment, transform, name)
        }
    }
    fn abort(&mut self, name: &'static str) {
        trace!("Aborting {}", name);
        // Note: we don't check if anything is in here, because in case these were the same we
        // didn't fill in the proposition.
        self.proposition.take();
    }
    fn confirm(&mut self, name: &'static str) {
        trace!("Confirming {}", name);
        if let Some(proposition) = self.proposition.take() {
            self.previous = Some(proposition);
        }
    }
    fn maybe_cached(&self, fragment: &F, _name: &'static str) -> bool {
        // Option doesn't implement parametrized PartialEq :-(
        if let Some(prev) = self.previous.as_ref() {
            fragment == prev
        } else {
            false
        }
    }
}

/// An object to map [`Instruction`]s from multiple drivers into instruction sequences not
/// containing duplicate IDs.
///
/// If one [`Driver`] uses services of some other slave drivers, it is up to the master to make
/// sure instructions gathered from the slaves don't collide on IDs. This helps in that regard.
///
/// It is expected to be used as:
/// * One mapping per slave driver, but sharing the [`IdGen`].
/// * All instructions from the slave are [`translate`]d through the mapping.
/// * The mapping is only stored and cached if [`confirm`] is called.
///
/// TODO Example
///
/// [`translate`]: IdMapping::translate
/// [`confirm`]: Driver::confirm
#[derive(Clone, Debug, Default)]
pub struct IdMapping {
    mapping: HashMap<CacheId, CacheId>,
}

impl IdMapping {
    /// Assigns new IDs so they are unique within the `IdMapping`s sharing the same `id_gen`.
    ///
    /// This changes the IDs so they are unique. It also changes the IDs used in the drop
    /// instructions to reflect the original changes and [`DropAll`][Instruction::DropAll] is
    /// expanded to separate instructions (because in the bigger context of the master, all might
    /// mean resources from other slave drivers).
    pub fn translate<'a, R, I>(
        &'a mut self,
        id_gen: &'a mut IdGen,
        instructions: I,
    ) -> impl Iterator<Item = Instruction<R>> + 'a
    where
        R: 'a,
        I: IntoIterator<Item = Instruction<R>> + 'a,
    {
        instructions
            .into_iter()
            // Borrow checker notes:
            // We need to move the self and id_gen into the closure. Otherwise, it creates
            // &mut &mut IdGen monster behind the scenes, however, the outer &mut has a short
            // lifetime because it points to the function's parameter.
            //
            // The mem::swap with the HashMap below is also because of borrow checker. The drain we
            // would like to use instead would have to eat the `&mut self` (or borrow it, but see
            // the same problem above). We *know* that we won't call this again until the drain
            // iterator is wholly consumed by flat_map, but the borrow checker doesn't. So this
            // trick instead.
            .flat_map(move |i| match i {
                Instruction::DropAll => {
                    let mut mapping = HashMap::new();
                    mem::swap(&mut mapping, &mut self.mapping);
                    Either::Left(
                        mapping
                            .into_iter()
                            .map(|(_, outer_id)| Instruction::DropSpecific(outer_id)),
                    )
                }
                Instruction::DropSpecific(id) => {
                    let id = self
                        .mapping
                        .remove(&id)
                        .expect("Inconsistent use of cache: missing ID to remove");
                    Either::Right(iter::once(Instruction::DropSpecific(id)))
                }
                Instruction::Install { id, resource } => {
                    let new_id = id_gen.next().expect("Run out of cache IDs? Impossible");
                    assert!(
                        self.mapping.insert(id, new_id).is_none(),
                        "Duplicate ID created"
                    );
                    Either::Right(iter::once(Instruction::Install {
                        id: new_id,
                        resource,
                    }))
                }
            })
    }

    /// Lists the IDs that are active in the target (translated).
    ///
    /// This can be used to, for example, generate instructions to completely „wipe“ the
    /// corresponding driver.
    pub fn active_target_ids(&self) -> impl Iterator<Item = &CacheId> {
        self.mapping.values()
    }
}

#[derive(Debug, Default)]
struct ItemDriver<Driver> {
    driver: Driver,
    id_mapping: IdMapping,
    proposed_mapping: Option<IdMapping>,
    used: bool,
    new: bool,
}

/// A plumbing [`Driver`] for sequences of fragments.
///
/// This driver is used to go from single [`Fragment`] to a sequence ‒ this is driver for things
/// like `Vec<F>` or `HashSet<F>`.
#[derive(Debug)]
pub struct SeqDriver<Item, SlaveDriver> {
    id_gen: IdGen,
    sub_drivers: Vec<ItemDriver<SlaveDriver>>,
    transaction_open: bool,
    // TODO: Can we actually get rid of this?
    _item: PhantomData<fn(&Item)>,
}

// The derived Default balks on Item: !Default, but we *don't* need that
impl<Item, SlaveDriver> Default for SeqDriver<Item, SlaveDriver> {
    fn default() -> Self {
        Self {
            id_gen: IdGen::new(),
            sub_drivers: Vec::new(),
            transaction_open: false,
            _item: PhantomData,
        }
    }
}

// TODO: This might use some nice tests.
impl<F, I, SlaveDriver> Driver<F> for SeqDriver<I, SlaveDriver>
where
    F: Fragment,
    I: Fragment,
    for<'a> &'a F: IntoIterator<Item = &'a I>,
    SlaveDriver: Driver<I> + Default,
{
    type SubFragment = SlaveDriver::SubFragment;
    fn instructions<T, Ins>(
        &mut self,
        fragment: &F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<<Self::SubFragment as Fragment>::Resource, Ins, Self::SubFragment>,
    {
        assert!(!self.transaction_open);
        trace!("Updating sequence {}", name);
        self.transaction_open = true;
        let mut instructions = Vec::new();
        let mut errors = Vec::new();

        for sub in fragment {
            let existing = self
                .sub_drivers
                .iter_mut()
                .find(|d| !d.used && d.driver.maybe_cached(sub, name));
            // unwrap_or_else angers the borrow checker here
            let slot = if let Some(existing) = existing {
                trace!("Found existing version of instance in {}", name);
                existing
            } else {
                trace!(
                    "Previous version of instance in {} not found, creating a new one",
                    name
                );
                self.sub_drivers.push(ItemDriver::default());
                let slot = self.sub_drivers.last_mut().unwrap();
                slot.new = true;
                slot
            };

            slot.used = true;
            match slot.driver.instructions(sub, transform, name) {
                Ok(new_instructions) => {
                    let mapping = if slot.new {
                        &mut slot.id_mapping
                    } else {
                        slot.proposed_mapping = Some(slot.id_mapping.clone());
                        slot.proposed_mapping.as_mut().unwrap()
                    };
                    instructions.extend(mapping.translate(&mut self.id_gen, new_instructions));
                }
                Err(errs) => errors.extend(errs),
            }
        }

        for slot in &self.sub_drivers {
            if !slot.used {
                instructions.extend(
                    slot.id_mapping
                        .active_target_ids()
                        .cloned()
                        .map(Instruction::DropSpecific),
                );
            }
        }

        if errors.is_empty() {
            Ok(instructions)
        } else {
            self.abort(name);
            Err(errors)
        }
    }
    fn confirm(&mut self, name: &'static str) {
        trace!("Confirming the whole sequence {}", name);
        assert!(self.transaction_open);
        self.transaction_open = false;
        // Get rid of the unused ones
        self.sub_drivers.retain(|s| s.used);
        // Confirm all the used ones, accept proposed mappings and mark everything as old for next
        // round.
        for sub in &mut self.sub_drivers {
            sub.driver.confirm(name);
            if let Some(mapping) = sub.proposed_mapping.take() {
                sub.id_mapping = mapping;
            }
            sub.new = false;
            sub.used = false;
        }
    }
    fn abort(&mut self, name: &'static str) {
        trace!("Aborting the whole sequence of {}", name);
        assert!(self.transaction_open);
        self.transaction_open = false;
        // Get rid of the new ones completely
        self.sub_drivers.retain(|s| !s.new);
        // Abort anything we touched before
        for sub in &mut self.sub_drivers {
            if sub.used {
                sub.driver.abort(name);
                sub.proposed_mapping.take();
                sub.used = false;
            }
            assert!(
                sub.proposed_mapping.is_none(),
                "Proposed mapping for something not used"
            );
        }
    }
    fn maybe_cached(&self, fragment: &F, name: &'static str) -> bool {
        fragment.into_iter().any(|s| {
            self.sub_drivers
                .iter()
                .any(|slave| slave.driver.maybe_cached(s, name))
        })
    }
}

/// A [`Driver`] for a single-shot initialization.
///
/// This driver creates the resource only the first time it is called. On an attempt to call it
/// again it warns if the value of the fragment is different.
pub struct OnceDriver<F: ToOwned> {
    loaded: Option<F::Owned>,
    initial: bool,
}

impl<F> Default for OnceDriver<F>
where
    F: ToOwned,
{
    fn default() -> Self {
        OnceDriver {
            loaded: None,
            initial: true,
        }
    }
}

impl<F> Driver<F> for OnceDriver<F>
where
    F: Fragment + PartialEq<<F as ToOwned>::Owned> + ToOwned + 'static,
{
    type SubFragment = F;
    fn instructions<T, I>(
        &mut self,
        fragment: &F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<<Self::SubFragment as Fragment>::Resource, I, Self::SubFragment>,
    {
        if let Some(loaded) = self.loaded.as_ref() {
            if fragment == loaded {
                warn!(
                    "{} changed in configuration, can't change at runtime, keeping previous",
                    name,
                );
            }
            Ok(Vec::new())
        } else {
            assert!(self.initial);
            trace!("Building {} for the first time", name);
            self.loaded = Some(fragment.to_owned());
            Trivial.instructions(fragment, transform, name)
        }
    }
    fn confirm(&mut self, _name: &'static str) {
        assert!(self.loaded.is_some(), "Confirm called before instructions");
        self.initial = false;
    }
    fn abort(&mut self, _name: &'static str) {
        if self.initial {
            // Keep initial to true in such case
            assert!(
                self.loaded.take().is_some(),
                "Abort called before instructions"
            );
        }
        // else - we still keep the thing that was set, because this must have been from previous
        // round
    }
    fn maybe_cached(&self, fragment: &F, _name: &'static str) -> bool {
        self.loaded
            .as_ref()
            .map(|l| fragment == l)
            .unwrap_or_default()
    }
}

/// A driver that initializes just once, but unlike [`OnceDriver`] is silent about changed
/// configurations.
///
/// This may be used for early but incomplete initialization of some global resource. It would then
/// be paired with a pipeline doing a full load later in the chain (one such example might be
/// initializing logging but without the background thread before daemonization, and doing full
/// logging with background thread afterwards).
///
/// See the [example in the daemonization chapter][crate::guide::daemonization].
pub struct SilentOnceDriver {
    attempted: bool,
    initial: bool,
}

impl Default for SilentOnceDriver {
    fn default() -> Self {
        Self {
            attempted: false,
            initial: true,
        }
    }
}

impl<F> Driver<F> for SilentOnceDriver
where
    F: Fragment,
{
    type SubFragment = F;
    fn instructions<T, I>(
        &mut self,
        fragment: &F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<<Self::SubFragment as Fragment>::Resource, I, Self::SubFragment>,
    {
        if self.initial {
            trace!("Building {} for the first time", name);
            assert!(!self.attempted);
            self.attempted = true;
            Trivial.instructions(fragment, transform, name)
        } else {
            Ok(Vec::new())
        }
    }
    fn confirm(&mut self, _name: &'static str) {
        assert!(self.attempted, "Confirm called before instructions");
        self.initial = false;
    }
    fn abort(&mut self, _name: &'static str) {
        // we still keep the thing that was set, because this must have been from previous
        // round
    }
    fn maybe_cached(&self, _: &F, _name: &'static str) -> bool {
        false
    }
}

/// An adaptor [`Driver`] for references.
///
/// This is used behind the scenes to wrap a driver for `F` to create a driver for `&F`.
#[derive(Debug, Default)]
pub struct RefDriver<Inner>(Inner);

impl<Inner> RefDriver<Inner> {
    /// Creates the driver.
    ///
    /// It is available to support also drivers that are provided and created by the user. Usually,
    /// the `Default` implementation is used within the [`Fragment`].
    pub fn new(inner: Inner) -> Self {
        RefDriver(inner)
    }
}

impl<'a, F: Fragment, Inner: Driver<F>> Driver<&'a F> for RefDriver<Inner> {
    type SubFragment = Inner::SubFragment;
    fn instructions<T, I>(
        &mut self,
        fragment: &&F,
        transform: &mut T,
        name: &'static str,
    ) -> Result<Vec<Instruction<T::OutputResource>>, Vec<AnyError>>
    where
        T: Transformation<<Self::SubFragment as Fragment>::Resource, I, Self::SubFragment>,
    {
        self.0.instructions(*fragment, transform, name)
    }
    fn confirm(&mut self, name: &'static str) {
        self.0.confirm(name);
    }
    fn abort(&mut self, name: &'static str) {
        self.0.abort(name);
    }
    fn maybe_cached(&self, fragment: &&F, name: &'static str) -> bool {
        self.0.maybe_cached(*fragment, name)
    }
}