-
Notifications
You must be signed in to change notification settings - Fork 138
Description
Currently Ref is defined as:
Line 1417 in 52ffa4d
| pub struct Ref<B, T: ?Sized>(B, PhantomData<T>); |
This has the consequence that, even if T: Sized, when in principle Ref could be a single-word thin pointer, Ref is still as large as B. Usually this is two words (e.g. for &[u8]), but sometimes it's more (e.g. for core::cell::Ref, which has a reference count).
For some types, this is unavoidable. E.g., no matter what we do, we need to store the entire core::cell::Ref - if we didn't, we'd be leaking memory. But for some types - such as &[u8] - we can reconstruct the original B: ByteSlice just from a pointer to T.
Thus, I propose the following addition to ByteSlice:
trait ByteSlice {
// Name to be bikeshedded later. We may not want to tie the name to the `Ref`
// type since we plan on maybe making `ByteSlice` unsealed at some point.
//
// For `&[u8]`/`&mut [u8]`, this is just `NonNullFoo<T>`. For `core::cell::Ref`/
// `core::cell::RefMut`, this is just `Self`.
type Foo<T: ?Sized>: AsRef<[u8]> + AsMut<[u8]>;
// Either discards `foo`, constructing `Foo` from `self` (e.g. for `core::cell::Ref`),
// or discards `self`, constructing `Foo` from `foo` (e.g. for `&[u8]`).
//
// SAFETY: Caller promises that `ptr` references a sequence of bytes which are
// all initialized. That ensures that we can implement `AsRef<[u8]>`/`AsMut<[u8]>`
// without a `T: AsBytes` bound.
unsafe fn into_foo<T: ?Sized>(self, foo: NonNullFoo<T>) -> Self::Foo;
}
struct NonNullFoo<T> {
// Invariant: Always references a fully-initialized sequences of bytes. This is fine
// because this is always constructed from a `B: ByteSlice` during `Ref` construction.
inner: NonNull<T>,
}
// NOTE: Caller needs to ensure the `NonNullFoo` doesn't live for too long since
// these methods are not `usnafe`. Might need to be a safety requirement on
// `ByteSlice::into_foo`.
impl<T> AsRef<[u8]> for NonNullFoo<T> { ... }
impl<T> AsMut<[u8]> for NonNullFoo<T> { ... }Then, we update Ref:
struct Ref<B, T: ?Sized>(<B as ByteSlice>::Foo<T>, PhantomData<B>);cc @kupiakos , I know you were interested in having this, and I remember you mentioned taking a stab at some ideas for how to implement it