VecDeque Ring Buffers
VecDeque is a growable ring buffer for queues and double-ended queues, giving efficient push and pop operations at both the front and the back.
What it is
VecDeque<T> is the standard double-ended queue.
It is useful when a sequence needs efficient work at both ends.
It fills the gap between Vec and specialized queue structures.
Use VecDeque for:
- FIFO queues
- sliding windows
- breadth-first traversal frontiers
- producer-consumer buffers
- deques where both ends are active
Use Vec when the sequence mostly grows and shrinks at the end.
The standard docs explicitly note that Vec is often faster when both choices are otherwise tied.
How it works
VecDeque stores elements in a growable ring buffer.
The logical start of the sequence may be in the middle of the allocation.
Pushing at the front can move the start backward.
Pushing at the back can move the end forward.
When either side reaches the allocation boundary, indexing wraps around.
This is why VecDeque can push and pop at both ends efficiently.
It is also why its contents are not always one contiguous slice.
Methods such as as_slices expose the two physical slices.
make_contiguous can rotate elements so the logical sequence is one slice.
Common methods include:
newwith_capacitypush_backpush_frontpop_backpop_frontfrontbackrotate_leftrotate_rightmake_contiguous
Example
use std::collections::VecDeque;
fn main() {
let mut queue = VecDeque::new();
queue.push_back("parse");
queue.push_back("typecheck");
queue.push_front("read");
assert_eq!(queue.pop_front(), Some("read"));
assert_eq!(queue.front(), Some(&"parse"));
assert_eq!(queue.pop_front(), Some("parse"));
assert_eq!(queue.pop_front(), Some("typecheck"));
assert_eq!(queue.pop_front(), None);
}Edge cases
use std::collections::VecDeque;
fn main() {
let mut window: VecDeque<i32> = VecDeque::from([1, 2, 3]);
window.push_back(4);
window.pop_front();
let contiguous = window.make_contiguous();
contiguous.sort_unstable();
assert_eq!(window.into_iter().collect::<Vec<_>>(), [2, 3, 4]);
}Best practice
- ✅ Use
VecDequefor FIFO queues instead of repeatedly removingVec[0]. - ✅ Use
push_backpluspop_frontfor ordinary queue behavior. - ✅ Use
with_capacitywhen a queue has a known upper bound or expected size. - ✅ Use
frontandbackto peek without removing. - ✅ Use
make_contiguousonly when an API needs a single slice or you want to sort the deque. - ✅ Prefer
Vecfor append-only sequences, stacks, and dense random access workloads. - ✅ Prefer
BinaryHeapwhen the next item is selected by priority rather than arrival order.
Pitfalls
- ⚠️ Treating
VecDequestorage as always contiguous is wrong; useas_slicesormake_contiguous. - ⚠️ Removing from the front of a
Vecrepeatedly is O(n) per removal; useVecDeque. - ⚠️ Assuming
VecDequebeatsVecfor all sequence workloads ignores cache locality and simpler layout. - ⚠️ Holding references into a deque while pushing or popping can conflict with mutation; see Holding Collection Element References Across Mutation.
- ⚠️
make_contiguousmay move elements inside the allocation, so avoid calling it in a hot loop without need. - ⚠️ A deque is not a priority queue; see BinaryHeap Priority Queues.
See also
std: Collections Deep · VecDeque · Vec · Choosing Standard Collections · BinaryHeap Priority Queues · Capacity and Reallocation · Iterating Collections · Holding Collection Element References Across Mutation · Stale Slice Indices · Iterator Performance
Sources
- Rust standard library,
VecDeque- std, https://doc.rust-lang.org/std/collections/struct.VecDeque.html - Rust standard library, “Use a VecDeque when” - std, https://doc.rust-lang.org/std/collections/index.html#use-a-vecdeque-when
