skiwi
skiwi

Reputation: 69249

Is it possible to return part of a struct by reference?

Consider the following two structs:

pub struct BitVector<S: BitStorage> {
    data: Vec<S>,
    capacity: usize,
    storage_size: usize
}

pub struct BitSlice<'a, S: BitStorage> {
    data: &'a [S],
    storage_size: usize
}

Where BitStorage is practically a type that is restricted to all unsigned integers (u8, u16, u32, u64, usize).

How to implement the Deref trait? (BitVector<S> derefs to BitSlice<S> similar to how Vec<S> derefs to &[S])

I have tried the following (Note that it doesn't compile due to issues with lifetimes, but more importantly because I try to return a value on the stack as a reference):

impl<'b, S: BitStorage> Deref for BitVector<S> {
    type Target = BitSlice<'b, S>;

    fn deref<'a>(&'a self) -> &'a BitSlice<'b, S> {
        let slice = BitSlice {
            data: self.data,
            storage_size: self.storage_size,
        };
        &slice
    }
}

I am aware that it is possible to return a field of a struct by reference, so for example I could return &Vec<S> or &usize in the Deref trait, but is it possible to return a BitSlice noting that I essentially have all the data in the BitVector already as Vec<S> can be transformed into &[S] and storage_size is already there?

I would think this is possible if I could create a struct using both values and somehow tell the compiler to ignore the fact that it is a struct that is created on the stack and instead just use the existing values, but I have got no clue how.

Upvotes: 2

Views: 95

Answers (1)

user395760
user395760

Reputation:

Deref is required to return a reference. A reference always points to some existing memory, and any local variable will not exist long enough. While there are, in theory, some sick tricks you could play to create a new object in deref and return a reference to it, all that I'm aware of result in a memory leak. Let's ignore these technicalities and just say it's plain impossible.

Now what? You'll have to change your API. Vec can implement Deref because it derefs to [T], not to &[T] or anything like that. You may have success with the same strategy: Make BitSlice<S> an unsized type containing only a slice [S], so that the return type is &'a BitSlice<S>. This assume the storage_size member is not needed. But it seems that this refers to the number of bits that are logically valid (i.e., can be accessed without extending the bit vector) — if so, that seems unavoidable1.

The other alternative, of course, is to not implement a Deref. Inconvenient, but if your slice data type is too far from an actual slice, it may be the only option.

RFC PR #1524 that proposed custom dynamically-sized types, then you could have a type BitSlice<S> that is like a slice but can have additional contents such as storage_size. However, this doesn't exist yet and it's far from certain if it ever will.

1 The capacity member on BitVector, however, seems pointless. Isn't that just sizeof S * 8?

Upvotes: 2

Related Questions