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
use state::Container;
use figment::Figment;

use crate::{Catcher, Config, Rocket, Route, Shutdown};
use crate::router::Router;
use crate::fairing::Fairings;

mod private {
    pub trait Sealed {  }
}

#[doc(hidden)]
pub trait Stateful: private::Sealed {
    fn into_state(self) -> State;
    fn as_state_ref(&self) -> StateRef<'_>;
}

/// A marker trait for Rocket's launch phases.
///
/// This treat is implemented by the three phase marker types: [`Build`],
/// [`Ignite`], and [`Orbit`], representing the three phases to launch an
/// instance of [`Rocket`]. This trait is _sealed_ and cannot be implemented
/// outside of Rocket.
///
/// For a description of the three phases, see [`Rocket#phases`].
pub trait Phase: private::Sealed {
    #[doc(hidden)]
    type State: std::fmt::Debug + Stateful + Sync + Send + Unpin;
}

macro_rules! phase {
    ($(#[$o:meta])* $P:ident ($(#[$i:meta])* $S:ident) { $($fields:tt)* }) => (
        $(#[$o])*
        pub enum $P { }

        impl Phase for $P {
            #[doc(hidden)]
            type State = $S;
        }

        $(#[$i])*
        #[doc(hidden)]
        pub struct $S {
            $($fields)*
        }

        impl Stateful for $S {
            fn into_state(self) -> State { State::$P(self) }
            fn as_state_ref(&self) -> StateRef<'_> { StateRef::$P(self) }
        }

        #[doc(hidden)]
        impl From<$S> for Rocket<$P> {
            fn from(s: $S) -> Self { Rocket(s) }
        }

        impl private::Sealed for $P {}

        impl private::Sealed for $S {}
    )
}

macro_rules! phases {
    ($($(#[$o:meta])* $P:ident ($(#[$i:meta])* $S:ident) { $($fields:tt)* })*) => (
        #[doc(hidden)]
        pub enum State { $($P($S)),* }

        #[doc(hidden)]
        pub enum StateRef<'a> { $($P(&'a $S)),* }

        $(phase!($(#[$o])* $P ($(#[$i])* $S) { $($fields)* });)*
    )
}

phases! {
    /// The initial launch [`Phase`].
    ///
    /// An instance of `Rocket` in this phase is typed as [`Rocket<Build>`] and
    /// represents a transient, in-progress build. See [`Rocket#build`] for
    /// details.
    Build (#[derive(Default, Debug)] Building) {
        pub(crate) routes: Vec<Route>,
        pub(crate) catchers: Vec<Catcher>,
        pub(crate) fairings: Fairings,
        pub(crate) figment: Figment,
        pub(crate) state: Container![Send + Sync],
    }

    /// The second launch [`Phase`]: post-build but pre-orbit.
    ///
    /// An instance of `Rocket` in this phase is typed as [`Rocket<Ignite>`] and
    /// represents a fully built and finalized application server ready for
    /// launch into orbit. See [`Rocket#ignite`] for full details.
    Ignite (#[derive(Debug)] Igniting) {
        pub(crate) router: Router,
        pub(crate) fairings: Fairings,
        pub(crate) figment: Figment,
        pub(crate) config: Config,
        pub(crate) state: Container![Send + Sync],
        pub(crate) shutdown: Shutdown,
    }

    /// The final launch [`Phase`].
    ///
    /// An instance of `Rocket` in this phase is typed as [`Rocket<Orbit>`] and
    /// represents a running application. See [`Rocket#orbit`] for full details.
    Orbit (#[derive(Debug)] Orbiting) {
        pub(crate) router: Router,
        pub(crate) fairings: Fairings,
        pub(crate) figment: Figment,
        pub(crate) config: Config,
        pub(crate) state: Container![Send + Sync],
        pub(crate) shutdown: Shutdown,
    }
}