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
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//! This module provides wrapper for types that cannot be dropped silently.
//! Usually such types are required to be returned to their creator,
//! for example many Vulkan resources must be destroyed by the same
//! Vulkan instance that created them.  Because they need some outside
//! context to be destroyed, Rust's `Drop` trait alone cannot handle them.
//! The `Escape` wrapper helps the user handle these values by sending the
//! underlying value to a `Terminal` when it is dropped.  The user can
//! then remove those values from the `Terminal` elsewhere in the program
//! and destroy them however necessary.
//!
//! Users are encouraged to dispose of values manually while using `Escape`
//! as just a safety net.

use {
    crossbeam_channel::{Receiver, Sender, TryRecvError},
    std::{
        iter::repeat,
        mem::ManuallyDrop,
        ops::{Deref, DerefMut},
        ptr::{drop_in_place, read},
        sync::Arc,
    },
};

/// Allows values to "escape" dropping by sending them to the `Terminal`.
#[derive(Debug)]
pub struct Escape<T> {
    value: ManuallyDrop<T>,
    sender: Sender<T>,
}

impl<T> Escape<T> {
    /// Escape value.
    pub fn escape(value: T, terminal: &Terminal<T>) -> Self {
        Escape {
            value: ManuallyDrop::new(value),
            sender: Sender::clone(&terminal.sender),
        }
    }

    /// Unwrap escaping value.
    /// This will effectivly prevent it from escaping.
    pub fn unescape(escape: Self) -> T {
        unsafe {
            // Prevent `<Escape<T> as Drop>::drop` from being executed.
            let mut escape = ManuallyDrop::new(escape);

            // Release value from `ManuallyDrop`.
            let value = read(&mut *escape.value);

            // Drop sender. If it panics - value will be dropped.
            // Relevant values are allowed to be dropped due to panic.
            drop_in_place(&mut escape.sender);
            value
        }
    }

    /// Share escaped value.
    pub fn share(escape: Self) -> Handle<T> {
        escape.into()
    }
}

impl<T> Deref for Escape<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &*self.value
    }
}

impl<T> DerefMut for Escape<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut *self.value
    }
}

impl<T> Drop for Escape<T> {
    fn drop(&mut self) {
        unsafe {
            // Read value from `ManuallyDrop` wrapper and send it over the channel.
            match self.sender.send(read(&mut *self.value)) {
                Ok(_) => {}
                Err(_) => {
                    log::error!("`Escape` was dropped after a `Terminal`?");
                }
            }
        }
    }
}

/// This types allows the user to create `Escape` wrappers.
/// Receives values from dropped `Escape` instances that was created by this `Terminal`.
#[derive(Debug)]
pub struct Terminal<T> {
    receiver: Receiver<T>,
    sender: ManuallyDrop<Sender<T>>,
}

impl<T> Default for Terminal<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T> Terminal<T> {
    /// Create new `Terminal`.
    pub fn new() -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        Terminal {
            sender: ManuallyDrop::new(sender),
            receiver,
        }
    }

    /// Wrap the value. It will be yielded by iterator returned by `Terminal::drain` if `Escape` will be dropped.
    pub fn escape(&self, value: T) -> Escape<T> {
        Escape::escape(value, &self)
    }

    // /// Check if `Escape` will send value to this `Terminal`.
    // pub fn owns(&self, escape: &Escape<T>) -> bool {
    //     *self.sender == escape.sender
    // }

    /// Get iterator over values from dropped `Escape` instances that was created by this `Terminal`.
    pub fn drain(&mut self) -> impl Iterator<Item = T> + '_ {
        repeat(()).scan(&mut self.receiver, move |receiver, ()| {
            // trace!("Drain escape");
            if !receiver.is_empty() {
                receiver.recv().ok()
            } else {
                None
            }
        })
    }
}

impl<T> Drop for Terminal<T> {
    fn drop(&mut self) {
        unsafe {
            ManuallyDrop::drop(&mut self.sender);
            match self.receiver.try_recv() {
                Err(TryRecvError::Disconnected) => {}
                _ => {
                    log::error!("Terminal must be dropped after all `Escape`s");
                }
            }
        }
    }
}

/// Allows values to "escape" dropping by sending them to the `Terminal`.
/// Permit sharing unlike [`Escape`]
///
/// [`Escape`]: ./struct.Escape.html
#[derive(Debug)]
pub struct Handle<T> {
    inner: Arc<Escape<T>>,
}

impl<T> Clone for Handle<T> {
    fn clone(&self) -> Self {
        Handle {
            inner: self.inner.clone(),
        }
    }
}

impl<T> From<Escape<T>> for Handle<T> {
    fn from(value: Escape<T>) -> Self {
        Handle {
            inner: Arc::new(value),
        }
    }
}

impl<T> Deref for Handle<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &**self.inner
    }
}