magic_buffer/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::{
4    ops::{
5        Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo, RangeToInclusive,
6    },
7    ptr::{slice_from_raw_parts, slice_from_raw_parts_mut},
8};
9use thiserror::Error;
10
11#[cfg(target_family = "windows")]
12mod windows;
13
14#[cfg(target_family = "windows")]
15use windows::*;
16
17#[cfg(target_os = "linux")]
18mod linux;
19
20#[cfg(target_os = "linux")]
21use linux::*;
22
23#[cfg(any(target_os = "macos", target_os = "ios"))]
24mod macos;
25
26#[cfg(any(target_os = "macos", target_os = "ios"))]
27use macos::*;
28
29/// The [`MagicBufferError`] error indicates an allocation failure that may be due
30/// to resource exhaustion or to something wrong with the given input arguments
31/// to [`MagicBuffer::new`].
32#[derive(Debug, Error)]
33pub enum MagicBufferError {
34    /// There is not enough memory available.
35    #[error("out of memory")]
36    OOM,
37    /// The specified buffer length is invalid. See [`MagicBuffer::new`] for more information.
38    #[error("invalid buffer len, {msg}")]
39    InvalidLen {
40        /// Details on why the `len` is invalid.
41        msg: String,
42    },
43}
44
45#[derive(Debug)]
46pub struct MagicBuffer {
47    addr: *mut u8,
48    len: usize,
49    mask: usize,
50}
51
52// SAFETY: Memory mappings are not tied to a thread, so they can be sent
53// across thread boundaries safely.
54unsafe impl Send for MagicBuffer {}
55
56// SAFETY: There is no interior mutability.
57unsafe impl Sync for MagicBuffer {}
58
59/// [`MagicBuffer`] provides a ring buffer implementation that
60/// can deref into a contiguous slice from any offset wrapping
61/// around the buffer.
62///
63/// This is made possible with virtual address mappings.
64/// The underlying buffer is mapped twice into virtual memory where
65/// the second mapping is adjacent to the first one. The logic
66/// for wrapping around the buffer is pushed down to the hardware.
67///
68/// # Examples
69/// ```
70/// # use magic_buffer::*;
71/// # fn main() -> Result<(), MagicBufferError> {
72/// let len = MagicBuffer::min_len();
73/// let buf = MagicBuffer::new(len)?;
74/// let slice = &buf[len/2..];
75/// assert_eq!(len, slice.len());
76/// # Ok(())
77/// # }
78/// ```
79#[allow(clippy::len_without_is_empty)]
80impl MagicBuffer {
81    /// Allocates a new [`MagicBuffer`] of the specified `len`.
82    ///
83    /// `len` must be a power of two, and also must be a multiple
84    /// of the operating system's allocation granularity. This is
85    /// usually the page size - most commonly 4KiB. On Windows
86    /// the allocation granularity is 64KiB (see [here](https://devblogs.microsoft.com/oldnewthing/20031008-00/?p=42223)).
87    ///
88    /// ## Errors
89    /// Will return a [`MagicBufferError`] if the allocation fails.
90    /// ```rust
91    /// # use magic_buffer::{MagicBuffer, MagicBufferError};
92    /// let err = MagicBuffer::new(0).unwrap_err();
93    /// assert!(matches!(err, MagicBufferError::InvalidLen{ .. }));
94    /// ```
95    ///
96    /// ## Panics
97    /// Will panic if it fails to cleanup in case of an error.
98    pub fn new(len: usize) -> Result<Self, MagicBufferError> {
99        if len == 0 {
100            return Err(MagicBufferError::InvalidLen {
101                msg: "len must be greater than 0".to_string(),
102            });
103        }
104
105        if !len.is_power_of_two() {
106            return Err(MagicBufferError::InvalidLen {
107                msg: "len must be power of two".to_string(),
108            });
109        }
110
111        let min_len = Self::min_len();
112        if len % min_len != 0 {
113            return Err(MagicBufferError::InvalidLen {
114                msg: format!("len must be page aligned, {}", min_len),
115            });
116        }
117
118        Ok(Self {
119            addr: unsafe { magic_buf_alloc(len) }?,
120            mask: len - 1,
121            len,
122        })
123    }
124
125    /// Returns the minimum buffer len that can be allocated.
126    ///
127    /// This is usually the page size - most commonly 4KiB. On Windows
128    /// the allocation granularity is 64KiB (see [here](https://devblogs.microsoft.com/oldnewthing/20031008-00/?p=42223)).
129    pub fn min_len() -> usize {
130        unsafe { magic_buf_min_len() }
131    }
132
133    /// Returns the length of this [`MagicBuffer`].
134    pub fn len(&self) -> usize {
135        self.len
136    }
137
138    /// Returns an unsafe pointer to the [`MagicBuffer`]. The `offset` species the first
139    /// element the pointer points to. The pointer can be used to address up to `len` elements.
140    ///
141    /// The caller must ensure that the [`MagicBuffer`] outlives the pointer this function returns,
142    /// or else it will end up pointing to garbage.
143    ///
144    /// The caller must also ensure that the memory the pointer (non-transitively) points to is
145    /// never written to (except inside an UnsafeCell) using this pointer or any pointer derived
146    /// from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`](MagicBuffer::as_mut_ptr).
147    ///
148    /// ## Examples
149    /// ```rust
150    /// # use magic_buffer::MagicBuffer;
151    /// let x = MagicBuffer::new(MagicBuffer::min_len()).unwrap();
152    /// let x_ptr = x.as_ptr(1);
153    ///
154    /// unsafe {
155    ///     for i in 0..x.len() {
156    ///         assert_eq!(*x_ptr.add(i), 0);
157    ///     }
158    /// }
159    /// ```
160    pub fn as_ptr(&self, offset: usize) -> *const u8 {
161        unsafe { self.addr.add(self.fast_mod(offset)).cast_const() }
162    }
163
164    /// Returns an unsafe mutable pointer to the [`MagicBuffer`]. The `offset` species the first
165    /// element the mutable pointer points to. The mutable pointer can be used to address up
166    /// to `len` elements.
167    ///
168    /// The caller must ensure that the [`MagicBuffer`] outlives the pointer this function returns,
169    /// or else it will end up pointing to garbage.
170    ///
171    /// ## Examples
172    /// ```rust
173    /// # use magic_buffer::MagicBuffer;
174    /// let mut x = MagicBuffer::new(MagicBuffer::min_len()).unwrap();
175    /// let x_ptr = x.as_mut_ptr(1);
176    ///
177    /// unsafe {
178    ///     for i in 0..x.len() {
179    ///         *x_ptr.add(i) = (i % 256) as u8;
180    ///     }
181    /// }
182    /// ```
183    pub fn as_mut_ptr(&mut self, offset: usize) -> *mut u8 {
184        unsafe { self.addr.add(self.fast_mod(offset)) }
185    }
186
187    #[inline(always)]
188    unsafe fn as_slice(&self, offset: usize, len: usize) -> &[u8] {
189        &*(slice_from_raw_parts(self.addr.add(offset), len))
190    }
191
192    #[inline(always)]
193    unsafe fn as_slice_mut(&mut self, offset: usize, len: usize) -> &mut [u8] {
194        &mut *(slice_from_raw_parts_mut(self.addr.add(offset), len))
195    }
196
197    #[inline(always)]
198    fn fast_mod(&self, v: usize) -> usize {
199        v & self.mask
200    }
201}
202
203impl Drop for MagicBuffer {
204    fn drop(&mut self) {
205        unsafe { magic_buf_free(self.addr, self.len) }
206    }
207}
208
209impl Deref for MagicBuffer {
210    type Target = [u8];
211
212    fn deref(&self) -> &Self::Target {
213        unsafe { self.as_slice(0, self.len) }
214    }
215}
216
217impl DerefMut for MagicBuffer {
218    fn deref_mut(&mut self) -> &mut Self::Target {
219        unsafe { self.as_slice_mut(0, self.len) }
220    }
221}
222
223impl Index<usize> for MagicBuffer {
224    type Output = u8;
225
226    fn index(&self, index: usize) -> &Self::Output {
227        unsafe { &*self.addr.add(self.fast_mod(index)) }
228    }
229}
230
231impl IndexMut<usize> for MagicBuffer {
232    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
233        unsafe { &mut *self.addr.add(self.fast_mod(index)) }
234    }
235}
236
237macro_rules! index_impl {
238    ($from:ty, $to:ty) => {
239        impl Index<$from> for MagicBuffer {
240            type Output = u8;
241
242            fn index(&self, index: $from) -> &Self::Output {
243                &self[index as $to]
244            }
245        }
246
247        impl IndexMut<$from> for MagicBuffer {
248            fn index_mut(&mut self, index: $from) -> &mut Self::Output {
249                &mut self[index as $to]
250            }
251        }
252    };
253}
254
255index_impl!(i64, isize);
256index_impl!(i32, isize);
257index_impl!(i16, isize);
258index_impl!(i8, isize);
259
260index_impl!(u64, usize);
261index_impl!(u32, usize);
262index_impl!(u16, usize);
263index_impl!(u8, usize);
264
265impl Index<isize> for MagicBuffer {
266    type Output = u8;
267
268    fn index(&self, index: isize) -> &Self::Output {
269        let index = if index < 0 {
270            self.len - self.fast_mod((-index) as usize)
271        } else {
272            self.fast_mod(index as usize)
273        };
274        unsafe { &*self.addr.add(index) }
275    }
276}
277
278impl IndexMut<isize> for MagicBuffer {
279    fn index_mut(&mut self, index: isize) -> &mut Self::Output {
280        let index = if index < 0 {
281            self.len - self.fast_mod((-index) as usize)
282        } else {
283            self.fast_mod(index as usize)
284        };
285        unsafe { &mut *self.addr.add(index) }
286    }
287}
288
289impl Index<Range<usize>> for MagicBuffer {
290    type Output = [u8];
291
292    fn index(&self, index: Range<usize>) -> &Self::Output {
293        if index.start > index.end {
294            return &[];
295        }
296
297        let len = index.end - index.start;
298        if len > self.len {
299            panic!("out of bounds")
300        }
301
302        unsafe { self.as_slice(self.fast_mod(index.start), len) }
303    }
304}
305
306impl IndexMut<Range<usize>> for MagicBuffer {
307    fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
308        if index.start > index.end {
309            return &mut [];
310        }
311
312        let len = index.end - index.start;
313        if len > self.len {
314            panic!("out of bounds")
315        }
316
317        unsafe { self.as_slice_mut(self.fast_mod(index.start), len) }
318    }
319}
320
321impl Index<RangeTo<usize>> for MagicBuffer {
322    type Output = [u8];
323
324    fn index(&self, index: RangeTo<usize>) -> &Self::Output {
325        let start = index.end - self.len;
326        unsafe { self.as_slice(self.fast_mod(start), self.len) }
327    }
328}
329
330impl IndexMut<RangeTo<usize>> for MagicBuffer {
331    fn index_mut(&mut self, index: RangeTo<usize>) -> &mut Self::Output {
332        let start = index.end - self.len;
333        unsafe { self.as_slice_mut(self.fast_mod(start), self.len) }
334    }
335}
336
337impl Index<RangeFrom<usize>> for MagicBuffer {
338    type Output = [u8];
339
340    fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
341        unsafe { self.as_slice(self.fast_mod(index.start), self.len) }
342    }
343}
344
345impl IndexMut<RangeFrom<usize>> for MagicBuffer {
346    fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut Self::Output {
347        unsafe { self.as_slice_mut(self.fast_mod(index.start), self.len) }
348    }
349}
350
351impl Index<RangeToInclusive<usize>> for MagicBuffer {
352    type Output = [u8];
353
354    fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
355        let start = index.end - self.len + 1;
356        unsafe { self.as_slice(self.fast_mod(start), self.len) }
357    }
358}
359
360impl IndexMut<RangeToInclusive<usize>> for MagicBuffer {
361    fn index_mut(&mut self, index: RangeToInclusive<usize>) -> &mut Self::Output {
362        let start = index.end - self.len + 1;
363        unsafe { self.as_slice_mut(self.fast_mod(start), self.len) }
364    }
365}
366
367impl Index<RangeFull> for MagicBuffer {
368    type Output = [u8];
369
370    fn index(&self, _: RangeFull) -> &Self::Output {
371        unsafe { self.as_slice(0, self.len) }
372    }
373}
374
375impl IndexMut<RangeFull> for MagicBuffer {
376    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
377        unsafe { self.as_slice_mut(0, self.len) }
378    }
379}
380
381#[cfg(test)]
382mod tests {
383    use super::*;
384
385    const VALID_BUF_LEN: usize = 1 << 16;
386    const INVALID_BUF_LEN_ALIGN: usize = 1 << 8;
387    const INVALID_BUF_LEN_POW2: usize = (1 << 16) + 5;
388
389    #[test]
390    fn allocates_buffer() {
391        let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
392        drop(buf);
393    }
394
395    #[test]
396    fn requires_power_of_two() {
397        MagicBuffer::new(INVALID_BUF_LEN_POW2)
398            .map_err(|e| {
399                println!("{}", e);
400                e
401            })
402            .expect_err("should not allocate buffer");
403    }
404
405    #[test]
406    fn requires_aligned_len() {
407        MagicBuffer::new(INVALID_BUF_LEN_ALIGN)
408            .map_err(|e| {
409                println!("{}", e);
410                e
411            })
412            .expect_err("should not allocate buffer");
413    }
414
415    #[test]
416    fn writes_are_visible_wrap_around() {
417        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
418        buf[0] = b'a';
419        assert_eq!(buf[0], buf[VALID_BUF_LEN]);
420    }
421
422    #[test]
423    fn deref_as_slice() {
424        let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
425        let slice: &[u8] = &buf;
426        assert_eq!(VALID_BUF_LEN, slice.len());
427    }
428
429    #[test]
430    fn deref_mut_as_slice() {
431        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
432        let slice: &mut [u8] = &mut buf;
433        assert_eq!(VALID_BUF_LEN, slice.len());
434    }
435
436    #[test]
437    fn closed_range() {
438        let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
439        let slice = &buf[0..VALID_BUF_LEN];
440        assert_eq!(VALID_BUF_LEN, slice.len());
441    }
442
443    #[test]
444    fn closed_range_mut() {
445        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
446        let slice = &mut buf[0..VALID_BUF_LEN];
447        assert_eq!(VALID_BUF_LEN, slice.len());
448    }
449
450    #[test]
451    fn range_to() {
452        let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
453        let slice = &buf[..VALID_BUF_LEN + 1];
454        assert_eq!(VALID_BUF_LEN, slice.len());
455    }
456
457    #[test]
458    fn range_to_mut() {
459        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
460        let slice = &mut buf[..VALID_BUF_LEN + 1];
461        assert_eq!(VALID_BUF_LEN, slice.len());
462    }
463
464    #[test]
465    fn range_from() {
466        let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
467        let slice = &buf[1..];
468        assert_eq!(VALID_BUF_LEN, slice.len());
469    }
470
471    #[test]
472    fn range_from_mut() {
473        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
474        let slice = &mut buf[1..];
475        assert_eq!(VALID_BUF_LEN, slice.len());
476    }
477
478    #[test]
479    fn range_to_inclusive() {
480        let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
481        let slice = &buf[..=VALID_BUF_LEN];
482        assert_eq!(VALID_BUF_LEN, slice.len());
483    }
484
485    #[test]
486    fn range_to_inclusive_mut() {
487        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
488        let slice = &mut buf[..=VALID_BUF_LEN];
489        assert_eq!(VALID_BUF_LEN, slice.len());
490    }
491
492    #[test]
493    fn range_full() {
494        let buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
495        let slice = &buf[..];
496        assert_eq!(VALID_BUF_LEN, slice.len());
497    }
498
499    #[test]
500    fn range_full_mut() {
501        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
502        let slice = &mut buf[..];
503        assert_eq!(VALID_BUF_LEN, slice.len());
504    }
505
506    #[test]
507    fn index_wrap_around() {
508        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
509        buf[0] = b'1';
510        assert_eq!(b'1', buf[VALID_BUF_LEN]);
511    }
512
513    #[test]
514    fn index_negative() {
515        let mut buf = MagicBuffer::new(VALID_BUF_LEN).expect("should allocate buffer");
516        buf[-1] = b'2';
517        assert_eq!(b'2', buf[VALID_BUF_LEN - 1]);
518    }
519}