sfio_promise/
lib.rs

1//! Helpers types and functions for making oo-bindgen future interfaces drop-safe.
2#![deny(
3    dead_code,
4    arithmetic_overflow,
5    invalid_type_param_default,
6    missing_fragment_specifier,
7    mutable_transmutes,
8    no_mangle_const_items,
9    overflowing_literals,
10    patterns_in_fns_without_body,
11    pub_use_of_private_extern_crate,
12    unknown_crate_types,
13    order_dependent_trait_objects,
14    illegal_floating_point_literal_pattern,
15    improper_ctypes,
16    late_bound_lifetime_arguments,
17    non_camel_case_types,
18    non_shorthand_field_patterns,
19    non_snake_case,
20    non_upper_case_globals,
21    no_mangle_generic_items,
22    private_in_public,
23    stable_features,
24    type_alias_bounds,
25    tyvar_behind_raw_pointer,
26    unconditional_recursion,
27    unused_comparisons,
28    unreachable_pub,
29    anonymous_parameters,
30    missing_copy_implementations,
31    missing_debug_implementations,
32    missing_docs,
33    trivial_casts,
34    trivial_numeric_casts,
35    unused_import_braces,
36    unused_qualifications,
37    clippy::all
38)]
39#![forbid(
40    unsafe_code,
41    rustdoc::broken_intra_doc_links,
42    unaligned_references,
43    while_true,
44    bare_trait_objects
45)]
46
47/// Types convertible to a Promise must implement this type
48pub trait FutureType<V> {
49    /// The value that will be returned if a Promise of this type is dropped without being completed
50    fn on_drop() -> V;
51
52    /// Complete the future with the specified value
53    fn complete(self, result: V);
54}
55
56/// A Promise is a type that is guaranteed to complete its underlying FutureType,
57/// even if it is dropped.
58#[derive(Debug)]
59pub struct Promise<T, V>
60where
61    T: FutureType<V>,
62{
63    inner: Option<T>,
64    _v: std::marker::PhantomData<V>,
65}
66
67impl<T, V> Promise<T, V>
68where
69    T: FutureType<V>,
70{
71    /// Construct a promise from a FutureType
72    fn new(inner: T) -> Self {
73        Self {
74            inner: Some(inner),
75            _v: Default::default(),
76        }
77    }
78
79    /// Complete the promise, consuming it
80    pub fn complete(mut self, result: V) {
81        if let Some(x) = self.inner.take() {
82            x.complete(result);
83        }
84    }
85}
86
87/// Wrap a type that implements FutureType into a drop-safe promise
88pub fn wrap<T, V>(callback: T) -> Promise<T, V>
89where
90    T: FutureType<V>,
91{
92    Promise::new(callback)
93}
94
95impl<T, V> Drop for Promise<T, V>
96where
97    T: FutureType<V>,
98{
99    fn drop(&mut self) {
100        if let Some(cb) = self.inner.take() {
101            cb.complete(T::on_drop());
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    struct Borrowed<'a> {
111        vec: &'a mut Vec<Result<u32, &'static str>>,
112    }
113
114    impl<'a> FutureType<Result<u32, &'static str>> for Borrowed<'a> {
115        fn on_drop() -> Result<u32, &'static str> {
116            Err("dropped")
117        }
118
119        fn complete(self, result: Result<u32, &'static str>) {
120            self.vec.push(result);
121        }
122    }
123
124    #[test]
125    fn completes_on_drop() {
126        let mut output = Vec::new();
127        let _ = wrap(Borrowed { vec: &mut output });
128        assert_eq!(output.as_slice(), [Err("dropped")]);
129    }
130
131    #[test]
132    fn only_completes_once_on_success() {
133        let mut output = Vec::new();
134        let promise = wrap(Borrowed { vec: &mut output });
135        promise.complete(Ok(42));
136        assert_eq!(output.as_slice(), [Ok(42)]);
137    }
138
139    #[test]
140    fn only_completes_once_on_failure() {
141        let mut output = Vec::new();
142        let promise = wrap(Borrowed { vec: &mut output });
143        promise.complete(Err("fail"));
144        assert_eq!(output.as_slice(), [Err("fail")]);
145    }
146}