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<(u64, usize), 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((v, len))) => {
63                assert_eq!(len, bytes.len(), "defer size mismatch");
64                bytes.copy_from_slice(&v.to_ne_bytes()[..len]);
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
86/// A deferred read operation.
87#[derive(Debug)]
88pub struct DeferredRead {
89    send: mesh::OneshotSender<Result<(u64, usize), IoError>>,
90}
91
92impl DeferredRead {
93    /// Completes the read operation with the specified data.
94    pub fn complete(self, bytes: &[u8]) {
95        let mut v = [0; 8];
96        v[..bytes.len()].copy_from_slice(bytes);
97        self.send.send(Ok((u64::from_ne_bytes(v), bytes.len())));
98    }
99
100    /// Completes the read operation with an error.
101    pub fn complete_error(self, error: IoError) {
102        self.send.send(Err(error));
103    }
104}
105
106/// A deferred write operation.
107#[derive(Debug)]
108pub struct DeferredWrite {
109    send: mesh::OneshotSender<Result<(u64, usize), IoError>>,
110}
111
112impl DeferredWrite {
113    /// Completes the write operation.
114    pub fn complete(self) {
115        self.send.send(Ok((0, 0)));
116    }
117
118    /// Completes the write operation with an error.
119    pub fn complete_error(self, error: IoError) {
120        self.send.send(Err(error));
121    }
122}
123
124/// Creates a deferred IO read operation.
125pub fn defer_read() -> (DeferredRead, DeferredToken) {
126    let (send, recv) = mesh::oneshot();
127    (
128        DeferredRead { send },
129        DeferredToken {
130            is_read: true,
131            recv,
132        },
133    )
134}
135
136/// Creates a deferred IO write operation.
137pub fn defer_write() -> (DeferredWrite, DeferredToken) {
138    let (send, recv) = mesh::oneshot();
139    (
140        DeferredWrite { send },
141        DeferredToken {
142            is_read: false,
143            recv,
144        },
145    )
146}