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
I've been engaged over the past few months in an exercise in Yak-shaving, wherein I re-implemented this crate in a couple of different ways, before finally deciding to just contribute to the already existing and much higher quality solution. The main feature that I need is the allocation of proper DSTs, which this crate doesn't support.
Although in the end my solution to this problem was to use nightly to get access to the ptr_metadata feature, one of the interceding versions simply polyfilled that feature in order to be able to allocate a subset of unsized types in a Gc.
The whole point of this is to store a function which computes a layout in the CollectVtable instead of storing a static layout, so as to allow truly dynamically sized Gc pointers.
Proposed API
The additional API surface, and changes to existing structs, is very very roughly as follows. And although I'm not hugely familiar with this code base, I don't see anywhere obvious which is antithetical to this approach.
traitMetaSized{typeMetadata:Sized + Copy;fnlayout_from_meta(meta:Self::Metadata) -> Result<Layout,LayoutError>;fninto_parts(this:*constSelf) -> (*const(),Self::Metadata);fnfrom_parts(ptr:*const(),meta:Self::Metadata) -> *constSelf;fninto_parts_mut(this:*mutSelf) -> (*mut(),Self::Metadata);fnfrom_parts_mut(ptr:*mut(),meta:Self::Metadata) -> *mutSelf;}impl<T>MetaSizedforT{ ... }impl<T>MetaSizedfor[T]{ ... }implMetaSizedforstr{ ... }// The additional type parameter here is to enable the pattern of reading a sized `GcBoxInner<(), T::Metadata>`, // extracting the metadata field, and then using that metadata to read a proper unsized `GcBoxInner<T>`.structGcBoxInner<T: ?Sized + MetaSized,M = T::Metadata>{pub(crate)header:GcBoxHeader,//+ Added field/// The metadata for the value stored in this `GcBox`.pub(crate)metadata:M,/// The typed value stored in this `GcBox`.pub(crate)value: mem::ManuallyDrop<T>,}impl<T: ?Sized + MetaSized>GcBoxInner<T>{// `GcBoxInner` cannot implement MetaSized due to overlapping impls.fnlayout_from_meta(meta:T::Metadata) -> Result<Layout,LayoutError>{ ...}fninto_parts(this:*constSelf) -> (*const(),T::Metadata){ ...}unsafefnfrom_parts(ptr:*const(),meta:T::Metadata) -> *constSelf{ ...}fninto_parts_mut(this:*mutSelf) -> (*mut(),T::Metadata){ ...}unsafefnfrom_parts_mut(ptr:*mut(),meta:T::Metadata) -> *mutSelf{ ...}}#[repr(align(16))]structCollectVtable{//- Removed field// box_layout: Layout,/// Computes the layout of the `GcBox` the GC'd value is stored in.layout_fn:unsafefn(GcBox) -> Layout,/// Drops the value stored in the given `GcBox` (without deallocating the box).drop_value:unsafefn(GcBox),/// Traces the value stored in the given `GcBox`.trace_value:unsafefn(GcBox,&mutContext),}
Downsides
There are of course downsides; it adds indirection where there previously was none; it is a fair amount of complexity to add; it's not truly general for all unsized types, just those which implement a crate-private trait; and I'm sure there are more. On the other hand, for all Sized types, this actually frees up 8 bytes in the CollectVtable without adding any data to the GcBoxInner, the other upsides I believe far outweigh the costs, and I'm happy to implement it myself if this seems up to snuff.
Playground with enough code to convince me that this is doable on stable, and frankly probably more than is necessary.
The text was updated successfully, but these errors were encountered:
After tinkering around in the codebase for a little while, this proposal is a non-starter as written, as it infects every unsized bound with the MetaSized trait, and thus excludes dyn objects.
This can be reworked, by defining GcBoxInner as follows
and then having GcBox point to the second field of a valid GcBoxInner<T, T::Metadata>. Since GcBoxInner is #[repr(C)], this means it is valid to read a GcBox as pointing to the first field of a GcBoxInner<T, ()>. The offset from this pointer to the metadata field can be statically calculated, with no information about the layout of T needed.
I also believe that this change also makes it possible to define a ThinGc pointer type, which could be a worthwhile addition.
I've been engaged over the past few months in an exercise in Yak-shaving, wherein I re-implemented this crate in a couple of different ways, before finally deciding to just contribute to the already existing and much higher quality solution. The main feature that I need is the allocation of proper DSTs, which this crate doesn't support.
Although in the end my solution to this problem was to use nightly to get access to the
ptr_metadata
feature, one of the interceding versions simply polyfilled that feature in order to be able to allocate a subset of unsized types in aGc
.The whole point of this is to store a function which computes a layout in the
CollectVtable
instead of storing a static layout, so as to allow truly dynamically sizedGc
pointers.Proposed API
The additional API surface, and changes to existing structs, is very very roughly as follows. And although I'm not hugely familiar with this code base, I don't see anywhere obvious which is antithetical to this approach.
Downsides
There are of course downsides; it adds indirection where there previously was none; it is a fair amount of complexity to add; it's not truly general for all unsized types, just those which implement a crate-private trait; and I'm sure there are more. On the other hand, for all
Sized
types, this actually frees up 8 bytes in theCollectVtable
without adding any data to theGcBoxInner
, the other upsides I believe far outweigh the costs, and I'm happy to implement it myself if this seems up to snuff.Playground with enough code to convince me that this is doable on stable, and frankly probably more than is necessary.
The text was updated successfully, but these errors were encountered: