try_drop/drop_strategies/adhoc/fn_mut/
mod.rs

1mod thread_unsafe;
2
3use crate::{FallibleTryDropStrategy, TryDropStrategy};
4use anyhow::Error;
5use parking_lot::Mutex;
6use std::marker::PhantomData;
7pub use thread_unsafe::*;
8
9/// A quick and dirty drop strategy which uses a function.
10///
11/// This is more flexible compared to [`AdHocDropStrategy`], accepting also [`FnMut`]s instead of
12/// only [`Fn`]s, but the function is guarded by a [`Mutex`], which has more overhead.
13///
14/// [`AdHocDropStrategy`]: super::AdHocDropStrategy
15#[cfg_attr(feature = "derives", derive(Debug, Default))]
16pub struct AdHocMutDropStrategy<F: FnMut(crate::Error)>(pub Mutex<F>);
17
18impl<F: FnMut(crate::Error)> AdHocMutDropStrategy<F> {
19    /// Create a new ad-hoc try drop strategy.
20    pub fn new(f: F) -> Self {
21        Self(Mutex::new(f))
22    }
23}
24
25impl<F: FnMut(crate::Error)> TryDropStrategy for AdHocMutDropStrategy<F> {
26    fn handle_error(&self, error: crate::Error) {
27        self.0.lock()(error)
28    }
29}
30
31impl<F: FnMut(crate::Error)> From<F> for AdHocMutDropStrategy<F> {
32    fn from(f: F) -> Self {
33        Self::new(f)
34    }
35}
36
37/// Signifies that this type can be converted into an [`AdHocMutDropStrategy`].
38pub trait IntoAdHocMutDropStrategy: FnMut(crate::Error) + Sized {
39    /// Convert this type into an [`AdHocMutDropStrategy`].
40    fn into_drop_strategy(self) -> AdHocMutDropStrategy<Self> {
41        AdHocMutDropStrategy::new(self)
42    }
43}
44
45impl<T: FnMut(crate::Error)> IntoAdHocMutDropStrategy for T {}
46
47/// A quick and dirty try drop strategy which uses a function.
48///
49/// This is more flexible compared to [`AdHocFallibleDropStrategy`], accepting also [`FnMut`]s
50/// instead of only [`Fn`]s, but the function is guarded by a [`Mutex`], which has more overhead.
51///
52/// [`AdHocFallibleDropStrategy`]: super::AdHocFallibleDropStrategy
53#[cfg_attr(feature = "derives", derive(Debug, Default))]
54pub struct AdHocMutFallibleDropStrategy<F, E>
55where
56    F: FnMut(crate::Error) -> Result<(), E>,
57    E: Into<anyhow::Error>,
58{
59    /// The function to call.
60    pub f: Mutex<F>,
61    _error: PhantomData<E>,
62}
63
64impl<F, E> AdHocMutFallibleDropStrategy<F, E>
65where
66    F: FnMut(crate::Error) -> Result<(), E>,
67    E: Into<anyhow::Error>,
68{
69    /// Create a new ad-hoc fallible drop strategy.
70    pub fn new(f: F) -> Self {
71        Self {
72            f: Mutex::new(f),
73            _error: PhantomData,
74        }
75    }
76}
77
78impl<F, E> FallibleTryDropStrategy for AdHocMutFallibleDropStrategy<F, E>
79where
80    F: FnMut(crate::Error) -> Result<(), E>,
81    E: Into<anyhow::Error>,
82{
83    type Error = E;
84
85    fn try_handle_error(&self, error: Error) -> Result<(), Self::Error> {
86        self.f.lock()(error)
87    }
88}
89
90impl<F, E> From<F> for AdHocMutFallibleDropStrategy<F, E>
91where
92    F: FnMut(crate::Error) -> Result<(), E>,
93    E: Into<anyhow::Error>,
94{
95    fn from(f: F) -> Self {
96        Self::new(f)
97    }
98}
99
100/// Signifies that this type can be converted into an [`AdHocMutFallibleDropStrategy`].
101pub trait IntoAdHocMutFallibleDropStrategy<E: Into<anyhow::Error>>:
102    FnMut(crate::Error) -> Result<(), E> + Sized
103{
104    /// Convert this type into an [`AdHocMutFallibleDropStrategy`].
105    fn into_drop_strategy(self) -> AdHocMutFallibleDropStrategy<Self, E> {
106        AdHocMutFallibleDropStrategy::new(self)
107    }
108}
109
110impl<T, E> IntoAdHocMutFallibleDropStrategy<E> for T
111where
112    T: FnMut(crate::Error) -> Result<(), E>,
113    E: Into<anyhow::Error>,
114{}
115
116#[cfg(test)]
117mod tests {
118    use std::sync::Arc;
119    use std::sync::atomic::AtomicBool;
120    use crate::drop_strategies::PanicDropStrategy;
121    use crate::{LOAD_ORDERING, STORE_ORDERING};
122    use crate::test_utils::fallible;
123    use super::*;
124
125    // we need this lock otherwise the test results will be inconsistent
126    static LOCK: Mutex<()> = parking_lot::const_mutex(());
127
128    #[test]
129    fn test_adhoc_mut_drop_strategy() {
130        let _lock = LOCK.lock();
131        let works = Arc::new(AtomicBool::new(false));
132        let w = Arc::clone(&works);
133        let strategy = AdHocMutDropStrategy::new(move |_| w.store(true, STORE_ORDERING));
134        crate::install_global_handlers(strategy, PanicDropStrategy::DEFAULT);
135        drop(fallible());
136        assert!(works.load(LOAD_ORDERING));
137    }
138
139    #[test]
140    fn test_into_adhoc_mut_drop_strategy() {
141        let _lock = LOCK.lock();
142        let works = Arc::new(AtomicBool::new(false));
143        let w = Arc::clone(&works);
144        let strategy = move |_| w.store(true, STORE_ORDERING);
145        let strategy = IntoAdHocMutDropStrategy::into_drop_strategy(strategy);
146        crate::install_global_handlers(strategy, PanicDropStrategy::DEFAULT);
147        drop(fallible());
148        assert!(works.load(LOAD_ORDERING));
149    }
150
151    #[test]
152    fn test_adhoc_mut_fallible_drop_strategy() {
153        let _lock = LOCK.lock();
154        let works = Arc::new(AtomicBool::new(false));
155        let w = Arc::clone(&works);
156        let strategy = AdHocMutFallibleDropStrategy::<_, crate::Error>::new(move |_| {
157            w.store(true, STORE_ORDERING);
158            Ok(())
159        });
160        crate::install_global_handlers(strategy, PanicDropStrategy::DEFAULT);
161        drop(fallible());
162        assert!(works.load(LOAD_ORDERING));
163    }
164
165    #[test]
166    fn test_into_adhoc_mut_fallible_drop_strategy() {
167        let _lock = LOCK.lock();
168        let works = Arc::new(AtomicBool::new(false));
169        let w = Arc::clone(&works);
170        let strategy = move |_| {
171            w.store(true, STORE_ORDERING);
172            Ok::<_, crate::Error>(())
173        };
174        let strategy = IntoAdHocMutFallibleDropStrategy::into_drop_strategy(strategy);
175        crate::install_global_handlers(strategy, PanicDropStrategy::DEFAULT);
176        drop(fallible());
177        assert!(works.load(LOAD_ORDERING));
178    }
179}