use crate::fairing::{Fairing, Info, Kind};
use crate::{Build, Data, Orbit, Request, Response, Rocket};
#[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() {
if let Some(active) = bitmap.get_mut(*i) {
*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();
if let Some(target) = bitmap.get_mut(i) {
*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()
}
}