1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use crate::{protocol, types::ShortUInt, Promise};
use log::warn;
use std::ops::Deref;

#[derive(Debug)]
pub struct CloseOnDrop<T: __private::Closable> {
    inner: Option<T>,
}

impl<T: __private::Closable> CloseOnDrop<T> {
    pub fn new(inner: T) -> Self {
        Self { inner: Some(inner) }
    }

    /// Give the underlying object, cancelling the close on drop action
    pub fn into_inner(mut self) -> T {
        let inner = self
            .inner
            .take()
            .expect("inner should only be None once consumed or dropped");
        std::mem::forget(self);
        inner
    }

    pub fn close(self, reply_code: ShortUInt, reply_text: &str) -> Promise<()> {
        self.into_inner().close(reply_code, reply_text)
    }
}

impl<T: __private::Closable> Deref for CloseOnDrop<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.inner
            .as_ref()
            .expect("inner should only be None once consumed or dropped")
    }
}

impl<T: __private::Closable> Drop for CloseOnDrop<T> {
    fn drop(&mut self) {
        if let Some(inner) = self.inner.as_ref() {
            if let Err(err) = inner
                .close(protocol::constants::REPLY_SUCCESS.into(), "OK")
                .wait()
            {
                warn!("Failed to close on drop: {:?}", err);
            }
        }
    }
}

pub(crate) mod __private {
    use super::*;

    pub trait Closable {
        fn close(&self, reply_code: ShortUInt, reply_text: &str) -> Promise<()>;
    }
}