How do I a custom pair of owned/borrowed types?

So say I have a bog-standard two-dimensional buffer type that owns its data:

pub struct Buf<T> {
    w: usize,
    h: usize,
    data: Vec<T>,
}

I want to borrow rectangular regions from a Buf, so I write

pub struct Slice<'a, T> {
    w: usize,
    h: usize,
    stride: usize,
    data: &'a [T], // starts at the top-left element of the slice
}

These are direct two-dimensional analogues of Vec<T> and &[T]. However, because my Slice is not a real reference type, it seems that I can implement neither Deref, Borrow, AsRef, or Index[Mut]<Output=Slice<T>> for Buf, each of those traits only working with builtin references. I can write custom slice and as_slice methods, but what's the best way to avoid duplication of code given that Buf and Slice have nigh identical interfaces? Vec gets all of its common API for free via Deref coercion to &[T], but that's not possible here.

1 Like

Indeed, this is going to be cumbersome. You will need your own non-standard methods.

"Custom DSTs" are an old feature request, still not available.

For now if you want to fake fat pointer semantics, the best you can do is ensure that your Buf and Slice are #[repr(C)] and that Buf contains data layout compatible with Slice for pointer-casting shenanigans. Sadly layout of Vec is data, capacity, len, not data, len, capacity, so it can't be cast to a slice, so you'd need to handle the pointers yourself.

1 Like

I ended up with the following pattern, which I guess works fine, at the expense of exposing the additional Inner type (should probably figure out a better name for it).

#[repr(transparent)]
pub struct Buf<T>(Inner<T, Vec<T>>);

impl<T> Deref for Buf<T> { /* delegate to Inner */ }
impl<T> DerefMut for Buf<T> { /* ... */ }

#[repr(transparent)]
pub struct Slice<'a, T>(Inner<T, &'a [T]>);

impl<'a, T> Deref for Slice<'a, T> { /* ... */ }

#[repr(transparent)]
pub struct SliceMut<'a, T>(Inner<T, &'a mut [T]>);

impl<'a, T> Deref for SliceMut<'a, T> { ... }
impl<'a, T> DerefMut for SliceMut<'a, T> { ... }

pub struct Inner<T, D> {
    w: usize,
    h: usize,
    stride: usize,
    data: D,
    _pd: PhantomData<T>,
}

impl<T, D: AsRef<[T]>> Inner<T, D> { /* common API */ }
impl<T, D: AsMut<[T]>> Inner<T, D> { /* common mutable API */ }

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.