rocket/fairing/
fairings.rs

1use std::collections::HashSet;
2
3use crate::{Rocket, Request, Response, Data, Build, Orbit};
4use crate::fairing::{Fairing, Info, Kind};
5use crate::log::PaintExt;
6
7use yansi::Paint;
8
9#[derive(Default)]
10pub struct Fairings {
11    // NOTE: This is a push-only vector due to the index-vectors below!
12    all_fairings: Vec<Box<dyn Fairing>>,
13    // Ignite fairings that have failed.
14    failures: Vec<Info>,
15    // The number of ignite fairings from `self.ignite` we've run.
16    num_ignited: usize,
17    // The vectors below hold indices into `all_fairings`.
18    ignite: Vec<usize>,
19    liftoff: Vec<usize>,
20    request: Vec<usize>,
21    response: Vec<usize>,
22    shutdown: Vec<usize>,
23}
24
25macro_rules! iter {
26    ($_self:ident . $kind:ident) => ({
27        iter!($_self, $_self.$kind.iter()).map(|v| v.1)
28    });
29    ($_self:ident, $indices:expr) => ({
30        let all_fairings = &$_self.all_fairings;
31        $indices.filter_map(move |i| {
32            debug_assert!(all_fairings.get(*i).is_some());
33            let f = all_fairings.get(*i).map(|f| &**f)?;
34            Some((*i, f))
35        })
36    })
37}
38
39impl Fairings {
40    #[inline]
41    pub fn new() -> Fairings {
42        Fairings::default()
43    }
44
45    pub fn active(&self) -> impl Iterator<Item = &usize> {
46        self.ignite.iter()
47            .chain(self.liftoff.iter())
48            .chain(self.request.iter())
49            .chain(self.response.iter())
50            .chain(self.shutdown.iter())
51    }
52
53    pub fn add(&mut self, fairing: Box<dyn Fairing>) {
54        let this = &fairing;
55        let this_info = this.info();
56        if this_info.kind.is(Kind::Singleton) {
57            // If we already ran a duplicate on ignite, then fail immediately.
58            // There is no way to uphold the "only run last singleton" promise.
59            //
60            // How can this happen? Like this:
61            //   1. Attach A (singleton).
62            //   2. Attach B (any fairing).
63            //   3. Ignite.
64            //   4. A executes on_ignite.
65            //   5. B executes on_ignite, attaches another A.
66            //   6. --- (A would run if not for this code)
67            let ignite_dup = iter!(self.ignite).position(|f| f.type_id() == this.type_id());
68            if let Some(dup_ignite_index) = ignite_dup {
69                if dup_ignite_index < self.num_ignited {
70                    self.failures.push(this_info);
71                    return;
72                }
73            }
74
75            // Finds `k` in `from` and removes it if it's there.
76            let remove = |k: usize, from: &mut Vec<usize>| {
77                if let Ok(j) = from.binary_search(&k) {
78                    from.remove(j);
79                }
80            };
81
82            // Collect all of the active duplicates.
83            let mut dups: Vec<usize> = iter!(self, self.active())
84                .filter(|(_, f)| f.type_id() == this.type_id())
85                .map(|(i, _)| i)
86                .collect();
87
88            // Reverse the dup indices so `remove` is stable given shifts.
89            dups.sort(); dups.dedup(); dups.reverse();
90            for i in dups {
91                remove(i, &mut self.ignite);
92                remove(i, &mut self.liftoff);
93                remove(i, &mut self.request);
94                remove(i, &mut self.response);
95                remove(i, &mut self.shutdown);
96            }
97        }
98
99        let index = self.all_fairings.len();
100        self.all_fairings.push(fairing);
101        if this_info.kind.is(Kind::Ignite) { self.ignite.push(index); }
102        if this_info.kind.is(Kind::Liftoff) { self.liftoff.push(index); }
103        if this_info.kind.is(Kind::Request) { self.request.push(index); }
104        if this_info.kind.is(Kind::Response) { self.response.push(index); }
105        if this_info.kind.is(Kind::Shutdown) { self.shutdown.push(index); }
106    }
107
108    pub fn append(&mut self, others: &mut Fairings) {
109        for fairing in others.all_fairings.drain(..) {
110            self.add(fairing);
111        }
112    }
113
114    pub async fn handle_ignite(mut rocket: Rocket<Build>) -> Rocket<Build> {
115        while rocket.fairings.num_ignited < rocket.fairings.ignite.len() {
116            // We're going to move `rocket` while borrowing `fairings`...
117            let mut fairings = std::mem::replace(&mut rocket.fairings, Fairings::new());
118            for fairing in iter!(fairings.ignite).skip(fairings.num_ignited) {
119                let info = fairing.info();
120                rocket = match fairing.on_ignite(rocket).await {
121                    Ok(rocket) => rocket,
122                    Err(rocket) => {
123                        fairings.failures.push(info);
124                        rocket
125                    }
126                };
127
128                fairings.num_ignited += 1;
129            }
130
131            // Note that `rocket.fairings` may now be non-empty since ignite
132            // fairings could have added more fairings! Move them to the end.
133            fairings.append(&mut rocket.fairings);
134            rocket.fairings = fairings;
135        }
136
137        rocket
138    }
139
140    #[inline(always)]
141    pub async fn handle_liftoff(&self, rocket: &Rocket<Orbit>) {
142        let liftoff_futures = iter!(self.liftoff).map(|f| f.on_liftoff(rocket));
143        futures::future::join_all(liftoff_futures).await;
144    }
145
146    #[inline(always)]
147    pub async fn handle_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
148        for fairing in iter!(self.request) {
149            fairing.on_request(req, data).await
150        }
151    }
152
153    #[inline(always)]
154    pub async fn handle_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
155        for fairing in iter!(self.response) {
156            fairing.on_response(req, res).await;
157        }
158    }
159
160    #[inline(always)]
161    pub async fn handle_shutdown(&self, rocket: &Rocket<Orbit>) {
162        let shutdown_futures = iter!(self.shutdown).map(|f| f.on_shutdown(rocket));
163        futures::future::join_all(shutdown_futures).await;
164    }
165
166    pub fn audit(&self) -> Result<(), &[Info]> {
167        match self.failures.is_empty() {
168            true => Ok(()),
169            false => Err(&self.failures)
170        }
171    }
172
173    pub fn pretty_print(&self) {
174        let active_fairings = self.active().collect::<HashSet<_>>();
175        if !active_fairings.is_empty() {
176            launch_meta!("{}{}:", "📡 ".emoji(), "Fairings".magenta());
177
178            for (_, fairing) in iter!(self, active_fairings.into_iter()) {
179                let (name, kind) = (fairing.info().name, fairing.info().kind);
180                launch_meta_!("{} ({})", name.primary().bold(), kind.blue().bold());
181            }
182        }
183    }
184}
185
186impl std::fmt::Debug for Fairings {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188        fn debug_info<'a>(iter: impl Iterator<Item = &'a dyn Fairing>) -> Vec<Info> {
189            iter.map(|f| f.info()).collect()
190        }
191
192        f.debug_struct("Fairings")
193            .field("launch", &debug_info(iter!(self.ignite)))
194            .field("liftoff", &debug_info(iter!(self.liftoff)))
195            .field("request", &debug_info(iter!(self.request)))
196            .field("response", &debug_info(iter!(self.response)))
197            .field("shutdown", &debug_info(iter!(self.shutdown)))
198            .finish()
199    }
200}