Skip to main content

dope_core/io/
provided.rs

1use std::cell::Cell;
2use std::ptr::NonNull;
3use std::slice;
4
5use crate::driver::buffers::ProvidedBuffers;
6use crate::driver::{DriverContext, DriverRef};
7
8pub struct ProvidedLease<'d> {
9    driver: DriverRef<'d>,
10    bid: Cell<Option<u16>>,
11    ptr: NonNull<u8>,
12    len: usize,
13}
14
15pub struct ProvidedView<'d> {
16    _lease: ProvidedLease<'d>,
17    ptr: NonNull<u8>,
18    len: usize,
19}
20
21impl<'d> ProvidedLease<'d> {
22    /// # Safety
23    /// `bid` must be a uniquely owned live completion buffer. This call
24    /// transfers its ownership to the returned lease.
25    pub unsafe fn from_completion(driver: &mut DriverContext<'_, 'd>, len: u32, bid: u16) -> Self {
26        let reference = driver.driver_ref();
27        let (ptr, len) = unsafe { driver.buffer_ptr_len(len, bid) };
28        Self {
29            driver: reference,
30            bid: Cell::new(Some(bid)),
31            ptr,
32            len,
33        }
34    }
35
36    pub fn as_slice(&self) -> &[u8] {
37        unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
38    }
39
40    pub fn range_of(&self, bytes: &[u8]) -> Option<(usize, usize)> {
41        let base = self.ptr.as_ptr().addr();
42        let start = bytes.as_ptr().addr();
43        let offset = start.checked_sub(base)?;
44        (offset <= self.len && bytes.len() <= self.len - offset).then_some((offset, bytes.len()))
45    }
46
47    pub fn into_view(self, offset: usize, len: usize) -> ProvidedView<'d> {
48        assert!(offset <= self.len && len <= self.len - offset);
49        let ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) };
50        ProvidedView {
51            _lease: self,
52            ptr,
53            len,
54        }
55    }
56
57    /// Transfers buffer-return responsibility to a retained subrange.
58    ///
59    /// The completion buffer has one logical owner. This method moves that
60    /// ownership into the returned view without moving the lease value, which
61    /// permits receive values borrowing the buffer to be dropped first.
62    pub fn retained_view(&self, offset: usize, len: usize) -> ProvidedView<'d> {
63        assert!(offset <= self.len && len <= self.len - offset);
64        let bid = self
65            .bid
66            .take()
67            .expect("provided buffer ownership was already transferred");
68        let ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) };
69        ProvidedView {
70            _lease: Self {
71                driver: self.driver,
72                bid: Cell::new(Some(bid)),
73                ptr: self.ptr,
74                len: self.len,
75            },
76            ptr,
77            len,
78        }
79    }
80
81    pub fn release(&self, driver: &mut DriverContext<'_, 'd>) {
82        let _ = self.driver;
83        if let Some(bid) = self.bid.take() {
84            unsafe { driver.release(bid) };
85        }
86    }
87}
88
89impl AsRef<[u8]> for ProvidedLease<'_> {
90    fn as_ref(&self) -> &[u8] {
91        self.as_slice()
92    }
93}
94
95impl Drop for ProvidedLease<'_> {
96    fn drop(&mut self) {
97        if let Some(bid) = self.bid.take() {
98            self.driver.return_buffer(bid);
99        }
100    }
101}
102
103impl ProvidedView<'_> {
104    pub fn as_slice(&self) -> &[u8] {
105        unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
106    }
107
108    pub fn len(&self) -> usize {
109        self.len
110    }
111
112    pub fn is_empty(&self) -> bool {
113        self.len == 0
114    }
115
116    pub fn advance(&mut self, count: usize) {
117        assert!(
118            count <= self.len,
119            "dope: provided view advance out of bounds"
120        );
121        self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(count)) };
122        self.len -= count;
123    }
124}
125
126impl AsRef<[u8]> for ProvidedView<'_> {
127    fn as_ref(&self) -> &[u8] {
128        self.as_slice()
129    }
130}