pointer-utils icon indicating copy to clipboard operation
pointer-utils copied to clipboard

`slice-dst`: Provide example for custom 'slices' using `SliceWithHeader`

Open MattesWhite opened this issue 3 years ago • 7 comments

Thank you for this awesome crate. I always respect when people dive into the unsafe world of Rust.

I'd like to use the slice-dst crate to build something similar to String and str. Let's assume:

struct MyString(Box<SliceWithHeader<Info, u8>>);

To mimicry str I want to implement Borrow<MyStr> for MyString and ToOwned for MyStr (type Owned = MyString). However, I have a problem defining MyStr. I could use a type alias:

type MyStr = SliceWithHeader<Info, u8>;

But this is inconvenient and won't allow some custom impl MyStr. What I would like is to use is a new-type-pattern. But this makes it difficult implementing Borrow:

struct MyStr(SliceWithHeader<Info, u8>);

impl Borrow<MyStr> for MyString {
    fn borrow(&self) -> &MyStr {
        &*self.0 // <-- requires some cast/convertion/idk
    }
}

Would it be safe to simple cast the reference from the Box within MyString to a &MyStr or would this be undefined behavior?

MattesWhite avatar Apr 07 '21 11:04 MattesWhite

If you don't mind third parties being able to perform the cast safely, the ref-cast crate automates the required bits to cast from &SliceWithHeader<Info, u8> to &MyStr. If you need to make the cast private, for now you have to do it yourself with a #[repr(transparent)] and an unsafe pointer reinterpreting (&*(self.0 as *const _ as *const _)).

It's still on my todo list to make a #[derive(SliceDst)] that'd allow you to just write something like

#[derive(SliceDst)]
#[repr(C)]
#[slice_dst(new(Info, &[u8]))]
struct MyStr(Info, [u8]);

and get a custom type like SliceWithHeader, but I've just not found the time to do it yet.

CAD97 avatar Apr 08 '21 01:04 CAD97

Is there something specific I can call out in the documentation to help direct people towards the correct practice for this? It's pretty much standard requirement for wrappers around unsized types to know how/when you can go from &T to &U, so (as someone who has that as baseline knowledge) I don't know where best to put that callout.

CAD97 avatar Apr 08 '21 01:04 CAD97

Thank you. That helped a lot. Pulling in a third-party crate to ensure soundness seems feasible to me. Personally, I hoped to find a well documented example in the project's repository.

MattesWhite avatar Apr 08 '21 05:04 MattesWhite

To go a little bit further and to stay with the MyString example, if I want to have a mutable buffer like type like String I have to manage things like capacity and reallocation of heap by myself, right?

MattesWhite avatar Apr 08 '21 05:04 MattesWhite

You would need to track the initialized prefix and handle reallocation. Actually, implementing our own Slice/SliceBuf pair would be an interesting case study for the docs... 🤔💭

Unfortunately I don't really have the time (or the clear freedom) to write up such a walkthrough / book-format material right now, but I'd be happy to mentor/guide/edit/review someone else doing so.

CAD97 avatar Apr 08 '21 21:04 CAD97

The basic formula:

Store Box<WithHeader< Header, [MaybeUninit<T>] >>. In Header, track which elements are initialized. When pushing a new element that requires reallocation, make a new Box<...> by copying over the content from the existing one (but with some more MaybeUninit<_> capacity), then swap in the new box and do the regular push.

Capacity is the length of your [MaybeUninit<T>]. Length is stored in your header (or in your stack part, if you want to be like Vec). If you want a thin pointer, store length alongside the slice as well (SliceWithHeader does this) and use Thin (from erasable).

Probably the best format to show off the tools I'm providing would be to write a ThinVec<_> where size_of::<ThinVec<_>>() == size_of::<*mut u8>() but that otherwise functions like a Vec (with a bare minimum of surface API to avoid clogging the example).

CAD97 avatar Apr 08 '21 21:04 CAD97

Okay, this looks manageable to me. I think I'll give it a try when I find the time... after I looked into my own university contract :sweat_smile:

MattesWhite avatar Apr 09 '21 05:04 MattesWhite