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 all_fairings: Vec<Box<dyn Fairing>>,
13 failures: Vec<Info>,
15 num_ignited: usize,
17 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 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 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 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 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 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 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}