wlan_ffi_transport/
completers.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// Type that wraps a closure for completing an operation.
6///
7/// Calling `Completer::reply()` forwards the status to the wrapped closure. Otherwise,
8/// dropping a `Completer` indicates failure with a `zx::Status::BAD_STATE` status.
9pub struct Completer<F>
10where
11    F: FnOnce(zx::sys::zx_status_t),
12{
13    completer: Option<F>,
14}
15
16// SAFETY: It's safe to use Completer on any thread because the caller of the constructor
17// promises the inner completer is safe to send to another thread.
18unsafe impl<F> Send for Completer<F> where F: FnOnce(zx::sys::zx_status_t) {}
19
20impl<F> Completer<F>
21where
22    F: FnOnce(zx::sys::zx_status_t),
23{
24    /// # Safety
25    ///
26    /// Caller promises the provided completer is safe to send to another thread.
27    /// In some cases, providing a completer that implements Send is difficult.
28    /// For example, a closure that captures a pointer does not implement Send.
29    pub unsafe fn new_unchecked(completer: F) -> Self {
30        Self { completer: Some(completer) }
31    }
32
33    pub fn reply(mut self, status: Result<(), zx::Status>) {
34        let completer = match self.completer.take() {
35            None => unreachable!(),
36            Some(completer) => completer,
37        };
38        completer(zx::Status::from(status).into_raw())
39    }
40}
41
42impl<F> Completer<F>
43where
44    F: FnOnce(zx::sys::zx_status_t) + Send,
45{
46    pub fn new(completer: F) -> Self {
47        Self { completer: Some(completer) }
48    }
49}
50
51impl<F> Drop for Completer<F>
52where
53    F: FnOnce(zx::sys::zx_status_t),
54{
55    fn drop(&mut self) {
56        if let Some(completer) = self.completer.take() {
57            completer(zx::Status::BAD_STATE.into_raw())
58        }
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use futures::channel::oneshot;
66
67    #[test]
68    fn reply_with_ok() {
69        let (sender, mut receiver) = oneshot::channel::<zx::sys::zx_status_t>();
70        let completer = Completer::new(move |status| {
71            sender.send(status).expect("Failed to send result.");
72        });
73        completer.reply(Ok(()));
74        assert_eq!(Ok(Some(zx::Status::OK.into_raw())), receiver.try_recv());
75    }
76
77    #[test]
78    fn reply_with_error() {
79        let (sender, mut receiver) = oneshot::channel::<zx::sys::zx_status_t>();
80        let completer = Completer::new(move |status| {
81            sender.send(status).expect("Failed to send result.");
82        });
83        completer.reply(Err(zx::Status::NO_RESOURCES));
84        assert_eq!(Ok(Some(zx::Status::NO_RESOURCES.into_raw())), receiver.try_recv());
85    }
86
87    #[test]
88    fn reply_with_error_when_dropped() {
89        let (sender, mut receiver) = oneshot::channel::<zx::sys::zx_status_t>();
90        let completer = Completer::new(move |status| {
91            sender.send(status).expect("Failed to send result.");
92        });
93        drop(completer);
94        assert_eq!(Ok(Some(zx::Status::BAD_STATE.into_raw())), receiver.try_recv());
95    }
96}