CAD97/pointer-utils

Ability to use `SliceWithHeader` in a newtype directly without `Box`

Opened this issue · 1 comments

I want to make a pair of newtypes MySlice(SliceWithHeader<HeaderType, u8>) and MyVec(HeaderType, Vec<u8>), so that MySlice is to MyVec as [u8] is to Vec<u8>.

It seems as per #69 that this crate offers only the ability to make MySlice(Box<SliceWithHeader<...>>) with Box (or Rc, Arc) but not without the Box.

I know it's possible to do this without the header as per How can I create newtypes for an unsized type and its owned counterpart (like str and String) in safe Rust? - Stack Overflow. But it's not clear to me how to get both (i) no Box, and (ii) header. Any suggestion?

For a newtype MySlice(SliceWithHeader<H, I>), you can soundly cast between Box<SliceWithHeader<H, I>> and Box<MySlice> if MySlice is #[repr(transparent)]1. If you want to forward the trait impls as well, those currently need to be manually written.

The MyVec type needs to store a VecWithHeader<A, B>, not (A, Vec<B>), if it wants to dereference to MySlice (SliceWithHeader<A, B>), as the header needs to be inline in the heap allocation. Unfortunately, this library doesn't offer such a type (yet?) as my driving usage has been focused on FAM style usage which is roughly Box<(A, [B])>, not resizable.

Longer-term, I want to provide a #[derive(SliceDst)] that would hopefully make the definition of custom slice-tailed DST types simpler. This work has been delayed on vague hopes of feature(ptr_metadata) progressing, but I'm now looking at potentially updating the current libraries that work without.

The general usage pattern currently expects you to always tie the header and tail together at the "top" level, i.e. ((A, B), [I]) and not (A, (B, [I])), as the former is much simpler to construct. The AllocSliceDst API does support initialization of non-SliceWithHeader slice DSTs, but exposing a safe API for such is difficult, especially in a generic (or even derivable) fashion.

I do want to make this more compositional (e.g. allow not storing the slice length inline if the erasable pointer support isn't needed) but doing so soundly isn't straightforward. However, I do have some ideas I'm experimenting with, that altogether I hope justify a major version bump even without the ptr_metadata improvements.

Footnotes

  1. Doing so directly with transmute isn't guaranteed to work, so the correct way to do the cast is Box::from_raw(Box::into_raw(this) as *mut MySlice). The docs guarantee that this is safe (w.r.t. Box) if the allocation layout (size and align) of the pointee type is the same.