Skip to main content

polyhorn_ios/raw/
queue.rs

1use dispatch::Queue;
2use std::mem::drop;
3use std::sync::{Arc, Mutex};
4
5/// Wraps an object that is bound to a specific libdispatch DispatchQueue. As a
6/// result, the wrapped object can only be accessed from the specified queue and
7/// will always be dropped from that queue (regardless of which thread the
8/// wrapper is dropped by).
9pub struct QueueBound<T>
10where
11    T: 'static,
12{
13    queue: Queue,
14    inner: Arc<Mutex<Option<InnerQueueBound<T>>>>,
15}
16
17impl<T> QueueBound<T>
18where
19    T: 'static,
20{
21    /// Returns a new queue bound wrapper around a value that is asynchronously
22    /// initialized using the given closure. The given closure is executed on
23    /// the given queue.
24    pub fn new<F>(queue: Queue, initializer: F) -> QueueBound<T>
25    where
26        F: FnOnce() -> T + Send + 'static,
27    {
28        let inner = Arc::new(Mutex::new(None));
29
30        queue.exec_async({
31            let inner = inner.clone();
32
33            move || {
34                inner
35                    .lock()
36                    .unwrap()
37                    .replace(InnerQueueBound(initializer()));
38            }
39        });
40
41        QueueBound { queue, inner }
42    }
43
44    /// Adopts a value that is assumed to already live on the given queue.
45    pub unsafe fn adopt(queue: Queue, value: T) -> QueueBound<T> {
46        let inner = Arc::new(Mutex::new(Some(InnerQueueBound(value))));
47
48        QueueBound { queue, inner }
49    }
50
51    /// Sends the given task to the queue and applies it to the value this
52    /// instance wraps.
53    pub fn with<F>(&self, task: F)
54    where
55        F: FnOnce(&mut T) + Send + 'static,
56    {
57        let inner = self.inner.clone();
58
59        self.queue.exec_async(move || {
60            if let Some(value) = inner.lock().unwrap().as_mut() {
61                task(&mut value.0);
62            }
63        })
64    }
65
66    /// Sends the given task and a value that is assumed to already live on the
67    /// this queue, to the queue and applies it to the value this instance
68    /// wraps.
69    pub unsafe fn with_adopt<F, V>(&self, value: V, task: F)
70    where
71        V: 'static,
72        F: FnOnce(&mut T, V) + Send + 'static,
73    {
74        let wrap = InnerQueueBound(value);
75        let inner = self.inner.clone();
76
77        self.queue.exec_async(move || {
78            if let Some(value) = inner.lock().unwrap().as_mut() {
79                task(&mut value.0, wrap.0);
80            }
81        });
82    }
83}
84
85impl<T> Drop for QueueBound<T>
86where
87    T: 'static,
88{
89    fn drop(&mut self) {
90        if let Some(value) = self.inner.lock().unwrap().take() {
91            self.queue.exec_async(move || drop(value));
92        }
93    }
94}
95
96struct InnerQueueBound<T>(T);
97
98unsafe impl<T> Send for InnerQueueBound<T> {}