mod thread_unsafe;
pub use thread_unsafe::ThreadUnsafeOnceCellDropStrategy;
mod private {
pub trait Sealed {}
}
use crate::{FallibleTryDropStrategy, TryDropStrategy};
pub use once_cell::sync::OnceCell;
use std::error::Error as StdError;
use std::fmt;
use std::marker::PhantomData;
use std::sync::Arc;
pub use thread_unsafe::*;
#[cfg_attr(
feature = "derives",
derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)
)]
pub enum Ignore {}
impl Mode for Ignore {}
impl private::Sealed for Ignore {}
#[cfg_attr(
feature = "derives",
derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)
)]
pub enum Error {}
impl Mode for Error {}
impl private::Sealed for Error {}
pub trait Mode: private::Sealed {}
#[derive(Debug)]
pub struct AlreadyOccupiedError(pub anyhow::Error);
impl StdError for AlreadyOccupiedError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(self.0.as_ref())
}
}
impl fmt::Display for AlreadyOccupiedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("an already existing error was occupied in this cell")
}
}
#[cfg_attr(feature = "derives", derive(Debug, Clone, Default))]
pub struct OnceCellDropStrategy<M: Mode> {
pub inner: Arc<OnceCell<anyhow::Error>>,
_mode: PhantomData<M>,
}
impl OnceCellDropStrategy<Ignore> {
pub fn ignore(item: Arc<OnceCell<anyhow::Error>>) -> Self {
Self::new(item)
}
}
impl OnceCellDropStrategy<Error> {
pub fn error(item: Arc<OnceCell<anyhow::Error>>) -> Self {
Self::new(item)
}
}
impl<M: Mode> OnceCellDropStrategy<M> {
pub fn new(item: Arc<OnceCell<anyhow::Error>>) -> Self {
Self {
inner: item,
_mode: PhantomData,
}
}
}
impl TryDropStrategy for OnceCellDropStrategy<Ignore> {
fn handle_error(&self, error: anyhow::Error) {
let _ = self.inner.set(error);
}
}
impl FallibleTryDropStrategy for OnceCellDropStrategy<Error> {
type Error = AlreadyOccupiedError;
fn try_handle_error(&self, error: anyhow::Error) -> Result<(), Self::Error> {
self.inner.set(error).map_err(AlreadyOccupiedError)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::drop_strategies::PanicDropStrategy;
use crate::test_utils::{ErrorsOnDrop, Fallible};
use crate::PureTryDrop;
fn test<M: Mode>()
where
OnceCellDropStrategy<M>: FallibleTryDropStrategy,
{
let item = Arc::new(OnceCell::new());
let strategy = OnceCellDropStrategy::<M>::new(Arc::clone(&item));
let errors =
ErrorsOnDrop::<Fallible, _>::given(strategy, PanicDropStrategy::DEFAULT).adapt();
drop(errors);
Arc::try_unwrap(item)
.expect("item still referenced by `errors`")
.into_inner()
.expect("no error occupied in `OnceCellDropStrategy`");
}
#[test]
fn test_ignore() {
test::<Ignore>();
}
#[test]
fn test_error() {
test::<Error>();
}
}