try_drop/drop_strategies/once_cell/
mod.rs1mod thread_unsafe;
3pub use thread_unsafe::ThreadUnsafeOnceCellDropStrategy;
4mod private {
5 pub trait Sealed {}
6}
7
8use crate::{FallibleTryDropStrategy, TryDropStrategy};
9pub use once_cell::sync::OnceCell;
10use std::error::Error as StdError;
11use std::fmt;
12use std::marker::PhantomData;
13use std::sync::Arc;
14pub use thread_unsafe::*;
15
16#[cfg_attr(
18 feature = "derives",
19 derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)
20)]
21pub enum Ignore {}
22
23impl Mode for Ignore {}
24impl private::Sealed for Ignore {}
25
26#[cfg_attr(
28 feature = "derives",
29 derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)
30)]
31pub enum Error {}
32
33impl Mode for Error {}
34impl private::Sealed for Error {}
35
36pub trait Mode: private::Sealed {}
38
39#[derive(Debug)]
41pub struct AlreadyOccupiedError(pub anyhow::Error);
42
43impl StdError for AlreadyOccupiedError {
44 fn source(&self) -> Option<&(dyn StdError + 'static)> {
45 Some(self.0.as_ref())
46 }
47}
48
49impl fmt::Display for AlreadyOccupiedError {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 f.write_str("an already existing error was occupied in this cell")
52 }
53}
54
55#[cfg_attr(feature = "derives", derive(Debug, Clone, Default))]
90pub struct OnceCellDropStrategy<M: Mode> {
91 pub inner: Arc<OnceCell<anyhow::Error>>,
93 _mode: PhantomData<M>,
94}
95
96impl OnceCellDropStrategy<Ignore> {
97 pub fn ignore(item: Arc<OnceCell<anyhow::Error>>) -> Self {
100 Self::new(item)
101 }
102}
103
104impl OnceCellDropStrategy<Error> {
105 pub fn error(item: Arc<OnceCell<anyhow::Error>>) -> Self {
108 Self::new(item)
109 }
110}
111
112impl<M: Mode> OnceCellDropStrategy<M> {
113 pub fn new(item: Arc<OnceCell<anyhow::Error>>) -> Self {
115 Self {
116 inner: item,
117 _mode: PhantomData,
118 }
119 }
120}
121
122impl TryDropStrategy for OnceCellDropStrategy<Ignore> {
123 fn handle_error(&self, error: anyhow::Error) {
124 let _ = self.inner.set(error);
125 }
126}
127
128impl FallibleTryDropStrategy for OnceCellDropStrategy<Error> {
129 type Error = AlreadyOccupiedError;
130
131 fn try_handle_error(&self, error: anyhow::Error) -> Result<(), Self::Error> {
132 self.inner.set(error).map_err(AlreadyOccupiedError)
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use crate::drop_strategies::PanicDropStrategy;
140 use crate::test_utils::{ErrorsOnDrop, Fallible};
141 use crate::PureTryDrop;
142
143 fn test<M: Mode>()
144 where
145 OnceCellDropStrategy<M>: FallibleTryDropStrategy,
146 {
147 let item = Arc::new(OnceCell::new());
148 let strategy = OnceCellDropStrategy::<M>::new(Arc::clone(&item));
149 let errors =
150 ErrorsOnDrop::<Fallible, _>::given(strategy, PanicDropStrategy::DEFAULT).adapt();
151 drop(errors);
152 Arc::try_unwrap(item)
153 .expect("item still referenced by `errors`")
154 .into_inner()
155 .expect("no error occupied in `OnceCellDropStrategy`");
156 }
157
158 #[test]
159 fn test_ignore() {
160 test::<Ignore>();
161 }
162
163 #[test]
164 fn test_error() {
165 test::<Error>();
166 }
167}