diff --git a/src/lib.rs b/src/lib.rs index 186a2fb..81701c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1137,13 +1137,7 @@ impl InPlaceInit for Box { where E: From, { - let mut this = Box::try_new_uninit()?; - let slot = this.as_mut_ptr(); - // SAFETY: When init errors/panics, slot will get deallocated but not dropped, - // slot is valid and will not be moved, because we pin it later. - unsafe { init.__pinned_init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { this.assume_init() }.into()) + Box::try_new_uninit()?.write_pin_init(init) } #[inline] @@ -1151,13 +1145,7 @@ impl InPlaceInit for Box { where E: From, { - let mut this = Box::try_new_uninit()?; - let slot = this.as_mut_ptr(); - // SAFETY: When init errors/panics, slot will get deallocated but not dropped, - // slot is valid. - unsafe { init.__init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { this.assume_init() }) + Box::try_new_uninit()?.write_init(init) } } @@ -1168,14 +1156,7 @@ impl InPlaceInit for Arc { where E: From, { - let mut this = Arc::try_new_uninit()?; - let slot = unsafe { Arc::get_mut_unchecked(&mut this) }; - let slot = slot.as_mut_ptr(); - // SAFETY: When init errors/panics, slot will get deallocated but not dropped, - // slot is valid and will not be moved, because we pin it later. - unsafe { init.__pinned_init(slot)? }; - // SAFETY: All fields have been initialized and this is the only `Arc` to that data. - Ok(unsafe { Pin::new_unchecked(this.assume_init()) }) + Arc::try_new_uninit()?.write_pin_init(init) } #[inline] @@ -1183,14 +1164,71 @@ impl InPlaceInit for Arc { where E: From, { - let mut this = Arc::try_new_uninit()?; - let slot = unsafe { Arc::get_mut_unchecked(&mut this) }; + Arc::try_new_uninit()?.write_init(init) + } +} + +/// Smart pointer containing uninitialized memory and that can write a value. +pub trait InPlaceWrite { + /// The type `Self` turns into when the contents are initialized. + type Initialized; + + /// Use the given initializer to write a value into `self`. + /// + /// Does not drop the current value and considers it as uninitialized memory. + fn write_init(self, init: impl Init) -> Result; + + /// Use the given pin-initializer to write a value into `self`. + /// + /// Does not drop the current value and considers it as uninitialized memory. + fn write_pin_init(self, init: impl PinInit) -> Result, E>; +} + +#[cfg(feature = "alloc")] +impl InPlaceWrite for Box> { + type Initialized = Box; + + fn write_init(mut self, init: impl Init) -> Result { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid. + unsafe { init.__init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { self.assume_init() }) + } + + fn write_pin_init(mut self, init: impl PinInit) -> Result, E> { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved, because we pin it later. + unsafe { init.__pinned_init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { self.assume_init() }.into()) + } +} + +#[cfg(feature = "alloc")] +impl InPlaceWrite for Arc> { + type Initialized = Arc; + + fn write_init(mut self, init: impl Init) -> Result { + let slot = unsafe { Arc::get_mut_unchecked(&mut self) }; let slot = slot.as_mut_ptr(); // SAFETY: When init errors/panics, slot will get deallocated but not dropped, // slot is valid. unsafe { init.__init(slot)? }; // SAFETY: All fields have been initialized. - Ok(unsafe { this.assume_init() }) + Ok(unsafe { self.assume_init() }) + } + + fn write_pin_init(mut self, init: impl PinInit) -> Result, E> { + let slot = unsafe { Arc::get_mut_unchecked(&mut self) }; + let slot = slot.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved, because we pin it later. + unsafe { init.__pinned_init(slot)? }; + // SAFETY: All fields have been initialized and this is the only `Arc` to that data. + Ok(unsafe { Pin::new_unchecked(self.assume_init()) }) } }