Skip to main content

chipset_device/io/
deferred.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Support for deferred IO, used when an IO can't be completed synchronously.
5//!
6//! Example:
7//!
8//! ```rust
9//! # use chipset_device::io::{IoResult, deferred::{DeferredRead, defer_read}};
10//! # use std::task::Context;
11//! struct Device {
12//!     deferred: Option<DeferredRead>,
13//! }
14//!
15//! impl Device {
16//!     fn read_handler(&mut self, data: &mut [u8]) -> IoResult {
17//!         // Defer this request to later.
18//!         let (deferred, token) = defer_read();
19//!         IoResult::Defer(token.into())
20//!     }
21//!
22//!     fn poll_device(&mut self, _cx: &mut Context<'_>) {
23//!         // The data is now available, complete the request.
24//!         if let Some(deferred) = self.deferred.take() {
25//!             deferred.complete(&[123]);
26//!         }
27//!     }
28//! }
29//! ```
30
31use crate::io::IoError;
32use std::future::Future;
33use std::pin::Pin;
34use std::task::Context;
35use std::task::Poll;
36use std::task::ready;
37
38/// Token to return in [`IoResult::Defer`](super::IoResult::Defer) for deferred
39/// IOs.
40///
41/// Create with [`defer_read`] or [`defer_write`].
42#[derive(Debug)]
43pub struct DeferredToken {
44    is_read: bool,
45    recv: mesh::OneshotReceiver<Result<Box<[u8]>, IoError>>,
46}
47
48impl DeferredToken {
49    /// Polls the deferred token for the results of a read operation.
50    ///
51    /// Copies the results into `bytes`.
52    ///
53    /// Panics if the deferred token was for a write operation.
54    pub fn poll_read(
55        &mut self,
56        cx: &mut Context<'_>,
57        bytes: &mut [u8],
58    ) -> Poll<Result<(), IoError>> {
59        assert!(self.is_read, "defer type mismatch");
60        let r = ready!(Pin::new(&mut self.recv).poll(cx));
61        match r {
62            Ok(Ok(data)) => {
63                assert_eq!(data.len(), bytes.len(), "defer size mismatch");
64                bytes.copy_from_slice(&data);
65                Poll::Ready(Ok(()))
66            }
67            Ok(Err(e)) => Poll::Ready(Err(e)),
68            Err(_) => Poll::Ready(Err(IoError::NoResponse)),
69        }
70    }
71
72    /// Polls the deferred token for the results of a write operation.
73    ///
74    /// Panics if the deferred token was for a read operation.
75    pub fn poll_write(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), IoError>> {
76        assert!(!self.is_read, "defer type mismatch");
77        let r = ready!(Pin::new(&mut self.recv).poll(cx));
78        match r {
79            Ok(Ok(_)) => Poll::Ready(Ok(())),
80            Ok(Err(e)) => Poll::Ready(Err(e)),
81            Err(_) => Poll::Ready(Err(IoError::NoResponse)),
82        }
83    }
84
85    /// Returns a future that waits for the deferred write to complete.
86    ///
87    /// Panics if the deferred token was for a read operation.
88    pub async fn write_future(mut self) -> Result<(), IoError> {
89        std::future::poll_fn(|cx| self.poll_write(cx)).await
90    }
91
92    /// Returns a future that waits for the deferred read to complete, and
93    /// copies the results into `bytes`.
94    ///
95    /// Panics if the deferred token was for a write operation.
96    pub async fn read_future(mut self, bytes: &mut [u8]) -> Result<(), IoError> {
97        std::future::poll_fn(|cx| self.poll_read(cx, bytes)).await
98    }
99}
100
101/// A deferred read operation.
102#[derive(Debug)]
103pub struct DeferredRead {
104    send: mesh::OneshotSender<Result<Box<[u8]>, IoError>>,
105}
106
107impl DeferredRead {
108    /// Completes the read operation with the specified data.
109    pub fn complete(self, bytes: &[u8]) {
110        self.send.send(Ok(bytes.into()));
111    }
112
113    /// Completes the read operation with an error.
114    pub fn complete_error(self, error: IoError) {
115        self.send.send(Err(error));
116    }
117}
118
119/// A deferred write operation.
120#[derive(Debug)]
121pub struct DeferredWrite {
122    send: mesh::OneshotSender<Result<Box<[u8]>, IoError>>,
123}
124
125impl DeferredWrite {
126    /// Completes the write operation.
127    pub fn complete(self) {
128        self.send.send(Ok(Box::default()));
129    }
130
131    /// Completes the write operation with an error.
132    pub fn complete_error(self, error: IoError) {
133        self.send.send(Err(error));
134    }
135}
136
137/// Creates a deferred IO read operation.
138pub fn defer_read() -> (DeferredRead, DeferredToken) {
139    let (send, recv) = mesh::oneshot();
140    (
141        DeferredRead { send },
142        DeferredToken {
143            is_read: true,
144            recv,
145        },
146    )
147}
148
149/// Creates a deferred IO write operation.
150pub fn defer_write() -> (DeferredWrite, DeferredToken) {
151    let (send, recv) = mesh::oneshot();
152    (
153        DeferredWrite { send },
154        DeferredToken {
155            is_read: false,
156            recv,
157        },
158    )
159}