Search code examples
rustcollectionsdeque

How to create a VecDeque with limited size?


I want to implement a VecDeque with a maximum size limit. I have two strategies but I can't complete either.

First approach: Inheritance by composition.

I Created a new struct:

pub struct LimVecDeque<T> {                                                                                                    
     deque: VecDeque<T>,                                                 
     limit: usize,                                                       
}

And create a new push function:

impl<T> LimVecDeque<T> {
  ...

  pub fn push (&self, elem: T) {
    self.deque.push_back(elem);
    if self.limit < self.deque.len() {
      self.deque.pop_front();
    }
  }

  ...
}

This works but, as my program grow up, I require to add functionality to my LimVecDeque struct. Most of them is a copy from the original VecDeque:

pub fn len(&self) -> usize {
  self.deque.len()
}

I have more problems to export VecDeque::iter(). I had problems with types and iterators (I'm not very good with iterators yet). This approach forces me to clone/export each function in VecDeque into LimVecDeque. Lot of work!

Second Approach: Create a new trait and implement for VecDeque:

trait Limited {
  type Elem;

  pub fn push_bounded(&self, limit: usize, elem: Elem);
}

and later implement the trait for VecDeque.

But I have to pass limit value in each insertion. How can pass limit value once?

In general, What is an easy way to add functionality to an struct from std (without loosing/hiding current ones)?


Solution

  • As pointed out by edkeveked's answer, there is a crate available (BoundedVecDequeue), which implements the exact case you are trying to implement.

    If you look at the implementation of BoundedVecDequeue you will see that it uses the first pattern you describe: to create wrapper methods where it is necessary to modify the behaivour of the wrapped type, and to delegate method calls where it is not.

    As you point out, this could result in a lot of boilerplate. To reduce the amount of work involved, you might like to try the delegate crate, which adds a macro that does the delegation for you:

    use delegate::delegate;
    
    impl<T> LimVecDeque<T> {
        delegate! {
            to self.inner {
    
                pub fn len(&self) -> usize;
                pub fn truncate(&mut self, new_len: usize);
                pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]);
                // etc
            }
        }
    
        // ...
    
    }
    

    Caveat: I have not actually used this crate myself yet, so I can't vouch for it's quality.