Skip to main content

dope_core/driver/storage/
cleanup.rs

1use std::{convert, mem};
2
3use dope_sys::memory;
4
5use crate::{
6    Resources,
7    driver::{life::native::create, storage},
8};
9
10/// Construction failure that still owns backend resources requiring cleanup.
11pub struct Cleanup(State<Resources, create::Failure>);
12
13impl Cleanup {
14    pub(in crate::driver) fn new<S: Into<Resources>>(state: S) -> Self {
15        Self(State::new(state))
16    }
17
18    /// Retries in place; the native owner remains resident until cleanup succeeds.
19    pub fn try_close(
20        &mut self,
21        report: impl FnMut(storage::Failure),
22    ) -> Result<storage::Failure, storage::Failure> {
23        self.0
24            .try_close(report, storage::Failure::from, storage::Failure::from)
25    }
26
27    pub fn primary(&self) -> storage::Failure {
28        self.0.primary(storage::Failure::from)
29    }
30
31    /// No pending failure remains after terminal cleanup.
32    pub fn cleanup(&self) -> Option<storage::Failure> {
33        self.0.failure(storage::Failure::from)
34    }
35}
36
37/// The native owner and its terminal primary occupy mutually exclusive retry phases.
38pub(super) enum State<R, P> {
39    Owner(R),
40    Primary(P),
41}
42
43impl<R, P> State<R, P> {
44    pub(super) fn new<S: Into<R>>(state: S) -> Self {
45        Self::Owner(state.into())
46    }
47}
48
49impl<R: memory::Cleanup<P>, P: Copy> State<R, P> {
50    pub(super) fn try_close<T, E>(
51        &mut self,
52        mut report: impl FnMut(E),
53        primary: impl FnOnce(P) -> T,
54        failure: impl Fn(R::Error) -> E,
55    ) -> Result<T, E> {
56        let retained = self.primary(convert::identity);
57        match mem::replace(self, Self::Primary(retained)) {
58            Self::Primary(value) => Ok(primary(value)),
59            Self::Owner(owner) => match owner.try_close(|error| report(failure(error))) {
60                Ok(value) => {
61                    *self = Self::Primary(value);
62                    Ok(primary(value))
63                }
64                Err(owner) => {
65                    let error = owner.failure();
66                    *self = Self::Owner(owner);
67                    Err(failure(error))
68                }
69            },
70        }
71    }
72
73    pub(super) fn primary<T>(&self, map: impl FnOnce(P) -> T) -> T {
74        map(match self {
75            Self::Owner(owner) => owner.primary(),
76            Self::Primary(primary) => *primary,
77        })
78    }
79
80    pub(super) fn failure<E>(&self, map: impl FnOnce(R::Error) -> E) -> Option<E> {
81        match self {
82            Self::Owner(owner) => Some(map(owner.failure())),
83            Self::Primary(_) => None,
84        }
85    }
86}