libsql_wal/io/
buf.rs

1// from tokio uring
2
3use std::mem::{size_of, MaybeUninit};
4
5use bytes::BytesMut;
6use zerocopy::{AsBytes, FromBytes};
7
8pub unsafe trait IoBuf: Unpin + 'static {
9    /// Returns a raw pointer to the vector’s buffer.
10    ///
11    /// This method is to be used by the `tokio-uring` runtime and it is not
12    /// expected for users to call it directly.
13    ///
14    /// The implementation must ensure that, while the `tokio-uring` runtime
15    /// owns the value, the pointer returned by `stable_ptr` **does not**
16    /// change.
17    fn stable_ptr(&self) -> *const u8;
18
19    /// Number of initialized bytes.
20    ///
21    /// This method is to be used by the `tokio-uring` runtime and it is not
22    /// expected for users to call it directly.
23    ///
24    /// For `Vec`, this is identical to `len()`.
25    fn bytes_init(&self) -> usize;
26
27    /// Total size of the buffer, including uninitialized memory, if any.
28    ///
29    /// This method is to be used by the `tokio-uring` runtime and it is not
30    /// expected for users to call it directly.
31    ///
32    /// For `Vec`, this is identical to `capacity()`.
33    fn bytes_total(&self) -> usize;
34}
35
36/// A mutable`io-uring` compatible buffer.
37///
38/// The `IoBufMut` trait is implemented by buffer types that can be passed to
39/// io-uring operations. Users will not need to use this trait directly.
40///
41/// # Safety
42///
43/// Buffers passed to `io-uring` operations must reference a stable memory
44/// region. While the runtime holds ownership to a buffer, the pointer returned
45/// by `stable_mut_ptr` must remain valid even if the `IoBufMut` value is moved.
46pub unsafe trait IoBufMut: IoBuf {
47    /// Returns a raw mutable pointer to the vector’s buffer.
48    ///
49    /// This method is to be used by the `tokio-uring` runtime and it is not
50    /// expected for users to call it directly.
51    ///
52    /// The implementation must ensure that, while the `tokio-uring` runtime
53    /// owns the value, the pointer returned by `stable_mut_ptr` **does not**
54    /// change.
55    fn stable_mut_ptr(&mut self) -> *mut u8;
56
57    /// Updates the number of initialized bytes.
58    ///
59    /// The specified `pos` becomes the new value returned by
60    /// `IoBuf::bytes_init`.
61    ///
62    /// # Safety
63    ///
64    /// The caller must ensure that all bytes starting at `stable_mut_ptr()` up
65    /// to `pos` are initialized and owned by the buffer.
66    unsafe fn set_init(&mut self, pos: usize);
67}
68
69unsafe impl<T: IoBufMut> IoBufMut for Box<T> {
70    fn stable_mut_ptr(&mut self) -> *mut u8 {
71        self.as_mut().stable_mut_ptr()
72    }
73
74    unsafe fn set_init(&mut self, pos: usize) {
75        self.as_mut().set_init(pos)
76    }
77}
78
79unsafe impl IoBuf for BytesMut {
80    fn stable_ptr(&self) -> *const u8 {
81        self.as_ptr()
82    }
83
84    fn bytes_init(&self) -> usize {
85        self.len()
86    }
87
88    fn bytes_total(&self) -> usize {
89        self.capacity()
90    }
91}
92
93unsafe impl IoBufMut for BytesMut {
94    fn stable_mut_ptr(&mut self) -> *mut u8 {
95        self.as_mut_ptr()
96    }
97
98    unsafe fn set_init(&mut self, pos: usize) {
99        unsafe { self.set_len(pos) }
100    }
101}
102
103unsafe impl<T: IoBuf> IoBuf for Box<T> {
104    fn stable_ptr(&self) -> *const u8 {
105        self.as_ref().stable_ptr()
106    }
107
108    fn bytes_init(&self) -> usize {
109        self.as_ref().bytes_init()
110    }
111
112    fn bytes_total(&self) -> usize {
113        self.as_ref().bytes_total()
114    }
115}
116
117pub struct ZeroCopyBuf<T> {
118    init: usize,
119    inner: MaybeUninit<T>,
120}
121
122pub struct ZeroCopyBoxIoBuf<T> {
123    inner: Box<T>,
124    init: usize,
125}
126
127impl<T> ZeroCopyBoxIoBuf<T> {
128    pub fn new(inner: Box<T>) -> Self {
129        Self {
130            init: size_of::<T>(),
131            inner,
132        }
133    }
134
135    pub fn new_uninit(inner: Box<T>) -> Self {
136        Self { init: 0, inner }
137    }
138
139    fn is_init(&self) -> bool {
140        self.init == size_of::<T>()
141    }
142
143    pub fn into_inner(self) -> Box<T> {
144        assert!(self.is_init());
145        self.inner
146    }
147}
148
149unsafe impl<T: AsBytes + Unpin + 'static> IoBuf for ZeroCopyBoxIoBuf<T> {
150    fn stable_ptr(&self) -> *const u8 {
151        T::as_bytes(&self.inner).as_ptr()
152    }
153
154    fn bytes_init(&self) -> usize {
155        self.init
156    }
157
158    fn bytes_total(&self) -> usize {
159        size_of::<T>()
160    }
161}
162
163unsafe impl<T: AsBytes + FromBytes + Unpin + 'static> IoBufMut for ZeroCopyBoxIoBuf<T> {
164    fn stable_mut_ptr(&mut self) -> *mut u8 {
165        T::as_bytes_mut(&mut self.inner).as_mut_ptr()
166    }
167
168    unsafe fn set_init(&mut self, pos: usize) {
169        self.init = pos;
170    }
171}
172
173impl<T> ZeroCopyBuf<T> {
174    pub fn new_init(inner: T) -> Self {
175        Self {
176            inner: MaybeUninit::new(inner),
177            init: size_of::<T>(),
178        }
179    }
180
181    pub fn new_uninit() -> Self {
182        Self {
183            init: 0,
184            inner: MaybeUninit::uninit(),
185        }
186    }
187
188    pub fn map_slice<F>(self, f: F) -> MapSlice<T, F>
189    where
190        for<'a> F: Fn(&'a Self) -> &'a [u8] + Unpin + 'static,
191    {
192        MapSlice { inner: self, f }
193    }
194
195    #[inline]
196    pub fn is_init(&self) -> bool {
197        self.init == size_of::<T>()
198    }
199
200    /// returns a ref to the inner type
201    /// # Panic
202    /// panics if the inner type is uninitialized
203    pub fn get_ref(&self) -> &T {
204        assert!(self.is_init());
205        unsafe { self.inner.assume_init_ref() }
206    }
207
208    pub fn get_mut(&mut self) -> &mut T {
209        assert!(self.is_init());
210        unsafe { self.inner.assume_init_mut() }
211    }
212
213    pub fn into_inner(self) -> T {
214        assert!(self.is_init());
215        unsafe { self.inner.assume_init() }
216    }
217
218    pub fn deinit(&mut self) {
219        self.init = 0;
220    }
221}
222
223pub struct MapSlice<T, F> {
224    inner: ZeroCopyBuf<T>,
225    f: F,
226}
227
228impl<T, F> MapSlice<T, F> {
229    pub(crate) fn into_inner(self) -> ZeroCopyBuf<T> {
230        self.inner
231    }
232}
233
234unsafe impl<T, F> IoBuf for MapSlice<T, F>
235where
236    for<'a> F: Fn(&'a ZeroCopyBuf<T>) -> &'a [u8] + Unpin + 'static,
237    T: Unpin + 'static + AsBytes,
238{
239    fn stable_ptr(&self) -> *const u8 {
240        (self.f)(&self.inner).as_ptr()
241    }
242
243    fn bytes_init(&self) -> usize {
244        (self.f)(&self.inner).len()
245    }
246
247    fn bytes_total(&self) -> usize {
248        (self.f)(&self.inner).len()
249    }
250}
251
252unsafe impl<T: AsBytes + Unpin + 'static> IoBuf for ZeroCopyBuf<T> {
253    fn stable_ptr(&self) -> *const u8 {
254        self.inner.as_ptr() as *const _
255    }
256
257    fn bytes_init(&self) -> usize {
258        self.init
259    }
260
261    fn bytes_total(&self) -> usize {
262        size_of::<T>()
263    }
264}
265
266unsafe impl<T: AsBytes + Unpin + 'static> IoBufMut for ZeroCopyBuf<T> {
267    fn stable_mut_ptr(&mut self) -> *mut u8 {
268        self.inner.as_mut_ptr() as *mut _
269    }
270
271    unsafe fn set_init(&mut self, pos: usize) {
272        assert!(pos <= size_of::<T>());
273        self.init = pos
274    }
275}
276
277unsafe impl IoBufMut for Vec<u8> {
278    fn stable_mut_ptr(&mut self) -> *mut u8 {
279        self.as_mut_ptr()
280    }
281
282    unsafe fn set_init(&mut self, init_len: usize) {
283        if self.len() < init_len {
284            self.set_len(init_len);
285        }
286    }
287}
288
289unsafe impl IoBuf for Vec<u8> {
290    fn stable_ptr(&self) -> *const u8 {
291        self.as_ptr()
292    }
293
294    fn bytes_init(&self) -> usize {
295        self.len()
296    }
297
298    fn bytes_total(&self) -> usize {
299        self.capacity()
300    }
301}