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
//! Application components: extensions/plugins for Abscissa applications.
//!
//! See docs on the `Component` trait for more information.

#![allow(unused_variables)]

mod handle;
mod id;
pub mod registry;

pub use self::{handle::Handle, id::Id, registry::Registry};
pub use abscissa_derive::Component;

use crate::{application::Application, shutdown::Shutdown, FrameworkError, Version};
use std::{any::Any, cmp::Ordering, fmt::Debug, slice::Iter};

/// Application components.
///
/// Components are Abscissa's primary extension mechanism, and are aware of
/// the application lifecycle. They are owned by the application as boxed trait
/// objects in a runtime type registry which is aware of a dependency ordering
/// and can (potentially in the future) support runtime reinitialization.
///
/// During application initialization, callbacks are sent to all components
/// upon events like application configuration being loaded. The
/// `register_dependency` callback is called for each dependency returned
/// by the `dependencies` method.
///
/// Additionally, they receive a callback prior to application shutdown.
///
/// ## Custom Derive
///
/// The main intended way to impl this trait is by using the built-in custom
/// derive functionality.
///
/// ```rust
/// use abscissa_core::Component;
///
/// #[derive(Component, Debug)]
/// pub struct MyComponent {}
/// ```
///
/// This will automatically implement the entire trait for you.
pub trait Component<A>: AsAny + Debug + Send + Sync
where
    A: Application,
{
    /// Identifier for this component.
    ///
    /// These are the Rust path (e.g. `crate_name:foo::Foo`) by convention.
    fn id(&self) -> Id;

    /// Version of this component
    fn version(&self) -> Version;

    /// Lifecycle event called when application configuration should be loaded
    /// if it were possible.
    fn after_config(&mut self, config: &A::Cfg) -> Result<(), FrameworkError> {
        Ok(())
    }

    /// Names of the components this component depends on.
    ///
    /// After this app's `after_config` callback is fired, the
    /// `register_dependency` callback below will be fired for each of these.
    fn dependencies(&self) -> Iter<'_, Id> {
        [].iter()
    }

    /// Register a dependency of this component (a.k.a. "dependency injection")
    fn register_dependency(
        &mut self,
        handle: Handle,
        dependency: &mut dyn Component<A>,
    ) -> Result<(), FrameworkError> {
        unimplemented!();
    }

    /// Perform any tasks which should occur before the app exits
    fn before_shutdown(&self, kind: Shutdown) -> Result<(), FrameworkError> {
        Ok(())
    }
}

impl<A> PartialEq for Box<dyn Component<A>>
where
    A: Application,
{
    fn eq(&self, other: &Self) -> bool {
        self.id() == other.id()
    }
}

impl<A> PartialOrd for Box<dyn Component<A>>
where
    A: Application,
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if other.dependencies().any(|dep| *dep == self.id()) {
            if self.dependencies().any(|dep| *dep == other.id()) {
                None
            } else {
                Some(Ordering::Greater)
            }
        } else if self.dependencies().any(|dep| *dep == other.id()) {
            Some(Ordering::Less)
        } else {
            Some(Ordering::Equal)
        }
    }
}

/// Dynamic type helper trait
// TODO(tarcieri): eliminate this trait or hide it from the public API
pub trait AsAny: Any {
    /// Borrow this concrete type as a `&dyn Any`
    fn as_any(&self) -> &dyn Any;

    /// Borrow this concrete type as a `&mut dyn Any`
    fn as_mut_any(&mut self) -> &mut dyn Any;
}

impl<T> AsAny for T
where
    T: Any,
{
    fn as_any(&self) -> &dyn Any {
        self
    }

    fn as_mut_any(&mut self) -> &mut dyn Any {
        self
    }
}