-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[lib] In-place initialization infrastructure #142518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
//! In-place initialization. | ||
//! | ||
//! This module describes the interface through which types supporting in-place initialization | ||
//! can perform initialization with minimal or zero additional allocations or moves. | ||
|
||
use crate::ptr::Pointee; | ||
|
||
/// In-place Initializer for `T`. | ||
/// | ||
/// An instance of `Init<T>` carries all the information necessary to initialize a `T` in a | ||
/// well-defined memory location, criteria of which is prescribed in the Safety section. | ||
/// | ||
/// # Fallibility | ||
/// | ||
/// The initialization might fail and return an error of type [`Self::Error`] instead. | ||
/// In that case, the memory provided to [`Self::init`] shall be repurposed in any way, | ||
/// even though it might have been written to by this initializer. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ## Initializing unsized types | ||
/// | ||
/// To initialize an unsized type, first query the required layout for `T` using [`Self::layout`]. | ||
/// Then provide a pointer to an allocation of at least the specified alignment and size. | ||
/// | ||
/// If initialization was successful, then [`Self::init`] returns the metadata that combined with | ||
/// the pointer to the given to [`Self::init`] yields a valid pointer to `T`. | ||
/// | ||
/// ``` ignore (illustrative) | ||
/// use std::alloc::alloc; | ||
/// fn init_boxed<T: ?Sized + Pointee, I: Init<T>>(init: I) -> Result<Box<T>, I::Error> { | ||
/// let layout = init.layout(); | ||
/// let memory = alloc(layout).cast::<()>(); | ||
/// let meta = init.init(memory)?; | ||
/// Box::from_raw(from_raw_parts_mut(memory, meta)) | ||
/// } | ||
/// ``` | ||
/// | ||
/// # Safety | ||
/// | ||
/// Implementers must ensure that if [`self.init(slot)`] returns `Ok(metadata)`, | ||
/// then [`core::ptr::from_raw_parts_mut(slot, metadata)`] must reference a valid | ||
/// value owned by the caller. | ||
/// Furthermore, the layout returned by using | ||
/// [`core::intrinsics::size_of_val`] and [`core::intrinsics::align_of_val`] on this pointer | ||
/// must match what [`Self::layout()`] returns exactly. | ||
/// | ||
/// If `T` is sized, or in other words `T: Sized`, [`Init::layout`] in this case *must* | ||
/// return the same layout as [`Layout::new::<T>()`] would. | ||
/// | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additionally, we should require that if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied |
||
/// Implementers must ensure that the implementation of `init()` does not rely | ||
/// on the value being pinned. | ||
/// | ||
/// [`core::ptr::from_raw_parts_mut(slot, metadata)`]: core::ptr::from_raw_parts_mut | ||
/// [`Self::layout()`]: Init::layout | ||
/// [`self.init(slot)`]: Init::init | ||
/// [`Layout::new::<T>()`]: core::alloc::Layout::new | ||
#[unstable(feature = "in_place_initialization", issue = "999999")] | ||
#[lang = "init_trait"] | ||
pub unsafe trait Init<T: ?Sized + Pointee> { | ||
/// Error type upon initialization failure during the actual | ||
/// in-place initialization procedure. | ||
#[lang = "init_error"] | ||
type Error; | ||
|
||
/// The layout needed by this initializer. | ||
/// This method must return a layout that precisely matches | ||
/// with `T`. | ||
/// Namely the size and the alignment must be equal. | ||
#[lang = "init_layout"] | ||
fn layout(&self) -> crate::alloc::Layout; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming it's not allowed to have Would it be better to only expose the layout/metadata in a single place, like replacing Then the trait user would do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that the metadata should be able to depend on what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Then There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay fair. But how do you get the alignment & size from the metadata? I didn't understand what you wrote above:
You don't have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to ask for a clarification. Did you mean the other way around, like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That case is wrong too, but I meant what I said. The layout must be an exact match - it's not okay for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Oh, I didn't realize that there is no method to get a unsafe fn layout_from_meta<T: ptr::Pointee + ?Sized>(meta: T::Metadata) -> Layout {
unsafe {
// wait, if `for_value_raw` only care about ptr metadata, why doesn't it just
// accept a `T::Metadata` parameter?
Layout::for_value_raw(ptr::from_raw_parts::<T>(ptr::null::<()>(), meta))
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have updated the comment to make it very specific. |
||
|
||
/// Writes a valid value of type `T` to `slot` or fails. | ||
/// | ||
/// If this call returns [`Ok`], then `slot` is guaranteed to contain a valid | ||
/// value of type `T`. | ||
/// Otherwise, in case the result is an [`Err`], the implementation must guarantee | ||
/// that the `slot` may be repurposed for future reuse. | ||
/// | ||
/// If `T` is unsized, then `slot` may be combined with | ||
/// the metadata to obtain a valid pointer to the value. | ||
/// | ||
/// Note that `slot` should be thought of as a `*mut T`. A unit type is used | ||
/// so that the pointer is thin even if `T` is unsized. | ||
/// | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're missing the part that if it returns There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied with additional comments There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I forgot to add the hunk to the change set. I would like to make it more explicit. Maybe it will become a future OpSem question. Should we make the I think we can defer it for further clarification. We can come back to update the documentation at any time before calling for stabilisation. |
||
/// # Safety | ||
/// | ||
/// The caller must provide a pointer that references a location that `init` | ||
/// may write to, and the location must have at least the size and alignment | ||
/// specified by [`Init::layout`]. | ||
#[lang = "init_init"] | ||
unsafe fn init(self, slot: *mut ()) -> Result<T::Metadata, Self::Error>; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.