Skip to content
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

Ability to use SliceWithHeader in a newtype directly without Box #88

Open
ggutoski opened this issue May 1, 2024 · 1 comment
Open

Comments

@ggutoski
Copy link

ggutoski commented May 1, 2024

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?

@CAD97
Copy link
Owner

CAD97 commented May 2, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants