1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Abscissa's component registry

pub use super::Component;
use crate::{
    application::{self, Application},
    error::{FrameworkError, FrameworkErrorKind::ComponentError},
    shutdown::Shutdown,
};
use std::{any::Any, borrow::Borrow, collections::HashSet, slice};

/// The component registry provides a system for runtime registration of
/// application components which can interact with each other dynamically.
///
/// Components are sorted according to a dependency ordering, started
/// in-order, and at application termination time, shut down in reverse order.
#[derive(Debug)]
pub struct Registry<A: Application> {
    components: Vec<Box<dyn Component<A>>>,
}

impl<A> Default for Registry<A>
where
    A: Application,
{
    fn default() -> Self {
        Registry { components: vec![] }
    }
}

impl<A> Registry<A>
where
    A: Application,
{
    /// Register components, determining their dependency order
    pub fn register<I>(&mut self, components: I) -> Result<(), FrameworkError>
    where
        I: IntoIterator<Item = Box<dyn Component<A>>>,
    {
        // TODO(tarcieri): flexible runtime registration?
        ensure!(
            self.components.is_empty(),
            ComponentError,
            "no support for registering additional components (yet)"
        );

        let mut result = Registry {
            components: components.into_iter().collect::<Vec<_>>(),
        };

        // Ensure all component names are unique
        let mut names = HashSet::new();

        for component in &result.components {
            ensure!(
                names.insert(component.name()),
                ComponentError,
                "duplicate component name: {}",
                component.name()
            );
        }

        result.sort();
        Ok(())
    }

    /// Callback fired by application when configuration has been loaded
    pub fn after_config(&mut self, config: &A::Cfg) -> Result<(), FrameworkError> {
        for component in self.iter_mut() {
            component.after_config(config)?;
        }

        Ok(())
    }

    /// Iterate over the components mutably.
    pub fn iter(&mut self) -> slice::Iter<Box<dyn Component<A>>> {
        self.components.iter()
    }

    /// Iterate over the components mutably.
    pub fn iter_mut(&mut self) -> slice::IterMut<Box<dyn Component<A>>> {
        self.components.iter_mut()
    }

    /// Shutdown components (in the reverse order they were started)
    pub fn shutdown(&self, app: &A, shutdown: Shutdown) -> Result<(), FrameworkError> {
        for component in self.components.iter().rev() {
            component.before_shutdown(shutdown)?;
        }

        Ok(())
    }

    /// Sort components by dependency ordering, loading the components that depend
    /// on others after their dependencies.
    ///
    /// Exits the application if the ordering cannot be resolved.
    fn sort(&mut self) {
        self.components.sort_by(|a, b| {
            a.partial_cmp(b)
                .unwrap_or_else(|| application::exit::bad_component_order(a.borrow(), b.borrow()))
        })
    }
}

impl<A> Registry<A>
where
    A: Application + 'static,
{
    /// Get a reference to a component of the given type, if one has been registered
    pub fn get_ref<C>(&self) -> Option<&C>
    where
        C: Component<A> + 'static,
    {
        // TODO(tarcieri): more efficient implementation
        for component in self.components.iter() {
            if let Some(result) = (component as &dyn Any).downcast_ref::<C>() {
                return Some(result);
            }
        }

        None
    }

    /// Get a mutable reference component of the given type, if one has been registered
    pub fn get_mut<C>(&mut self) -> Option<&mut C>
    where
        C: Component<A> + 'static,
    {
        // TODO(tarcieri): more efficient implementation
        for component in self.components.iter_mut() {
            if let Some(result) = (component as &mut dyn Any).downcast_mut::<C>() {
                return Some(result);
            }
        }

        None
    }
}