-
Notifications
You must be signed in to change notification settings - Fork 104
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
Support KnownLayout
trait and custom DSTs
#29
Labels
compatibility-nonbreaking
Changes that are (likely to be) non-breaking
Comments
joshlf
changed the title
Use
Use Aug 9, 2023
ptr_metadata
feature to shrink LayoutVerified
and support DSTsptr_metadata
feature to shrink Ref
and support DSTs
joshlf
added
the
compatibility-nonbreaking
Changes that are (likely to be) non-breaking
label
Aug 12, 2023
Closed
joshlf
changed the title
Use
Support unsized Sep 3, 2023
ptr_metadata
feature to shrink Ref
and support DSTsMaybeUninit
and custom DSTs
26 tasks
joshlf
added a commit
that referenced
this issue
Sep 3, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
Closed
joshlf
added a commit
that referenced
this issue
Sep 3, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 3, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 3, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 3, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
Closed
joshlf
added a commit
that referenced
this issue
Sep 4, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 4, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 4, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 5, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Merge AsMaybeUninit into KnownLayout Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 5, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Merge AsMaybeUninit into KnownLayout Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 5, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Merge AsMaybeUninit into KnownLayout Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 5, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Merge AsMaybeUninit into KnownLayout Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 6, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Figure out how to get rid of KnownLayout<MaybeUninit = mem::MaybeUninit<T>> bounds. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 6, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Figure out how to get rid of KnownLayout<MaybeUninit = mem::MaybeUninit<T>> bounds. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 6, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Figure out how to get rid of KnownLayout<MaybeUninit = mem::MaybeUninit<T>> bounds. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 6, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Figure out how to get rid of KnownLayout<MaybeUninit = mem::MaybeUninit<T>> bounds. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 6, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Figure out how to get rid of KnownLayout<MaybeUninit = mem::MaybeUninit<T>> bounds. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 6, 2023
The standard library's `MaybeUninit` type does not currently support wrapping unsized types. This commit introduces a polyfill with the same behavior as `MaybeUninit` which does support wrapping unsized types. In this commit, the only supported types are sized types and slice types. Later (as part of #29), we will add the ability to derive the `AsMaybeUninit` trait, which will extend support to custom DSTs. TODO: Figure out how to get rid of KnownLayout<MaybeUninit = mem::MaybeUninit<T>> bounds. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 7, 2023
In its initial form, the `KnownLayout` trait encodes type layout information slightly more complex than can be gleaned from any arbitrary `T: ?Sized`. This allows it to support not just sized and slice types, but also "custom DSTs" (those with fixed-size fields followed by a trailing slice type). This is the first step to supporting various operations on arbitrary custom DSTs. Makes progress on #29
Merged
joshlf
added a commit
that referenced
this issue
Sep 7, 2023
In its initial form, the `KnownLayout` trait encodes type layout information slightly more complex than can be gleaned from any arbitrary `T: ?Sized`. This allows it to support not just sized and slice types, but also "custom DSTs" (those with fixed-size fields followed by a trailing slice type). This is the first step to supporting various operations on arbitrary custom DSTs. Makes progress on #29
joshlf
added a commit
that referenced
this issue
May 14, 2024
While we're here, rename `from` to `from_bytes` so that naming is consistent (otherwise, we'd have to add `from_with_elems` rather than `from_bytes_with_elems`, which is a weird name). Makes progress on #29
github-merge-queue bot
pushed a commit
that referenced
this issue
May 14, 2024
While we're here, rename `from` to `from_bytes` so that naming is consistent (otherwise, we'd have to add `from_with_elems` rather than `from_bytes_with_elems`, which is a weird name). Makes progress on #29
joshlf
added
the
blocking-next-release
This issue should be resolved before we release on crates.io
label
May 30, 2024
joshlf
added
blocking-next-release-publicization
and removed
blocking-next-release
This issue should be resolved before we release on crates.io
labels
Jul 1, 2024
joshlf
added a commit
that referenced
this issue
Sep 7, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 7, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 7, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 7, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 8, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 8, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 8, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
joshlf
added a commit
that referenced
this issue
Sep 8, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
github-merge-queue bot
pushed a commit
that referenced
this issue
Sep 8, 2024
Change methods that allocate to return a new error, `AllocError`, on allocation failure rather than panicking or aborting. Makes progress on #29
The remaining issue is tracked separately: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Overview
The
KnownLayout
trait encodes enough information about a type's layout to be able to synthesize pointers to values of that type at runtime. While we can already do this for sized types and slice types,KnownLayout
generalizes this to "slice DSTs" - types with leading fixed-sized fields followed by a trailing slice.Progress
const
codeKnownLayout
for sized typesKnownLayout
for unsized typesT: Sized
bound fromalign_of<T>()
offset_of!
and expand it to support unsized typesalign_of_val_raw
offset_of!
and expand it to support unsized typessize_of_val_raw
repr(C)
layout algorithmDstLayout::extend
#633DstLayout::pad_to_align
#638derive(KnownLayout)
on DSTs #643KnownLayout
inRef
, and use this to supportKnownLayout
in other places#[doc(hidden)]
Ref
constructor which takesT: ?Sized + KnownLayout
, and is named something likenew_known_layout_name_to_be_bikeshedded
KnownLayout
, removeSized
from some APIs #967Ref
method named something likederef_known_layout_name_to_be_bikeshedded
(and similar forderef_mut
). This method should not have aT: FromBytes
bound, and should instead beunsafe
and require that the containedT
is valid as a safety precondition (this allows it to be used inTryFromBytes
).KnownLayout
, removeSized
from some APIs #967TryFromBytes::try_from_ref
) to internally construct aRef
and then use the appropriate private deref methodKnownLayout
, removeSized
from some APIs #967T: KnownLayout
requiresT
's fields to beKnownLayout
#1162RequireKnownLayout
to apply recursively to all fields to remain forwards-compatible with #494size_of::<T>()
)repr(transparent)
types (and maybe other reprs?)KnownLayout
on unsizedrepr(transparent)
types #1477FromBytes
methods and/orRef
constructors which operate on the whole buffer (rather than just the prefix/suffix) and take an explicit trailing element countwith_elems
Ref
constructors #1258TODO(#29)
commentsKnownLayout
violates private-in-public rules in some cases #1292KnownLayout
public (as of this writing, this will be in 0.8 per #671):#[doc(hidden)]
from all itemsT: Sized
bound withT: ?Sized + KnownLayout
; merge these APIs with any private APIs which were added during development (such asRef::new_known_layout_name_to_be_bikeshedded
)FromBytes:: ref_from_prefix
andref_from_suffix
have stale doc comments that refer tosize_of::<Self>()
Ref::new
,new_from_prefix
, andnew_from_suffix
have stale doc comments that refer tosize_of::<T>()
Motivation
Many users use zerocopy by defining types whose layouts match the layouts of data that needs to be parsed, serialized, or otherwise interacted with. Currently, zerocopy supports types with fixed size ("sized" types) and slices (a repeated structure of 0 or more instances of a sized type). However, many of our users have data which is not shaped like either of these.
In particular, many of our users have data which is shaped like a "slice-based dynamically-sized type" or "slice DST". A slice DST is a type with some number of fixed-sized fields followed by a trailing slice field. For example:
In this example, all
UdpPacket
s have the same fixedUdpHeader
, but may have a variable number of bytes in the trailingbody
field. The layout ofUdpPacket
exactly matches the layout of a UDP packet on the wire.This design aims to support users whose data can be modeled by slice DSTs.
Design
What
KnownLayout
needs to encodeKnownLayout
needs to provide any information required in order to perform a conversion from&[u8]
to&T
whereT
is a sized type, a slice type, or a slice DST. This conversion may be fallible due to size or alignment.In order to support these conversions, zerocopy must know the following:
This is encoded in the
DstLayout
type:Computing layout
In order to compute
KnownLayout
's associatedLAYOUT
constant, we use a recursive approach:align_of
andsize_of
align_of
andsize_of
to get the alignment and size of the element type; the slice's layout can be computed from these valuesFor composite types (namely in the context of
#[derive(KnownLayout)]
), we need to extract a few pieces of information:From these, we can compute the
LAYOUT
. However, computing these in a generic context is highly non-trivial.There are multiple avenues we could approach, but they all have pros and cons, and many are subject to timelines beyond our control since they require stabilizing currently-unstable Rust features. Our plan is to "race" them - try our best to drive progress on all fronts and see which approach gets to the finish line first. Since stabilizing unstable Rust features is a low-bandwidth/high-latency process, we expect this to be a reasonable use of our time.
Option 1:
offset_of!
and unsizedalign_of
The
offset_of!
macro provides the ability to directly query for the offset of a field within a type. It is currently unstable, and only supports sized types. If we could stabilizeoffset_of!
and add support for unsized types, we could use it to query the offset of a type's trailing slice field.We also need to support alignment. For this, we'd need
align_of
to drop itsT: Sized
bound.Option 2:
size_of_val_raw
andalign_of_val_raw
TODO
Option N: Manually implement Rust's
repr(C)
layout algorithmTODO
Validating and computing casts
TODO:
validate_cast_and_convert_metadata
Relationship to other traits
Ideally, we'd like
KnownLayout
to be a super-trait ofFromZeroes
(orTryFromBytes
(#5) onceFromZeroes: TryFromBytes
). Unfortunately,FromZeroes
supports types whichKnownLayout
cannot support: unsized types without a fixed representation (ie,repr(rust)
). These types do not provide sufficient guarantees about their layout in order to satisfyKnownLayout
's safety conditions. We have two options:FromZeroes
to only support types whichKnownLayout
can support, and then haveFromZeroes: KnownLayout
KnownLayout
as a bound on individual functions and methodsWe intend for zerocopy to be a general-purpose library which supports use cases that do not require known representations (any use case which doesn't require a type's layout to correspond to a fixed specification, but only to be consistent within the context of a program's execution). The first option would preclude us from supporting these use cases, so we opt for the latter: we will use
KnownLayout
as a bound on individual functions and methods.Deriving
KnownLayout
Computing alignment
Use
align_of_val_raw
Blocked on rust-lang/rust#69835
TODO
Use a
#[repr(C)]
type and field offsetBlocked on either rust-lang/rust#106655 or rust-lang/rust#69835
This design is prototyped in #576:
This design relies on the
trailing_field_offset!
macro added in #540 and described below. This macro relies on stabilizing rust-lang/rust#69835. Alternatively, if we can stabilizeoffset_of!
(rust-lang/rust#106655) and add support for usingoffset_of!
with unsized types, then we can replacetrailing_field_offset!
here withoffset_of!
.Computing trailing field offset
The
DstLayout
type needs to know the offset of the trailing slice within a DST. For example, givenBar
:...the trailing
tail: [u8]
is at offset 4 (after 2 bytes forBar.u
and 2 bytes forFoo.u
).In order to compute trailing slice offset in the context of a custom derive, it's necessary to compute recursively. In particular, given the offset of the trailing field within the outermost type (in this case,
Bar.foo
) and the offset of the trailing slice within the inner type (in this case,Foo.tail
), it's possible to compute the offset of the trailing slice within the outer type as the sum of these two values. In all cases, this is a recursive computation that bottoms out at an actual slice type,[T]
, whose trailing slice offset is 0.Thus the challenge is, given the AST of an arbitrary, possibly dynamically-sized type, to produce code which computes the byte offset of the trailing field. We have a few options.
offset_of!
Blocked on rust-lang/rust#106655
We could simply wait for the standard library's
offset_of!
macro to stabilize and add support for unsized types.addr_of!
Blocked on rust-lang/rust#69835
Another option is to rely on the standard library's
addr_of!
macro. Given a raw pointer to the beginning of a type, the expressionaddr_of!((*ptr).trailing_field)
will compute the address of trailing field, and the raw pointer methodoffset_from
can be used to compute the byte offset between these two pointers, effectively computing the trailing field offset.Unfortunately, place projection the
addr_of!
macro performs a place projection, and even if the pointers are never dereferenced, place projections may only happen inside the bounds of a valid allocation. Per The Reference, the following is undefined behavior:Thus, in order to use
addr_of!
, we need a valid allocation which is large enough that the field projection will not go out-of-bounds (the allocation does not need to be properly aligned). It is fairly trivial to produce a large allocation, even at const time:This, however, isn't enough. We also need to bounds check our allocation to make sure that the field projection won't go out-of-bounds. While it's unlikely we'd ever encounter a type with a trailing field offset of 2^16 bytes, it's not impossible, and we can't exhibit undefined behavior if we encounter such a type.
In order to perform the bounds check, we need some way of obtaining an upper bound for the trailing field offset before we've actually computed it. The only way of doing this (to my knowledge) is to calculate the size of the smallest possible value of the type (ie, the value with 0 trailing slice elements). We can't construct such an instance in the general case, but we can construct a raw pointer to such an instance:
This relies on behavior which is currently not well-defined, but is in review as of this writing.
However, once we have this raw pointer, we need to know its size. The only way to do this is with the currently-unstable
size_of_val_raw
. Once we've computed the size of the smallest possible value for our type (ie,size_of_val_raw(t)
), we have an upper bound for the offset of the trailing field; so long as this value is not larger than the size of our allocation, the field projection is guaranteed to be in-bounds, allowing us to soundly compute the trailing field offset.Old text
Add a replacement for
MaybeUninit
which supports unsized types. Add support for conversions on custom dynamically sized-types (DSTs).Status
Phase 1 is in review in #312.
Motivation
This proposal aims to solve two problems using a single, unified design.
Unsized
MaybeUninit
The standard library's
MaybeUninit
type don't support wrapping unsized types.MaybeUninit
is a core building block of important designs likeTryFromBytes
. So long as it doesn't support unsized types, designs likeTryFromBytes
also can't support unsized types.Custom DSTs
While zerocopy supports conversions on slice types, it doesn't support conversions on custom dynamically-sized types (DSTs) like:
Currently, users such as packet-formats instead write code like:
The latter code is more cumbersome, and requires storing an extra pointer in order to refer to a UDP packet in memory.
The ability to support custom DSTs is a frequent request from our users.
Design
This design comes in two phases; the first phase can be implemented without the second phase, and will provide value on its own.
In Phase 1, support is added for a
MaybeUninit
-like type that supports wrapping bothT: Sized
and[T] where T: Sized
. This will unlock theTryFromBytes
design as described above. In the Phase 2, support is added for aKnownLayout
trait which provides a superset of the functionality from Phase 1, and supports zero-copy conversion of arbitrary custom DSTs. A custom derive is providedKnownLayout
.Phase 1:
MaybeUninit
The standard library's
MaybeUninit<T>
type has the same layout asT
, but it has no bit validity constraints - any byte value, including an uninitialized byte, may be written at any byte offset in aMaybeUninit<T>
. A replacement for this type just needs to have these semantics, and also needs to support unsized types.Our design builds upon the fact that
MaybeUninit
exists and works for sized types. We define the following trait:For
Sized
types, the implementation is trivial:For all other types, we use the standard library's
MaybeUninit
type as a building block to build up a type whose layout is the same as whatMaybeUninit
's would be if it supported unsized types:Finally, we add our own
MaybeUninit
type, which is simply a convenience wrapper:In Phase 1, these are the only supported unsized types. In Phase 2, we allow deriving
AsMaybeUninit
on arbitrary types, which adds support for custom DSTs.Safety invariants
The safety invariants on
AsMaybeUninit
are somewhat complex. This is mostly a result of needing to support unsized types. For a more in-depth explanation of why supporting unsized types introduces a lot of complexity, see here.Let's walk through these:
T::MaybeUninit
containing any bit pattern, including uninitialized bytes."T
andT::MaybeUninit
's alignment in prose rather than by referring tocore::mem::align_of
because that function requires that its type argument is sized.as
cast requirement ensures thatT
andT::MaybeUninit
are either both sized or have compatible unsized types. In particular, Rust prohibits sized-to-unsized casts; requiring both directions to be valid ensures that casts are sized-to-sized or unsized-to-unsized. The size equality constraint ensures that:T
and aT::MaybeUninit
whose trailing slices are of the same length have the same sizeUnsafeCell
. In other words, interior mutability soundness is a runtime property that is only violated when anUnsafeCell
is used, not merely when a reference to it is constructed. Unfortunately, this is not actually currently guaranteed, and is unsound under the stacked borrows memory model. Thus, we need to ensure thatUnsafeCell
s inT
andT::MaybeUninit
line up perfectly.Pointer conversion
We want to be able to provide unsized equivalents of the
assume_init_ref
andassume_init_mut
methods. However, the naive implementation doesn't work:The
*const T::MaybeUninit as *mut T
cast isn't valid in a generic context whereT: ?Sized
because Rust doesn't know what type of pointers these are (thin, fat, what kind of fat pointer, etc). In order to get around this problem, we add the following methods toAsMaybeUninit
:This allows us to get
assume_init_ref
andassume_init_mut
to work:Phase 2:
KnownLayout
TODO
TODO: Mention that this will require removing the blanket impl of
AsMaybeUninit
forT: Sized
, which will be a breaking change. We need to not publish in between Phases 1 and 2.Alternatives
For
MaybeUninit
, we could propose a change to Rust to add limited support for unsized unions, which would allowMaybeUninit
(which is a union type) to support unsized types. Even if such a proposal were accepted, it would likely take months or years to be stabilized and thus available for our use.For custom DSTs, we could wait until the
ptr_metadata
andlayout_for_ptr
features stabilize, which would allow us to rewriteRef
like this:For
Sized
types,T::Metadata
would be()
, and soRef
would consume only a single word (rather than two, as it does today).On its own, we could still support slice types (
T = [U]
) as we do today usingfrom_raw_parts
andfrom_raw_parts_mut
. However, usinglayout_for_ptr
, we could also determine a DST's prefix and element sizes and thus support arbitrary DSTs rather than just slices.This design would work, but it's unlikely that either of these features will stabilize soon, and we need something in the meantime. The design presented also unblocks unsized
MaybeUninit
, which these features wouldn't help with.The text was updated successfully, but these errors were encountered: