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}