flipperzero_sys/furi/
alloc.rs

1//! Low-level wrappers around Furi memory allocation API.
2
3use core::ops::{Deref, DerefMut};
4use core::ptr::NonNull;
5
6/// Heap-allocated value.
7///
8/// This is intended for situations where it is not possible to rely upon a global allocator.
9/// Most users should make use of `flipperzero-alloc`.
10#[derive(PartialEq, Eq)]
11#[repr(transparent)]
12pub struct FuriBox<T: ?Sized>(NonNull<T>);
13
14impl<T> FuriBox<T> {
15    /// Allocates and initializes a correctly aligned value on the system heap.
16    pub fn new(value: T) -> Self {
17        let ptr = unsafe { crate::aligned_malloc(size_of::<T>(), align_of::<T>()) as *mut T };
18        assert!(!ptr.is_null());
19        assert!(ptr.is_aligned());
20
21        unsafe {
22            ptr.write(value);
23
24            // SAFETY: Pointer is non-null, aligned and represents a valid `T`
25            FuriBox::from_raw(ptr)
26        }
27    }
28
29    /// Consume the box and return raw pointer.
30    ///
31    /// Caller is responsible for calling `T::drop()` and freeing the pointer with `aligned_free`.
32    pub fn into_raw(b: FuriBox<T>) -> *mut T {
33        b.0.as_ptr()
34    }
35
36    /// Constructs a box from a raw pointer.
37    ///
38    /// # Safety
39    ///
40    /// This function is unsafe because improper use may lead to memory problems.
41    ///
42    /// The caller is responsible for ensuring the pointer is non-null, was allocated using `aligned_malloc`
43    /// with the correct alignment for `T` and that the memory represents a valid `T`.
44    pub unsafe fn from_raw(raw: *mut T) -> Self {
45        FuriBox(unsafe { NonNull::new_unchecked(raw) })
46    }
47
48    /// Returns a raw pointer to the Box’s contents.
49    ///
50    /// The caller must ensure that the Box outlives the pointer this function returns,
51    /// or else it will end up dangling.
52    ///
53    /// The caller must also ensure that the memory the pointer (non-transitively) points to
54    /// is never written to (except inside an `UnsafeCell`) using this pointer
55    /// or any pointer derived from it. If you need to mutate the contents of the Box, use `as_mut_ptr``.
56    ///
57    /// This method guarantees that for the purpose of the aliasing model,
58    /// this method does not materialize a reference to the underlying memory,
59    /// and thus the returned pointer will remain valid when mixed with
60    /// other calls to as_ptr and as_mut_ptr.
61    pub fn as_ptr(b: &FuriBox<T>) -> *const T {
62        b.0.as_ptr().cast_const()
63    }
64
65    /// Returns a raw mutable pointer to the Box’s contents.
66    ///
67    /// The caller must ensure that the Box outlives the pointer this function returns,
68    /// or else it will end up dangling.
69    ///
70    /// This method guarantees that for the purpose of the aliasing model,
71    /// this method does not materialize a reference to the underlying memory,
72    /// and thus the returned pointer will remain valid when mixed with
73    /// other calls to `as_ptr`` and `as_mut_ptr``.
74    pub fn as_mut_ptr(b: &mut FuriBox<T>) -> *mut T {
75        b.0.as_ptr()
76    }
77}
78
79impl<T: ?Sized> Drop for FuriBox<T> {
80    fn drop(&mut self) {
81        // SAFETY: Pointer was allocated by `aligned_malloc`
82        unsafe { crate::aligned_free(self.0.as_ptr().cast()) }
83    }
84}
85
86impl<T: ?Sized> AsRef<T> for FuriBox<T> {
87    fn as_ref(&self) -> &T {
88        // SAFETY: Pointer is non-null, aligned and represents a valid `T`
89        unsafe { self.0.as_ref() }
90    }
91}
92
93impl<T: ?Sized> AsMut<T> for FuriBox<T> {
94    fn as_mut(&mut self) -> &mut T {
95        // SAFETY: Pointer is non-null, aligned and represents a valid `T`
96        unsafe { self.0.as_mut() }
97    }
98}
99
100impl<T: ?Sized> Deref for FuriBox<T> {
101    type Target = T;
102
103    fn deref(&self) -> &Self::Target {
104        // SAFETY: Pointer is non-null, aligned and represents a valid `T`
105        unsafe { self.0.as_ref() }
106    }
107}
108
109impl<T: ?Sized> DerefMut for FuriBox<T> {
110    fn deref_mut(&mut self) -> &mut Self::Target {
111        // SAFETY: Pointer is non-null, aligned and represents a valid `T`
112        unsafe { self.0.as_mut() }
113    }
114}