Skip to main content

io_buffer/
buffer.rs

1use super::utils::{safe_copy, set_zero};
2use libc::{c_void, free, malloc, posix_memalign};
3use nix::errno::Errno;
4use std::slice;
5use std::{
6    fmt,
7    ops::{Deref, DerefMut},
8    ptr::{NonNull, null_mut},
9};
10
11/// # Buffer
12///
13/// Buffer is a static type, buffer wrapper without lifecycle,
14/// built for [io-engine crate](https://docs.rs/io-engine).
15/// Erase the lifecycle and type for io-uring or libaio.
16///
17/// Memory footprint is only 16B.
18///
19/// # Limitation
20///
21/// size and cap (max to i32)
22///
23/// # Usage
24///
25/// - [Buffer::alloc()]: malloc() a owned buffer (uninitialized, mutable),
26///
27/// - [Buffer::aligned()]: posix_memalign() a owned buffer (uninitialized, mutable),
28///
29/// - [Buffer::from_c_ref_const]: Reference a raw pointer from c code (not owned, immutable),
30///
31/// - [Buffer::from_c_ref_mut]: Reference a raw pointer from c code (not owned, mmutable),
32///
33/// - convert `Buffer::From<Vec<u8>>` (mutable and owned),
34///
35/// - convert `InTo<Vec<u8>>`
36///
37/// - When Clone, will copy the content into a newly "malloc" allocated Buffer. (not aligned)
38#[repr(C)]
39pub struct Buffer {
40    buf_ptr: NonNull<c_void>,
41    /// the highest bit of `size` represents `owned`
42    pub(crate) size: u32,
43    /// the highest bit of `cap` represents `mutable`
44    pub(crate) cap: u32,
45}
46
47impl fmt::Debug for Buffer {
48    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49        write!(f, "buffer {:p} size {}", self.get_raw(), self.len())
50    }
51}
52
53unsafe impl Send for Buffer {}
54
55unsafe impl Sync for Buffer {}
56
57pub const MIN_ALIGN: u32 = 512;
58pub const MAX_BUFFER_SIZE: u32 = 1 << 31;
59
60fn is_aligned(offset: usize, size: usize) -> bool {
61    (offset & (MIN_ALIGN as usize - 1) == 0) && (size & (MIN_ALIGN as usize - 1) == 0)
62}
63
64impl Buffer {
65    /// Allocate mutable and owned aligned buffer for aio by posix_memalign(),
66    /// with size set to capacity.
67    ///
68    /// **NOTE**: Be aware that buffer allocated is not initialized.
69    ///
70    /// `size`: must be larger than zero
71    #[inline]
72    pub fn aligned(size: i32) -> Result<Buffer, Errno> {
73        let mut _buf = Self::_alloc(MIN_ALIGN, size)?;
74        #[cfg(all(feature = "fail", feature = "rand"))]
75        fail::fail_point!("alloc_buf", |_| {
76            rand_buffer(&mut _buf);
77            return Ok(_buf);
78        });
79        Ok(_buf)
80    }
81
82    /// Allocate mutable and owned aligned buffer for aio by posix_memalign(),
83    /// with size set to capacity.
84    ///
85    /// **NOTE**: Be aware that buffer allocated is not initialized.
86    ///
87    /// `size`: must be larger than zero
88    ///
89    /// `align`: normally 512 or 4096
90    #[inline]
91    pub fn aligned_by(size: i32, align: u32) -> Result<Buffer, Errno> {
92        let mut _buf = Self::_alloc(align, size)?;
93        #[cfg(all(feature = "fail", feature = "rand"))]
94        fail::fail_point!("alloc_buf", |_| {
95            rand_buffer(&mut _buf);
96            return Ok(_buf);
97        });
98        Ok(_buf)
99    }
100
101    /// Allocate mutable and owned non-aligned Buffer by malloc(),
102    /// with size set to capacity.
103    ///
104    /// **NOTE**: Be aware that buffer allocated is not initialized.
105    ///
106    /// `size`: must be larger than zero
107    #[inline]
108    pub fn alloc(size: i32) -> Result<Buffer, Errno> {
109        let mut _buf = Self::_alloc(0, size)?;
110        #[cfg(all(feature = "fail", feature = "rand"))]
111        fail::fail_point!("alloc_buf", |_| {
112            rand_buffer(&mut _buf);
113            return Ok(_buf);
114        });
115        Ok(_buf)
116    }
117
118    /// Allocate a buffer.
119    ///
120    /// `size`: must be larger than zero
121    #[inline]
122    fn _alloc(align: u32, size: i32) -> Result<Self, Errno> {
123        assert!(size > 0);
124        let mut ptr: *mut c_void = null_mut();
125        if align > 0 {
126            debug_assert!((align & (MIN_ALIGN - 1)) == 0);
127            debug_assert!((size as u32 & (align - 1)) == 0);
128            unsafe {
129                let res = posix_memalign(&mut ptr, align as libc::size_t, size as libc::size_t);
130                if res != 0 {
131                    return Err(Errno::ENOMEM);
132                }
133            }
134        } else {
135            ptr = unsafe { malloc(size as libc::size_t) };
136            if ptr.is_null() {
137                return Err(Errno::ENOMEM);
138            }
139        }
140        // owned == true
141        let _size = size as u32 | MAX_BUFFER_SIZE;
142        // mutable == true
143        let _cap = _size;
144        Ok(Self { buf_ptr: unsafe { NonNull::new_unchecked(ptr) }, size: _size, cap: _cap })
145    }
146
147    /// make a imutable reference from current buffer
148    ///
149    /// A convenient method for from_c_ref_const() with buffer referencing the pointer of self
150    ///
151    /// # Safety
152    ///
153    /// Will not free on drop. You have to ensure the buffer valid throughout the lifecycle
154    pub unsafe fn make_ref_const(&self) -> Self {
155        // owned == false
156        // mutable == false
157        Self {
158            buf_ptr: self.buf_ptr,
159            size: self.size ^ MAX_BUFFER_SIZE,
160            cap: self.cap ^ MAX_BUFFER_SIZE,
161        }
162    }
163
164    /// Force a reference buffer to owned & muttable buffer, so that it will free the memory on drop
165    ///
166    /// # Safety
167    ///
168    /// You have to make sure the original owned buffer is forgotten.
169    ///
170    /// Useful to implement COW logic
171    #[inline]
172    pub unsafe fn force_owned(&mut self) {
173        // set the own flag
174        self.size |= MAX_BUFFER_SIZE;
175        self.cap |= MAX_BUFFER_SIZE;
176    }
177
178    /// Wrap a mutable buffer passed from c code, without owner ship.
179    ///
180    /// `size`: must be larger than or equal to zero.
181    ///
182    /// # Safety
183    ///
184    /// Will not free on drop. You have to ensure the buffer valid throughout the lifecycle.
185    #[inline]
186    pub unsafe fn from_c_ref_mut(ptr: *mut c_void, size: i32) -> Self {
187        assert!(size >= 0);
188        assert!(!ptr.is_null());
189        // owned == false
190        // mutable == true
191        let _cap = size as u32 | MAX_BUFFER_SIZE;
192        Self { buf_ptr: unsafe { NonNull::new_unchecked(ptr) }, size: size as u32, cap: _cap }
193    }
194
195    /// Wrap a const buffer passed from c code, without owner ship.
196    ///
197    /// `size`: must be larger than or equal to zero.
198    ///
199    /// # Safety
200    ///
201    /// Will not free on drop. You have to ensure the buffer valid throughout the lifecycle
202    #[inline]
203    pub unsafe fn from_c_ref_const(ptr: *const c_void, size: i32) -> Self {
204        assert!(size >= 0);
205        assert!(!ptr.is_null());
206        // owned == false
207        // mutable == false
208        Self {
209            buf_ptr: unsafe { NonNull::new_unchecked(ptr as *mut c_void) },
210            size: size as u32,
211            cap: size as u32,
212        }
213    }
214
215    /// Tell whether the Buffer has true 'static lifetime.
216    #[inline(always)]
217    pub fn is_owned(&self) -> bool {
218        self.size & (MAX_BUFFER_SIZE) != 0
219    }
220
221    /// Tell whether the Buffer can as_mut().
222    #[inline(always)]
223    pub fn is_mutable(&self) -> bool {
224        self.cap & (MAX_BUFFER_SIZE) != 0
225    }
226
227    /// Return the buffer's size.
228    #[inline(always)]
229    pub fn len(&self) -> usize {
230        let size = self.size & (MAX_BUFFER_SIZE - 1);
231        size as usize
232    }
233
234    /// Return the memory capacity managed by buffer's ptr
235    #[inline(always)]
236    pub fn capacity(&self) -> usize {
237        let cap = self.cap & (MAX_BUFFER_SIZE - 1);
238        cap as usize
239    }
240
241    /// Change the buffer's size, the same as `Vec::set_len()`. Panics when len > capacity
242    #[inline(always)]
243    pub fn set_len(&mut self, len: usize) {
244        assert!(
245            len < MAX_BUFFER_SIZE as usize,
246            "size {} >= {} is not supported",
247            len,
248            MAX_BUFFER_SIZE
249        );
250        assert!(len <= self.cap as usize, "size {} must be <= {}", len, self.cap);
251        let owned: u32 = self.size & MAX_BUFFER_SIZE;
252        self.size = owned | len as u32;
253    }
254
255    #[inline(always)]
256    fn _as_ref(&self) -> &[u8] {
257        unsafe { slice::from_raw_parts(self.buf_ptr.as_ptr() as *const u8, self.len()) }
258    }
259
260    /// On debug mode, will panic if the Buffer is not owned [Buffer::from_c_ref_const()]
261    ///
262    /// On release will skip the check for speed.
263    #[inline(always)]
264    fn _as_mut(&mut self) -> &mut [u8] {
265        #[cfg(debug_assertions)]
266        {
267            if !self.is_mutable() {
268                panic!("Cannot change a mutable buffer")
269            }
270        }
271        unsafe { slice::from_raw_parts_mut(self.buf_ptr.as_ptr() as *mut u8, self.len()) }
272    }
273
274    /// Check this buffer usable by aio. True when get from `Buffer::aligned()`.
275    #[inline(always)]
276    pub fn is_aligned(&self) -> bool {
277        is_aligned(self.buf_ptr.as_ptr() as usize, self.capacity())
278    }
279
280    /// Get buffer raw pointer
281    #[inline]
282    pub fn get_raw(&self) -> *const u8 {
283        self.buf_ptr.as_ptr() as *const u8
284    }
285
286    /// Get buffer raw mut pointer
287    #[inline]
288    pub fn get_raw_mut(&mut self) -> *mut u8 {
289        self.buf_ptr.as_ptr() as *mut u8
290    }
291
292    /// Copy from src u8 slice into self[offset..].
293    ///
294    /// **NOTE**: will not do memset.
295    ///
296    /// # Argument
297    ///
298    ///  * offset: Address of this buffer to start filling.
299    ///
300    /// # Panic
301    ///
302    /// If offset >= self.len(), will panic
303    #[inline]
304    pub fn copy_from(&mut self, offset: usize, src: &[u8]) {
305        let size = self.len();
306        let dst = self.as_mut();
307        if offset > 0 {
308            assert!(offset < size);
309            safe_copy(&mut dst[offset..], src);
310        } else {
311            safe_copy(dst, src);
312        }
313    }
314
315    /// Copy from another u8 slice into self[offset..], and memset the rest part.
316    ///
317    /// Argument:
318    ///
319    ///  * offset: Address of this buffer to start filling.
320    #[inline]
321    pub fn copy_and_clean(&mut self, offset: usize, other: &[u8]) {
322        let size = self.len();
323        let dst = self.as_mut();
324        assert!(offset < size);
325        let end: usize = if offset > 0 {
326            set_zero(&mut dst[0..offset]);
327            offset + safe_copy(&mut dst[offset..], other)
328        } else {
329            safe_copy(dst, other)
330        };
331        if size > end {
332            set_zero(&mut dst[end..]);
333        }
334    }
335
336    /// Fill this buffer with zero
337    #[inline]
338    pub fn zero(&mut self) {
339        set_zero(self);
340    }
341
342    /// Fill specified region of buffer[offset..(offset+len)] with zero
343    #[inline]
344    pub fn set_zero(&mut self, offset: usize, len: usize) {
345        let _len = self.len();
346        let mut end = offset + len;
347        if end > _len {
348            end = _len;
349        }
350        let buf = self.as_mut();
351        if offset > 0 || end < _len {
352            set_zero(&mut buf[offset..end]);
353        } else {
354            set_zero(buf);
355        }
356    }
357}
358
359/// Allocates a new memory with the same size and clone the content.
360/// If original buffer is a c reference, will get a owned buffer after clone().
361impl Clone for Buffer {
362    fn clone(&self) -> Self {
363        let mut new_buf = if self.is_aligned() {
364            Self::aligned(self.capacity() as i32).unwrap()
365        } else {
366            Self::alloc(self.capacity() as i32).unwrap()
367        };
368        if self.len() != self.capacity() {
369            new_buf.set_len(self.len());
370        }
371        safe_copy(new_buf.as_mut(), self.as_ref());
372        new_buf
373    }
374}
375
376/// Automatically free on drop when buffer is owned
377impl Drop for Buffer {
378    fn drop(&mut self) {
379        if self.is_owned() {
380            unsafe {
381                free(self.buf_ptr.as_ptr());
382            }
383        }
384    }
385}
386
387/// Convert a owned Buffer to `Vec<u8>`. Panic when buffer is a ref.
388impl From<Buffer> for Vec<u8> {
389    fn from(mut val: Buffer) -> Self {
390        if !val.is_owned() {
391            panic!("buffer is c ref, not owned");
392        }
393        // Change to not owned, to prevent drop()
394        val.size &= MAX_BUFFER_SIZE - 1;
395        unsafe {
396            Vec::<u8>::from_raw_parts(val.buf_ptr.as_ptr() as *mut u8, val.len(), val.capacity())
397        }
398    }
399}
400
401/// Convert `Vec<u8>` to Buffer, inherit the size and cap of Vec.
402impl From<Vec<u8>> for Buffer {
403    fn from(buf: Vec<u8>) -> Self {
404        let size = buf.len();
405        let cap = buf.capacity();
406        assert!(
407            size < MAX_BUFFER_SIZE as usize,
408            "size {} >= {} is not supported",
409            size,
410            MAX_BUFFER_SIZE
411        );
412        assert!(
413            cap < MAX_BUFFER_SIZE as usize,
414            "cap {} >= {} is not supported",
415            cap,
416            MAX_BUFFER_SIZE
417        );
418        // owned == true
419        let _size = size as u32 | MAX_BUFFER_SIZE;
420        // mutable == true
421        let _cap = cap as u32 | MAX_BUFFER_SIZE;
422        Buffer {
423            buf_ptr: unsafe { NonNull::new_unchecked(buf.leak().as_mut_ptr() as *mut c_void) },
424            size: _size,
425            cap: _cap,
426        }
427    }
428}
429
430impl Deref for Buffer {
431    type Target = [u8];
432
433    #[inline]
434    fn deref(&self) -> &[u8] {
435        self._as_ref()
436    }
437}
438
439impl AsRef<[u8]> for Buffer {
440    #[inline]
441    fn as_ref(&self) -> &[u8] {
442        self._as_ref()
443    }
444}
445
446/// On debug mode, will panic if the Buffer is not owned [Buffer::from_c_ref_const()]
447///
448/// On release will skip the check for speed.
449impl AsMut<[u8]> for Buffer {
450    #[inline]
451    fn as_mut(&mut self) -> &mut [u8] {
452        self._as_mut()
453    }
454}
455
456impl DerefMut for Buffer {
457    #[inline]
458    fn deref_mut(&mut self) -> &mut [u8] {
459        self._as_mut()
460    }
461}