fbl/recyclable.rs
1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use core::ffi::c_void;
8use core::ptr::NonNull;
9use kalloc::AllocError;
10
11/// Trait for types that can be recycled (deallocated).
12///
13/// # Safety
14///
15/// Implementing this trait is unsafe because the implementer must ensure that:
16/// - `allocate`, if overridden, returns a valid pointer that can be safely deallocated by
17/// `recycle`.
18/// - `recycle` correctly deallocates the pointer and does not cause double-free or use-after-free.
19pub unsafe trait Recyclable: Sized {
20 /// Allocates a new instance of `Self`.
21 ///
22 /// The default implementation returns `Err(AllocError)`, which is appropriate for types
23 /// that cannot be allocated from Rust (e.g., C++ ref-counted objects).
24 fn allocate(_value: Self) -> Result<NonNull<Self>, AllocError> {
25 Err(AllocError)
26 }
27
28 /// Recycles the object.
29 ///
30 /// # Safety
31 ///
32 /// - The caller must ensure that `ptr` points to a valid, fully-initialized
33 /// instance of `Self` that has no other references.
34 /// - The caller must not use the pointer or any references derived from it
35 /// after this call.
36 unsafe fn recycle(ptr: NonNull<Self>);
37
38 /// Helper for FFI functions to call `recycle`.
39 ///
40 /// # Safety
41 ///
42 /// - The caller must ensure that `ptr` is valid and points to a valid object
43 /// of type `Self` that has no other references.
44 /// - The caller must not use the pointer or any references derived from it
45 /// after this call.
46 unsafe fn recycle_ffi(ptr: *mut c_void) {
47 // SAFETY: The caller of `recycle_ffi` must ensure that `ptr` is non-null
48 // and points to a valid `Self` that can be safely recycled.
49 unsafe {
50 Self::recycle(NonNull::new_unchecked(ptr as *mut Self));
51 }
52 }
53}
54
55/// Trait for types that can be allocated in an uninitialized state.
56///
57/// # Safety
58///
59/// Implementing this trait is unsafe because the implementer must ensure that:
60/// - `allocate_uninit` returns a valid pointer to uninitialized memory that can
61/// be safely deallocated by `recycle_uninit`.
62/// - `recycle_uninit` correctly deallocates the pointer without dropping the content
63/// (as it is uninitialized) and does not cause double-free or use-after-free.
64pub unsafe trait UninitRecyclable: Recyclable {
65 /// Allocates a new uninitialized instance of `Self`.
66 fn allocate_uninit() -> Result<NonNull<core::mem::MaybeUninit<Self>>, AllocError>;
67
68 /// Recycles an uninitialized object.
69 ///
70 /// # Safety
71 ///
72 /// - The caller must ensure that `ptr` points to a valid (but possibly uninitialized)
73 /// instance of `Self` that has no other references.
74 /// - The caller must not use the pointer or any references derived from it
75 /// after this call.
76 unsafe fn recycle_uninit(ptr: NonNull<core::mem::MaybeUninit<Self>>);
77}