try_drop/drop_strategies/once_cell/
thread_unsafe.rs

1use super::{AlreadyOccupiedError, Error, Ignore, Mode};
2use crate::{FallibleTryDropStrategy, TryDropStrategy};
3use once_cell::unsync::OnceCell;
4use std::marker::PhantomData;
5use std::rc::Rc;
6
7/// A drop strategy which sets an error value once.
8///
9/// For more information see it's thread safe counterpart.
10#[cfg_attr(feature = "derives", derive(Debug, Clone, Default))]
11pub struct ThreadUnsafeOnceCellDropStrategy<M: Mode> {
12    /// The inner error value.
13    pub inner: Rc<OnceCell<anyhow::Error>>,
14    _marker: PhantomData<M>,
15}
16
17impl ThreadUnsafeOnceCellDropStrategy<Ignore> {
18    /// Create a new once cell drop strategy which will ignore if there is already an error value in
19    /// its cell.
20    pub fn ignore(value: Rc<OnceCell<anyhow::Error>>) -> Self {
21        Self::new(value)
22    }
23}
24
25impl ThreadUnsafeOnceCellDropStrategy<Error> {
26    /// Create a new once cell drop strategy which will error if there is already an error value in
27    /// its cell.
28    pub fn error(value: Rc<OnceCell<anyhow::Error>>) -> Self {
29        Self::new(value)
30    }
31}
32
33impl<M: Mode> ThreadUnsafeOnceCellDropStrategy<M> {
34    /// Create a new once cell drop strategy which sets an error value once.
35    pub fn new(value: Rc<OnceCell<anyhow::Error>>) -> Self {
36        Self {
37            inner: value,
38            _marker: PhantomData,
39        }
40    }
41}
42
43impl TryDropStrategy for ThreadUnsafeOnceCellDropStrategy<Ignore> {
44    fn handle_error(&self, error: anyhow::Error) {
45        let _ = self.inner.set(error);
46    }
47}
48
49impl FallibleTryDropStrategy for ThreadUnsafeOnceCellDropStrategy<Error> {
50    type Error = AlreadyOccupiedError;
51
52    fn try_handle_error(&self, error: anyhow::Error) -> Result<(), Self::Error> {
53        self.inner.set(error).map_err(AlreadyOccupiedError)
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use crate::drop_strategies::PanicDropStrategy;
60    use crate::test_utils::fallible_given;
61    use super::*;
62
63    fn test<M: Mode>()
64    where
65        ThreadUnsafeOnceCellDropStrategy<M>: FallibleTryDropStrategy,
66    {
67        let item = Rc::new(OnceCell::new());
68        let strategy = ThreadUnsafeOnceCellDropStrategy::<M>::new(Rc::clone(&item));
69        drop(fallible_given(strategy, PanicDropStrategy::DEFAULT));
70        Rc::try_unwrap(item)
71            .expect("item still referenced by `errors`")
72            .into_inner()
73            .expect("no error occupied in `OnceCellDropStrategy`");
74    }
75
76    #[test]
77    fn test_error() {
78        test::<Error>();
79    }
80
81    #[test]
82    fn test_ignore() {
83        test::<Ignore>();
84    }
85}