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}