Implementing Deref to DST for vector newtype with extra field

Is there any way to implement Deref in a situation like the following?

use std::ops::Deref;

struct Foo {
    info: usize,
    data: Vec<f64>
}

struct FooView {
    info: usize,
    data: [f64],
}

impl Deref for Foo {
    type Target = FooView;

    fn deref(&self) -> &Self::Target {
        todo!()
    }
}

Playground.

In the situation without the info field, I gather that this is possible by marking the structs #[repr(transparent)] and doing a pointer cast or something like ref_cast. The nomicon also shows how to achieve something similar using "unsizing coercion", but I cannot quite make the same thing work when Foo contains a vector instead of an array.

This is impossible, since Foo and FooView have fundamentally different layouts. In Foo, float values are stored elsewhere, and the struct itself contains a pointer to them; but in FooView, float values are stored inline, next to the info field.

Right. That's a shame, but good to know. Thank you!

If you don't really depend on the Vec in Foo you can use the slice-dst crate to store info and data inline which would allow to use ref_case. Funny enough, I have currently a PR open that adds an example that implements Deref.

1 Like

That's interesting, thanks! For anyone (including myself) who stumbles on this in the future, I guess the idea would be along the following lines (for the simple case without Vec):

use std::{boxed::Box, ops::Deref};

use ref_cast::RefCast;

use slice_dst::SliceWithHeader;

struct Foo(Box<SliceWithHeader<usize, f64>>);

#[derive(RefCast)]
#[repr(transparent)]
struct FooView(SliceWithHeader<usize, f64>);

impl Deref for Foo {
    type Target = FooView;

    fn deref(&self) -> &Self::Target {
        FooView::ref_cast(&self.0)
    }
}

It's a shame that the header also has to go on the heap, but very neat that it's possible without unsafe. Thank you for the PR, also, it was helpful to see an example.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.