Reputation: 69249
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
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