Skip to main content

rs_matter/utils/
init.rs

1/*
2 *
3 *    Copyright (c) 2024-2026 Project CHIP Authors
4 *
5 *    Licensed under the Apache License, Version 2.0 (the "License");
6 *    you may not use this file except in compliance with the License.
7 *    You may obtain a copy of the License at
8 *
9 *        http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *    Unless required by applicable law or agreed to in writing, software
12 *    distributed under the License is distributed on an "AS IS" BASIS,
13 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *    See the License for the specific language governing permissions and
15 *    limitations under the License.
16 */
17
18use core::convert::Infallible;
19use core::{cell::UnsafeCell, mem::MaybeUninit};
20
21/// Re-export `pinned-init` because its API is very unstable currently (0.0.x)
22pub use pinned_init::*;
23
24/// Convert a closure returning `Result<impl Init<T, E>, E>` into an `Init<T, E>`.
25pub fn into_init<F, T, E, I: Init<T, E>>(f: F) -> impl Init<T, E>
26where
27    F: FnOnce() -> Result<I, E>,
28{
29    unsafe { init_from_closure(move |slot| f()?.__init(slot)) }
30}
31
32/// An extension trait for converting `Init<T, Infallible>` to a fallible `Init<T, E>`.
33/// Useful when chaining an infallible initializer with a fallible chained initialization function.
34pub trait IntoFallibleInit<T>: Init<T, Infallible> {
35    /// Convert the infallible initializer to a fallible one.
36    fn into_fallible<E>(self) -> impl Init<T, E> {
37        unsafe {
38            init_from_closure(move |slot| {
39                unwrap!(Self::__init(self, slot));
40
41                Ok(())
42            })
43        }
44    }
45}
46
47impl<T, I> IntoFallibleInit<T> for I where I: Init<T, Infallible> {}
48
49/// An extension trait for retrofitting `UnsafeCell` with an initializer.
50pub trait UnsafeCellInit<T> {
51    /// Create a new in-place initializer for `UnsafeCell`
52    /// by using the given initializer for the value.
53    fn init<I: Init<T>>(value: I) -> impl Init<Self>;
54}
55
56impl<T> UnsafeCellInit<T> for UnsafeCell<T> {
57    fn init<I: Init<T>>(value: I) -> impl Init<Self> {
58        unsafe {
59            init_from_closure::<_, Infallible>(move |slot: *mut Self| {
60                // `slot` contains uninit memory, avoid creating a reference.
61                let slot: *mut T = slot as _;
62
63                // Initialize the value
64                unwrap!(value.__init(slot));
65
66                Ok(())
67            })
68        }
69    }
70}
71
72/// An extension trait that allows safe initialization of
73/// `MaybeUninit<T>` memory.
74pub trait InitMaybeUninit<T> {
75    /// Initialize Self with the given in-place initializer.
76    fn init_with<I: Init<T>>(&mut self, init: I) -> &mut T {
77        unwrap!(self.try_init_with(init))
78    }
79
80    /// Try to initialize Self with the given fallible in-place initializer.
81    fn try_init_with<I: Init<T, E>, E>(&mut self, init: I) -> Result<&mut T, E>;
82
83    /// Initialize Self with all-zeroes
84    fn init_zeroed(&mut self) -> &mut T
85    where
86        T: Zeroable,
87    {
88        self.init_with(pinned_init::zeroed())
89    }
90}
91
92impl<T> InitMaybeUninit<T> for MaybeUninit<T> {
93    fn try_init_with<I: Init<T, E>, E>(&mut self, init: I) -> Result<&mut T, E> {
94        unsafe {
95            Init::<T, E>::__init(init, self.as_mut_ptr())?;
96
97            Ok(self.assume_init_mut())
98        }
99    }
100}
101
102/// A trait for types that have a canonical, stack-safe, in-place default initializer.
103///
104/// This is the in-place initialization analogue of `Default`: unlike `Default::default()`
105/// which returns `Self` by value (potentially materializing a large value on the stack),
106/// `init_default()` returns an `Init<Self>` that writes the value directly into its
107/// final memory location. This is essential for large types (e.g. buffers sized in MiB)
108/// whose on-stack construction would overflow the stack.
109pub trait InitDefault: Sized {
110    /// Returns a canonical in-place initializer for `Self`.
111    fn init_default() -> impl Init<Self>;
112}