19b2299afSBenno Lossin // SPDX-License-Identifier: Apache-2.0 OR MIT 29b2299afSBenno Lossin 39b2299afSBenno Lossin #[cfg(all(feature = "alloc", not(feature = "std")))] 49b2299afSBenno Lossin use alloc::{boxed::Box, sync::Arc}; 59b2299afSBenno Lossin #[cfg(feature = "alloc")] 69b2299afSBenno Lossin use core::alloc::AllocError; 79b2299afSBenno Lossin use core::{mem::MaybeUninit, pin::Pin}; 89b2299afSBenno Lossin #[cfg(feature = "std")] 99b2299afSBenno Lossin use std::sync::Arc; 109b2299afSBenno Lossin 119b2299afSBenno Lossin #[cfg(not(feature = "alloc"))] 129b2299afSBenno Lossin type AllocError = core::convert::Infallible; 139b2299afSBenno Lossin 149b2299afSBenno Lossin use crate::{ 159b2299afSBenno Lossin init_from_closure, pin_init_from_closure, InPlaceWrite, Init, PinInit, ZeroableOption, 169b2299afSBenno Lossin }; 179b2299afSBenno Lossin 189b2299afSBenno Lossin pub extern crate alloc; 199b2299afSBenno Lossin 20*3c75fff1SMiguel Ojeda // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee: 21*3c75fff1SMiguel Ojeda // <https://doc.rust-lang.org/stable/std/option/index.html#representation>). 22*3c75fff1SMiguel Ojeda unsafe impl<T> ZeroableOption for Box<T> {} 239b2299afSBenno Lossin 249b2299afSBenno Lossin /// Smart pointer that can initialize memory in-place. 259b2299afSBenno Lossin pub trait InPlaceInit<T>: Sized { 269b2299afSBenno Lossin /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this 279b2299afSBenno Lossin /// type. 289b2299afSBenno Lossin /// 299b2299afSBenno Lossin /// If `T: !Unpin` it will not be able to move afterwards. try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> where E: From<AllocError>309b2299afSBenno Lossin fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> 319b2299afSBenno Lossin where 329b2299afSBenno Lossin E: From<AllocError>; 339b2299afSBenno Lossin 349b2299afSBenno Lossin /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this 359b2299afSBenno Lossin /// type. 369b2299afSBenno Lossin /// 379b2299afSBenno Lossin /// If `T: !Unpin` it will not be able to move afterwards. pin_init(init: impl PinInit<T>) -> Result<Pin<Self>, AllocError>389b2299afSBenno Lossin fn pin_init(init: impl PinInit<T>) -> Result<Pin<Self>, AllocError> { 399b2299afSBenno Lossin // SAFETY: We delegate to `init` and only change the error type. 409b2299afSBenno Lossin let init = unsafe { 419b2299afSBenno Lossin pin_init_from_closure(|slot| match init.__pinned_init(slot) { 429b2299afSBenno Lossin Ok(()) => Ok(()), 439b2299afSBenno Lossin Err(i) => match i {}, 449b2299afSBenno Lossin }) 459b2299afSBenno Lossin }; 469b2299afSBenno Lossin Self::try_pin_init(init) 479b2299afSBenno Lossin } 489b2299afSBenno Lossin 499b2299afSBenno Lossin /// Use the given initializer to in-place initialize a `T`. try_init<E>(init: impl Init<T, E>) -> Result<Self, E> where E: From<AllocError>509b2299afSBenno Lossin fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> 519b2299afSBenno Lossin where 529b2299afSBenno Lossin E: From<AllocError>; 539b2299afSBenno Lossin 549b2299afSBenno Lossin /// Use the given initializer to in-place initialize a `T`. init(init: impl Init<T>) -> Result<Self, AllocError>559b2299afSBenno Lossin fn init(init: impl Init<T>) -> Result<Self, AllocError> { 569b2299afSBenno Lossin // SAFETY: We delegate to `init` and only change the error type. 579b2299afSBenno Lossin let init = unsafe { 589b2299afSBenno Lossin init_from_closure(|slot| match init.__init(slot) { 599b2299afSBenno Lossin Ok(()) => Ok(()), 609b2299afSBenno Lossin Err(i) => match i {}, 619b2299afSBenno Lossin }) 629b2299afSBenno Lossin }; 639b2299afSBenno Lossin Self::try_init(init) 649b2299afSBenno Lossin } 659b2299afSBenno Lossin } 669b2299afSBenno Lossin 679b2299afSBenno Lossin #[cfg(feature = "alloc")] 689b2299afSBenno Lossin macro_rules! try_new_uninit { 699b2299afSBenno Lossin ($type:ident) => { 709b2299afSBenno Lossin $type::try_new_uninit()? 719b2299afSBenno Lossin }; 729b2299afSBenno Lossin } 739b2299afSBenno Lossin #[cfg(all(feature = "std", not(feature = "alloc")))] 749b2299afSBenno Lossin macro_rules! try_new_uninit { 759b2299afSBenno Lossin ($type:ident) => { 769b2299afSBenno Lossin $type::new_uninit() 779b2299afSBenno Lossin }; 789b2299afSBenno Lossin } 799b2299afSBenno Lossin 809b2299afSBenno Lossin impl<T> InPlaceInit<T> for Box<T> { 819b2299afSBenno Lossin #[inline] try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> where E: From<AllocError>,829b2299afSBenno Lossin fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> 839b2299afSBenno Lossin where 849b2299afSBenno Lossin E: From<AllocError>, 859b2299afSBenno Lossin { 869b2299afSBenno Lossin try_new_uninit!(Box).write_pin_init(init) 879b2299afSBenno Lossin } 889b2299afSBenno Lossin 899b2299afSBenno Lossin #[inline] try_init<E>(init: impl Init<T, E>) -> Result<Self, E> where E: From<AllocError>,909b2299afSBenno Lossin fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> 919b2299afSBenno Lossin where 929b2299afSBenno Lossin E: From<AllocError>, 939b2299afSBenno Lossin { 949b2299afSBenno Lossin try_new_uninit!(Box).write_init(init) 959b2299afSBenno Lossin } 969b2299afSBenno Lossin } 979b2299afSBenno Lossin 989b2299afSBenno Lossin impl<T> InPlaceInit<T> for Arc<T> { 999b2299afSBenno Lossin #[inline] try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> where E: From<AllocError>,1009b2299afSBenno Lossin fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> 1019b2299afSBenno Lossin where 1029b2299afSBenno Lossin E: From<AllocError>, 1039b2299afSBenno Lossin { 1049b2299afSBenno Lossin let mut this = try_new_uninit!(Arc); 1059b2299afSBenno Lossin let Some(slot) = Arc::get_mut(&mut this) else { 1069b2299afSBenno Lossin // SAFETY: the Arc has just been created and has no external references 1079b2299afSBenno Lossin unsafe { core::hint::unreachable_unchecked() } 1089b2299afSBenno Lossin }; 1099b2299afSBenno Lossin let slot = slot.as_mut_ptr(); 1109b2299afSBenno Lossin // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 1119b2299afSBenno Lossin // slot is valid and will not be moved, because we pin it later. 1129b2299afSBenno Lossin unsafe { init.__pinned_init(slot)? }; 1139b2299afSBenno Lossin // SAFETY: All fields have been initialized and this is the only `Arc` to that data. 1149b2299afSBenno Lossin Ok(unsafe { Pin::new_unchecked(this.assume_init()) }) 1159b2299afSBenno Lossin } 1169b2299afSBenno Lossin 1179b2299afSBenno Lossin #[inline] try_init<E>(init: impl Init<T, E>) -> Result<Self, E> where E: From<AllocError>,1189b2299afSBenno Lossin fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> 1199b2299afSBenno Lossin where 1209b2299afSBenno Lossin E: From<AllocError>, 1219b2299afSBenno Lossin { 1229b2299afSBenno Lossin let mut this = try_new_uninit!(Arc); 1239b2299afSBenno Lossin let Some(slot) = Arc::get_mut(&mut this) else { 1249b2299afSBenno Lossin // SAFETY: the Arc has just been created and has no external references 1259b2299afSBenno Lossin unsafe { core::hint::unreachable_unchecked() } 1269b2299afSBenno Lossin }; 1279b2299afSBenno Lossin let slot = slot.as_mut_ptr(); 1289b2299afSBenno Lossin // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 1299b2299afSBenno Lossin // slot is valid. 1309b2299afSBenno Lossin unsafe { init.__init(slot)? }; 1319b2299afSBenno Lossin // SAFETY: All fields have been initialized. 1329b2299afSBenno Lossin Ok(unsafe { this.assume_init() }) 1339b2299afSBenno Lossin } 1349b2299afSBenno Lossin } 1359b2299afSBenno Lossin 1369b2299afSBenno Lossin impl<T> InPlaceWrite<T> for Box<MaybeUninit<T>> { 1379b2299afSBenno Lossin type Initialized = Box<T>; 1389b2299afSBenno Lossin write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E>1399b2299afSBenno Lossin fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> { 1409b2299afSBenno Lossin let slot = self.as_mut_ptr(); 1419b2299afSBenno Lossin // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 1429b2299afSBenno Lossin // slot is valid. 1439b2299afSBenno Lossin unsafe { init.__init(slot)? }; 1449b2299afSBenno Lossin // SAFETY: All fields have been initialized. 1459b2299afSBenno Lossin Ok(unsafe { self.assume_init() }) 1469b2299afSBenno Lossin } 1479b2299afSBenno Lossin write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E>1489b2299afSBenno Lossin fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> { 1499b2299afSBenno Lossin let slot = self.as_mut_ptr(); 1509b2299afSBenno Lossin // SAFETY: When init errors/panics, slot will get deallocated but not dropped, 1519b2299afSBenno Lossin // slot is valid and will not be moved, because we pin it later. 1529b2299afSBenno Lossin unsafe { init.__pinned_init(slot)? }; 1539b2299afSBenno Lossin // SAFETY: All fields have been initialized. 1549b2299afSBenno Lossin Ok(unsafe { self.assume_init() }.into()) 1559b2299afSBenno Lossin } 1569b2299afSBenno Lossin } 157