You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#1828 implements initial support for an UnalignUnsized<T> wrapper, that drop its value by moving it to an aligned place, then running its destructor. For derivations of KnownLayout on default repr types (which are always sized), this achieved by stack allocating the well-aligned place. For derivations of KnownLayout on repr(C) types (which may or may not be sized), this is achieved by heap allocation.
These conditions are less precise than we'd wish. Rather than depending on the syntax T, we'd like the drop behavior to depend on the actual sizedness of T. I.e., if T is sized, a place for it it can be stack allocated; otherwise, heap allocated.
Single Trait Approach
Unfortunately, it is impossible to straight-forwardly extend KnownLayout with this capability; e.g., this attempt induces solver cycles on implementations of KnownLayout for wrapper types (playground):
use std::cell::UnsafeCell;use std::mem::MaybeUninit;// Helps ensure that the correct metadata kind is used and// can hold methods whose impl differs on `T`'s (un)sizedness.traitMetadata<T: ?Sized>{}impl<T>Metadata<T>for(){}impl<T: ?Sized>Metadata<T>forusize{}// A trait encoding layout facts about `Self`.traitKnownLayout{// What metadata do pointers to `Self` have?typeMetadata:Metadata<Self>;// A type with a layout like `Self`, but allowing uninit// bytes in all positions.typeMaybeUninit: ?Sized + KnownLayout<Metadata = Self::Metadata>;}// A working-as-intended impl of `KnownLayout`:impl<T>KnownLayoutfor[T]{typeMetadata = usize;typeMaybeUninit = [MaybeUninit<T>];}// Is there anything we can do to get this impl to compile?impl<T: ?Sized + KnownLayout>KnownLayoutforUnsafeCell<T>{typeMetadata = <TasKnownLayout>::Metadata;typeMaybeUninit = UnsafeCell<<TasKnownLayout>::MaybeUninit>;}
Layered Approach
To break the cycles, we must introduce an additional trait layer. In the below approach, derive(KnownLayout) actually emits an impl for KnownLayoutInternal, while KnownLayout (now backed by a blanket impl bounded by MetadataCoherent):
use std::cell::UnsafeCell;use std::mem::MaybeUninit;pubtraitMetadata{}implMetadatafor(){}implMetadataforusize{}// This trait is the one implemented by `derive(KnownLayout)`#[doc(hidden)]pubtraitKnownLayoutInternal{// What metadata do pointers to `Self` have?typeMetadata:Metadata;// A type with a layout like `Self`, but allowing uninit// bytes in all positions.typeMaybeUninit: ?Sized + KnownLayoutInternal<Metadata = Self::Metadata>;}#[doc(hidden)]pubtraitMetadataCoherent<T: ?Sized>:Metadata{}impl<T>MetadataCoherent<T>forusizewhereT: ?Sized + KnownLayoutInternal<Metadata = Self>{}impl<T>MetadataCoherent<T>for()whereT:KnownLayoutInternal<Metadata = Self>{}// This trait is the one that appears as a bound in public APIs.pubtraitKnownLayout:KnownLayoutInternalwhereSelf::Metadata:MetadataCoherent<Self>{}impl<T: ?Sized + KnownLayoutInternal>KnownLayoutforTwhereSelf::Metadata:MetadataCoherent<Self>{}// A working-as-intended impl of `KnownLayoutInternal`:impl<T>KnownLayoutInternalfor[T]{typeMetadata = usize;typeMaybeUninit = [MaybeUninit<T>];}// And this now compiles, too!impl<T: ?Sized + KnownLayoutInternal>KnownLayoutInternalforUnsafeCell<T>{typeMetadata = <TasKnownLayoutInternal>::Metadata;typeMaybeUninit = UnsafeCell<<TasKnownLayoutInternal>::MaybeUninit>;}
Unfortunately, the
where
Self::Metadata:MetadataCoherent<Self>
on KnownLayout is not implied by KnownLayout!
If you define a function with an argument bounded by KnownLayout; e.g.:
fnfoo<T:KnownLayout>(){}
...rustc produces this error:
error[E0277]: the trait bound `<T as KnownLayoutInternal>::Metadata: MetadataCoherent<T>` is not satisfied
--> src/lib.rs:1:11
|
1 | fn foo<T: KnownLayout>() {}
| ^^^^^^^^^^^ the trait `MetadataCoherent<T>` is not implemented for `<T as KnownLayoutInternal>::Metadata`
|
note: required by a bound in `KnownLayout`
--> src/lib.rs:37:21
|
35 | pub trait KnownLayout: KnownLayoutInternal
| ----------- required by a bound in this trait
36 | where
37 | Self::Metadata: MetadataCoherent<Self>
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `KnownLayout`
help: consider further restricting the associated type
|
1 | fn foo<T: KnownLayout>() where <T as KnownLayoutInternal>::Metadata: MetadataCoherent<T> {}
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The text was updated successfully, but these errors were encountered:
#1828 implements initial support for an
UnalignUnsized<T>
wrapper, that drop its value by moving it to an aligned place, then running its destructor. For derivations ofKnownLayout
on default repr types (which are always sized), this achieved by stack allocating the well-aligned place. For derivations ofKnownLayout
onrepr(C)
types (which may or may not be sized), this is achieved by heap allocation.These conditions are less precise than we'd wish. Rather than depending on the syntax
T
, we'd like the drop behavior to depend on the actual sizedness ofT
. I.e., ifT
is sized, a place for it it can be stack allocated; otherwise, heap allocated.Single Trait Approach
Unfortunately, it is impossible to straight-forwardly extend
KnownLayout
with this capability; e.g., this attempt induces solver cycles on implementations ofKnownLayout
for wrapper types (playground):Layered Approach
To break the cycles, we must introduce an additional trait layer. In the below approach,
derive(KnownLayout)
actually emits an impl forKnownLayoutInternal
, whileKnownLayout
(now backed by a blanket impl bounded byMetadataCoherent
):Unfortunately, the
on
KnownLayout
is not implied byKnownLayout
!If you define a function with an argument bounded by
KnownLayout
; e.g.:...rustc produces this error:
The text was updated successfully, but these errors were encountered: