&mut Vec<T> that can only modify elements, but not push/pop elements

I want to build a wrapper around Vec<T>, say

FixedSizeVec<T: Clone>(Vec<T>)

impl <T> FixedSizeVec<T> {
  pub fn new(n: usize, t: T) -> FixedSizeVec<T> {
    // T
  }
}

Now, I want to keep as much of the functionality of Vec as possible, but ensure that push/pop is impossible. Is there a known idiomatic solution to this problem?

Most of Vec's functionality is available because it dereferences to a slice. If your type does the same, then you'll be able to call all of the slice methods, which include accessing and modifying elements but not changing size:

impl<T> Deref for FixedSizeVec<T> {
    type Target = [T];
    fn deref(&self) -> &[T] { &self.0 }
}

impl<T> DerefMut for FixedSizeVec<T> {
    fn deref_mut(&mut self) -> &mut [T] { &mut self.0 }
}

Now you can use FixedSizeVec just like other slice-pointer types:

let mut v = FixedSizeVec::new(5, "hello");
v[4] = "goodbye";
v.sort();
println!("{:?}", &v[0..2]);

Playground

3 Likes

This is brilliant. Expanding on your chain of logic, a vec that we can only modify but not change size is basically a &'a mut [T]. So we are tempted to write:

FixedSizeVec<'a, T>(&'a mut [T]);

but then to avoid lifetimes, we would have to make it

FixedSizeVec<T>(Vec<T>);

and have it return a &'a mut [T] instead. This makes sense now. Thanks!

You can use struct FixedSizeVec<T>(Box<[T]>); to save the space for capacity field, or directly use Box<[T]> itself.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.