use crate::{Rocket, Request, Response, Data, Build, Orbit};
use crate::fairing::{Fairing, Info, Kind};
#[derive(Default)]
pub struct Fairings {
all_fairings: Vec<Box<dyn Fairing>>,
failures: Vec<Info>,
num_ignited: usize,
ignite: Vec<usize>,
liftoff: Vec<usize>,
request: Vec<usize>,
response: Vec<usize>,
shutdown: Vec<usize>,
}
macro_rules! iter {
($_self:ident . $kind:ident) => ({
iter!($_self, $_self.$kind.iter().copied()).map(|v| v.1)
});
($_self:ident, $indices:expr) => ({
let all_fairings = &$_self.all_fairings;
$indices.filter_map(move |i| {
let i = i.clone();
debug_assert!(all_fairings.get(i).is_some());
let f = all_fairings.get(i).map(|f| &**f)?;
Some((i, f))
})
})
}
impl Fairings {
#[inline]
pub fn new() -> Fairings {
Fairings::default()
}
pub fn active(&self) -> impl Iterator<Item = &usize> {
self.ignite.iter()
.chain(self.liftoff.iter())
.chain(self.request.iter())
.chain(self.response.iter())
.chain(self.shutdown.iter())
}
pub fn unique_active(&self) -> impl Iterator<Item = usize> {
let mut bitmap = vec![false; self.all_fairings.len()];
for i in self.active() {
bitmap.get_mut(*i).map(|active| *active = true);
}
bitmap.into_iter()
.enumerate()
.filter_map(|(i, active)| active.then_some(i))
}
pub fn unique_set(&self) -> Vec<&dyn Fairing> {
iter!(self, self.unique_active()).map(|v| v.1).collect()
}
pub fn add(&mut self, fairing: Box<dyn Fairing>) {
let this = &fairing;
let this_info = this.info();
if this_info.kind.is(Kind::Singleton) {
let ignite_dup = iter!(self.ignite).position(|f| f.type_id() == this.type_id());
if let Some(dup_ignite_index) = ignite_dup {
if dup_ignite_index < self.num_ignited {
self.failures.push(this_info);
return;
}
}
let remove = |k: usize, from: &mut Vec<usize>| {
if let Ok(j) = from.binary_search(&k) {
from.remove(j);
}
};
let mut dups: Vec<usize> = iter!(self, self.unique_active())
.filter(|(_, f)| f.type_id() == this.type_id())
.map(|(i, _)| i)
.collect();
dups.sort(); dups.dedup(); dups.reverse();
for i in dups {
remove(i, &mut self.ignite);
remove(i, &mut self.liftoff);
remove(i, &mut self.request);
remove(i, &mut self.response);
remove(i, &mut self.shutdown);
}
}
let index = self.all_fairings.len();
self.all_fairings.push(fairing);
if this_info.kind.is(Kind::Ignite) { self.ignite.push(index); }
if this_info.kind.is(Kind::Liftoff) { self.liftoff.push(index); }
if this_info.kind.is(Kind::Request) { self.request.push(index); }
if this_info.kind.is(Kind::Response) { self.response.push(index); }
if this_info.kind.is(Kind::Shutdown) { self.shutdown.push(index); }
}
pub fn append(&mut self, others: &mut Fairings) {
for fairing in others.all_fairings.drain(..) {
self.add(fairing);
}
}
pub async fn handle_ignite(mut rocket: Rocket<Build>) -> Rocket<Build> {
while rocket.fairings.num_ignited < rocket.fairings.ignite.len() {
let mut fairings = std::mem::replace(&mut rocket.fairings, Fairings::new());
for fairing in iter!(fairings.ignite).skip(fairings.num_ignited) {
let info = fairing.info();
rocket = match fairing.on_ignite(rocket).await {
Ok(rocket) => rocket,
Err(rocket) => {
fairings.failures.push(info);
rocket
}
};
fairings.num_ignited += 1;
}
fairings.append(&mut rocket.fairings);
rocket.fairings = fairings;
}
rocket
}
#[inline(always)]
pub async fn handle_liftoff(&self, rocket: &Rocket<Orbit>) {
let liftoff_futures = iter!(self.liftoff).map(|f| f.on_liftoff(rocket));
futures::future::join_all(liftoff_futures).await;
}
#[inline(always)]
pub async fn handle_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
for fairing in iter!(self.request) {
fairing.on_request(req, data).await
}
}
#[inline(always)]
pub async fn handle_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
for fairing in iter!(self.response) {
fairing.on_response(req, res).await;
}
}
#[inline(always)]
pub async fn handle_shutdown(&self, rocket: &Rocket<Orbit>) {
let shutdown_futures = iter!(self.shutdown).map(|f| f.on_shutdown(rocket));
futures::future::join_all(shutdown_futures).await;
}
pub fn audit(&self) -> Result<(), &[Info]> {
match &self.failures[..] {
[] => Ok(()),
failures => Err(failures)
}
}
pub fn filter<F: Fairing>(&self) -> impl Iterator<Item = &F> {
iter!(self, self.unique_active())
.filter_map(|v| v.1.downcast_ref::<F>())
}
pub fn filter_mut<F: Fairing>(&mut self) -> impl Iterator<Item = &mut F> {
let mut bitmap = vec![false; self.all_fairings.len()];
for &i in self.active() {
let is_target = self.all_fairings.get(i)
.and_then(|f| f.downcast_ref::<F>())
.is_some();
bitmap.get_mut(i).map(|target| *target = is_target);
}
self.all_fairings.iter_mut()
.enumerate()
.filter(move |(i, _)| *bitmap.get(*i).unwrap_or(&false))
.filter_map(|(_, f)| f.downcast_mut::<F>())
}
}
impl std::fmt::Debug for Fairings {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn debug_info<'a>(iter: impl Iterator<Item = &'a dyn Fairing>) -> Vec<Info> {
iter.map(|f| f.info()).collect()
}
f.debug_struct("Fairings")
.field("launch", &debug_info(iter!(self.ignite)))
.field("liftoff", &debug_info(iter!(self.liftoff)))
.field("request", &debug_info(iter!(self.request)))
.field("response", &debug_info(iter!(self.response)))
.field("shutdown", &debug_info(iter!(self.shutdown)))
.finish()
}
}