evering/
op.rs

1#![doc = include_str!("op.md")]
2
3use alloc::boxed::Box;
4use core::any::Any;
5use core::pin::Pin;
6use core::task::{Context, Poll};
7
8use crate::driver::{DriverHandle, OpId};
9
10/// # Safety
11///
12/// All submitted resources must be recycled.
13pub unsafe trait Completable: 'static + Unpin {
14    type Output;
15    type Driver: DriverHandle;
16
17    /// Transforms the received payload to the corresponding output.
18    ///
19    /// This function is called when the operation is completed, and the output
20    /// is then returned as [`Poll::Ready`].
21    fn complete(
22        self,
23        driver: &Self::Driver,
24        payload: <Self::Driver as DriverHandle>::Payload,
25    ) -> Self::Output;
26
27    /// Completes this operation with the submitted extension.
28    ///
29    /// For more information, see [`complete`](Self::complete).
30    fn complete_ext(
31        self,
32        driver: &Self::Driver,
33        payload: <Self::Driver as DriverHandle>::Payload,
34        ext: <Self::Driver as DriverHandle>::Ext,
35    ) -> Self::Output
36    where
37        Self: Sized,
38    {
39        _ = ext;
40        self.complete(driver, payload)
41    }
42
43    /// Cancels this operation.
44    fn cancel(self, driver: &Self::Driver) -> Cancellation;
45}
46
47pub struct Cancellation(#[allow(dead_code)] Option<Box<dyn Any>>);
48
49impl Cancellation {
50    pub const fn noop() -> Self {
51        Self(None)
52    }
53
54    pub fn recycle<T: 'static>(resource: T) -> Self {
55        Self(Some(Box::new(resource)))
56    }
57}
58
59pub struct Op<T: Completable> {
60    driver: T::Driver,
61    id: OpId,
62    data: Option<T>,
63}
64
65impl<T: Completable> Op<T> {
66    pub fn new(driver: T::Driver, id: OpId, data: T) -> Self {
67        Self {
68            driver,
69            id,
70            data: Some(data),
71        }
72    }
73}
74
75impl<T: Completable> Future for Op<T> {
76    type Output = T::Output;
77    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
78        self.driver.get().poll(self.id, cx).map(|(p, ext)| {
79            self.data
80                .take()
81                .expect("invalid operation state")
82                .complete_ext(&self.driver, p, ext)
83        })
84    }
85}
86
87impl<T: Completable> Drop for Op<T> {
88    fn drop(&mut self) {
89        self.driver.get().remove(self.id, || {
90            self.data
91                .take()
92                .expect("invalid operation state")
93                .cancel(&self.driver)
94        })
95    }
96}