//! Extensions use super::*; use std::{ mem::{ self, ManuallyDrop, }, marker::PhantomData, ops, iter, }; /// Essentially equivelant bound as `eyre::StdError` (private trait) /// /// Useful for when using traits that convert a generic type into an `eyre::Report`. pub trait EyreError: std::error::Error + Send + Sync + 'static{} impl EyreError for T where T: std::error::Error + Send + Sync + 'static{} #[derive(Debug, Clone)] pub struct Joiner(I, F, bool); #[derive(Debug, Clone, Copy)] pub struct CloneJoiner(T); impl Joiner { #[inline(always)] fn size_calc(low: usize) -> usize { match low { 0 | 1 => low, 2 => 4, x if x % 2 == 0 => x * 2, odd => (odd * 2) - 1 } } } type JoinerExt = Joiner; impl Iterator for Joiner where I: Iterator, F: FnMut() -> I::Item { type Item = I::Item; #[inline] fn next(&mut self) -> Option { let val = match self.2 { false => self.0.next(), true => Some(self.1()) }; if val.is_some() { self.2 ^= true; } val } #[inline] fn size_hint(&self) -> (usize, Option) { let (low, high) = self.0.size_hint(); (Self::size_calc(low), high.map(Self::size_calc)) } } impl Iterator for Joiner> where I: Iterator, T: Clone { type Item = I::Item; #[inline] fn next(&mut self) -> Option { let val = match self.2 { false => self.0.next(), true => Some(self.1.0.clone()) }; if val.is_some() { self.2 ^= true; } val } #[inline] fn size_hint(&self) -> (usize, Option) { let (low, high) = self.0.size_hint(); (Self::size_calc(low), high.map(Self::size_calc)) } } impl iter::FusedIterator for Joiner where Joiner: Iterator, I: iter::FusedIterator{} impl ExactSizeIterator for Joiner where Joiner: Iterator, I: ExactSizeIterator {} pub trait IterJoinExt: Sized { fn join_by T>(self, joiner: F) -> Joiner; fn join_by_default(self) -> Joiner T> where T: Default; fn join_by_clone(self, value: T) -> Joiner> where T: Clone; } impl IterJoinExt for I where I: Iterator { #[inline] fn join_by T>(self, joiner: F) -> Joiner { Joiner(self, joiner, false) } #[inline] fn join_by_default(self) -> Joiner T> where T: Default { Joiner(self, T::default, false) } #[inline] fn join_by_clone(self, value: T) -> Joiner> where T: Clone { Joiner(self, CloneJoiner(value), false) } } pub trait IntoEyre { fn into_eyre(self) -> eyre::Result; } impl IntoEyre for Result { #[inline(always)] fn into_eyre(self) -> eyre::Result { match self { Err(e) => Err(eyre::Report::from(e)), Ok(y) => Ok(y), } } } pub trait FlattenReports { /// Flatten a `eyre::Result>` into an `eyre::Result` fn flatten(self) -> eyre::Result; } pub trait FlattenEyreResult where E: EyreError { /// Flatten a `Result, OE>` into an `eyre::Result` fn flatten(self) -> eyre::Result; } pub trait FlattenResults { /// Flatten a `Result, E>` into a `Result`. fn flatten(self) -> Result; } impl> FlattenResults for Result, E> { /// Flatten a `Result>, E>` into a `Result` /// /// This will convert the inner error into the type of the outer error. #[inline] fn flatten(self) -> Result { match self { Err(e) => Err(e), Ok(Ok(e)) => Ok(e), Ok(Err(e)) => Err(e.into()) } } } impl FlattenEyreResult for Result, E> { #[inline] fn flatten(self) -> eyre::Result { match self { Err(e) => Err(e).with_note(|| "Flattened report (outer)"), Ok(Err(e)) => Err(e).with_warning(|| "Flattened report (inner)"), Ok(Ok(a)) => Ok(a), } } } impl FlattenReports for eyre::Result> { #[inline] fn flatten(self) -> eyre::Result { match self { Err(e) => Err(e.with_note(|| "Flattened report (outer)")), Ok(Err(e)) => Err(e.with_warning(|| "Flattened report (inner)")), Ok(Ok(a)) => Ok(a), } } } impl FlattenReports for eyre::Result> { #[inline] fn flatten(self) -> eyre::Result { match self { Err(e) => Err(e.with_note(|| "Flattened report (outer)")), Ok(None) => Err(eyre!("Value expected, but not found").with_section(|| format!("Option<{}>", std::any::type_name::()).header("Option type was")).with_warning(|| "Flattened report (inner)")), Ok(Some(a)) => Ok(a), } } } impl FlattenEyreResult for Result, E> { #[inline] fn flatten(self) -> eyre::Result { match self { Err(e) => Err(e).with_note(|| "Flattened report (outer)"), Ok(None) => Err(eyre!("Value expected, but not found") .with_section(|| format!("Option<{}>", std::any::type_name::()) .header("Option type was")) .with_warning(|| "Flattened report (inner)")), Ok(Some(a)) => Ok(a), } } } #[derive(Debug)] enum RunOnceInternal { Live(ManuallyDrop), Dead, } impl Clone for RunOnceInternal { #[inline] fn clone(&self) -> Self { match self { Self::Live(l) => Self::Live(l.clone()), _ => Self::Dead } } } impl RunOnceInternal { /// Take `F` now, unless it doesn't need to be dropped. /// /// # Returns /// * if `!needs_drop::()`, `None` is always returned. /// * if `self` is `Dead`, `None` is returned. /// * if `self` is `Live(f)`, `Some(f)` is returned, and `self` is set to `Dead`. #[inline(always)] fn take_now_for_drop(&mut self) -> Option { if mem::needs_drop::() { self.take_now() } else { None } } /// If `Live`, return the value inside and set to `Dead`. /// Otherwise, return `None`. #[inline(always)] fn take_now(&mut self) -> Option { if let Self::Live(live) = self { let val = unsafe { ManuallyDrop::take(live) }; *self = Self::Dead; Some(val) } else { None } } } impl ops::Drop for RunOnceInternal { #[inline] fn drop(&mut self) { if mem::needs_drop::() { if let Self::Live(func) = self { unsafe { ManuallyDrop::drop(func) }; } } } } /// Holds a 0 argument closure that will only be ran *once*. #[derive(Debug, Clone)] pub struct RunOnce(PhantomData T>, RunOnceInternal); unsafe impl Send for RunOnce where F: FnOnce() -> T + Send {} impl RunOnce where F: FnOnce() -> T { pub const fn new(func: F) -> Self { Self(PhantomData, RunOnceInternal::Live(ManuallyDrop::new(func))) } pub const fn never() -> Self { Self(PhantomData, RunOnceInternal::Dead) } #[inline] pub fn try_take(&mut self) -> Option { match &mut self.1 { RunOnceInternal::Live(func) => { Some(unsafe { ManuallyDrop::take(func) }) }, _ => None } } #[inline] pub fn try_run(&mut self) -> Option { self.try_take().map(|func| func()) } #[inline] pub fn run(mut self) -> T { self.try_run().expect("Function has already been consumed") } #[inline] pub fn take(mut self) -> F { self.try_take().expect("Function has already been consumed") } #[inline] pub fn is_runnable(&self) -> bool { if let RunOnceInternal::Dead = &self.1 { false } else { true } } } #[inline(always)] pub(crate) fn map_bool(ok: bool, value: T) -> T where T: Default { if ok { value } else { T::default() } } pub trait SealExt { fn try_seal(&self, shrink: bool, grow: bool, write: bool) -> io::Result<()>; #[inline] fn sealed(self, shrink: bool, grow: bool, write: bool) -> Self where Self: Sized { if let Err(e) = self.try_seal(shrink, grow, write) { panic!("Failed to apply seals: {}", io::Error::last_os_error()) } self } } #[cfg(any(feature="memfile", feature="exec"))] const _: () = { impl SealExt for T { #[cfg_attr(feature="logging", instrument(skip(self)))] fn sealed(self, shrink: bool, grow: bool, write: bool) -> Self where Self: Sized { use libc::{ F_SEAL_GROW, F_SEAL_SHRINK, F_SEAL_WRITE, F_ADD_SEALS, fcntl }; let fd = self.as_raw_fd(); if unsafe { fcntl(fd, F_ADD_SEALS , map_bool(shrink, F_SEAL_SHRINK) | map_bool(grow, F_SEAL_GROW) | map_bool(write, F_SEAL_WRITE)) } < 0 { panic!("Failed to apply seals to file descriptor {fd}: {}", io::Error::last_os_error()) } self } #[cfg_attr(feature="logging", instrument(skip(self), err))] fn try_seal(&self, shrink: bool, grow: bool, write: bool) -> io::Result<()> { use libc::{ F_SEAL_GROW, F_SEAL_SHRINK, F_SEAL_WRITE, F_ADD_SEALS, fcntl }; let fd = self.as_raw_fd(); if unsafe { fcntl(fd, F_ADD_SEALS , map_bool(shrink, F_SEAL_SHRINK) | map_bool(grow, F_SEAL_GROW) | map_bool(write, F_SEAL_WRITE)) } < 0 { Err(io::Error::last_os_error()) } else { Ok(()) } } } };