Skip to content

Commit 6841b61

Browse files
committed
rust: init: add write_[pin_]init functions
Sometimes it is necessary to split allocation and initialization into two steps. One such situation is when reusing existing allocations obtained via `Box::drop_contents`. See [1] for an example. In order to support this use case add `write_[pin_]init` functions to the pin-init API. These functions operate on already allocated smart pointers that wrap `MaybeUninit<T>`. Link: https://lore.kernel.org/rust-for-linux/f026532f-8594-4f18-9aa5-57ad3f5bc592@proton.me/ [1] Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Boqun Feng <boqun.feng@gmail.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Gary Guo <gary@garyguo.net> Link: https://lore.kernel.org/r/20240819112415.99810-2-benno.lossin@proton.me Signed-off-by: Miguel Ojeda <ojeda@kernel.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> (cherry picked from commit 6d1c22d0ace31d096b0dab5318c6a0d3219d6456)
1 parent 218a675 commit 6841b61

File tree

1 file changed

+63
-25
lines changed

1 file changed

+63
-25
lines changed

src/lib.rs

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,27 +1137,15 @@ impl<T> InPlaceInit<T> for Box<T> {
11371137
where
11381138
E: From<AllocError>,
11391139
{
1140-
let mut this = Box::try_new_uninit()?;
1141-
let slot = this.as_mut_ptr();
1142-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1143-
// slot is valid and will not be moved, because we pin it later.
1144-
unsafe { init.__pinned_init(slot)? };
1145-
// SAFETY: All fields have been initialized.
1146-
Ok(unsafe { this.assume_init() }.into())
1140+
Box::try_new_uninit()?.write_pin_init(init)
11471141
}
11481142

11491143
#[inline]
11501144
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
11511145
where
11521146
E: From<AllocError>,
11531147
{
1154-
let mut this = Box::try_new_uninit()?;
1155-
let slot = this.as_mut_ptr();
1156-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1157-
// slot is valid.
1158-
unsafe { init.__init(slot)? };
1159-
// SAFETY: All fields have been initialized.
1160-
Ok(unsafe { this.assume_init() })
1148+
Box::try_new_uninit()?.write_init(init)
11611149
}
11621150
}
11631151

@@ -1168,29 +1156,79 @@ impl<T> InPlaceInit<T> for Arc<T> {
11681156
where
11691157
E: From<AllocError>,
11701158
{
1171-
let mut this = Arc::try_new_uninit()?;
1172-
let slot = unsafe { Arc::get_mut_unchecked(&mut this) };
1173-
let slot = slot.as_mut_ptr();
1174-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1175-
// slot is valid and will not be moved, because we pin it later.
1176-
unsafe { init.__pinned_init(slot)? };
1177-
// SAFETY: All fields have been initialized and this is the only `Arc` to that data.
1178-
Ok(unsafe { Pin::new_unchecked(this.assume_init()) })
1159+
Arc::try_new_uninit()?.write_pin_init(init)
11791160
}
11801161

11811162
#[inline]
11821163
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
11831164
where
11841165
E: From<AllocError>,
11851166
{
1186-
let mut this = Arc::try_new_uninit()?;
1187-
let slot = unsafe { Arc::get_mut_unchecked(&mut this) };
1167+
Arc::try_new_uninit()?.write_init(init)
1168+
}
1169+
}
1170+
1171+
/// Smart pointer containing uninitialized memory and that can write a value.
1172+
pub trait InPlaceWrite<T> {
1173+
/// The type `Self` turns into when the contents are initialized.
1174+
type Initialized;
1175+
1176+
/// Use the given initializer to write a value into `self`.
1177+
///
1178+
/// Does not drop the current value and considers it as uninitialized memory.
1179+
fn write_init<E>(self, init: impl Init<T, E>) -> Result<Self::Initialized, E>;
1180+
1181+
/// Use the given pin-initializer to write a value into `self`.
1182+
///
1183+
/// Does not drop the current value and considers it as uninitialized memory.
1184+
fn write_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E>;
1185+
}
1186+
1187+
#[cfg(feature = "alloc")]
1188+
impl<T> InPlaceWrite<T> for Box<MaybeUninit<T>> {
1189+
type Initialized = Box<T>;
1190+
1191+
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
1192+
let slot = self.as_mut_ptr();
1193+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1194+
// slot is valid.
1195+
unsafe { init.__init(slot)? };
1196+
// SAFETY: All fields have been initialized.
1197+
Ok(unsafe { self.assume_init() })
1198+
}
1199+
1200+
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
1201+
let slot = self.as_mut_ptr();
1202+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1203+
// slot is valid and will not be moved, because we pin it later.
1204+
unsafe { init.__pinned_init(slot)? };
1205+
// SAFETY: All fields have been initialized.
1206+
Ok(unsafe { self.assume_init() }.into())
1207+
}
1208+
}
1209+
1210+
#[cfg(feature = "alloc")]
1211+
impl<T> InPlaceWrite<T> for Arc<MaybeUninit<T>> {
1212+
type Initialized = Arc<T>;
1213+
1214+
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
1215+
let slot = unsafe { Arc::get_mut_unchecked(&mut self) };
11881216
let slot = slot.as_mut_ptr();
11891217
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
11901218
// slot is valid.
11911219
unsafe { init.__init(slot)? };
11921220
// SAFETY: All fields have been initialized.
1193-
Ok(unsafe { this.assume_init() })
1221+
Ok(unsafe { self.assume_init() })
1222+
}
1223+
1224+
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
1225+
let slot = unsafe { Arc::get_mut_unchecked(&mut self) };
1226+
let slot = slot.as_mut_ptr();
1227+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1228+
// slot is valid and will not be moved, because we pin it later.
1229+
unsafe { init.__pinned_init(slot)? };
1230+
// SAFETY: All fields have been initialized and this is the only `Arc` to that data.
1231+
Ok(unsafe { Pin::new_unchecked(self.assume_init()) })
11941232
}
11951233
}
11961234

0 commit comments

Comments
 (0)