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}