Collection Adapters and Specialized Types

push_front() and push_back()

The .push_front(value) and .push_back(value) methods on VecDeque<T> (and LinkedList<T>) insert an element at the beginning (logical index 0) or end (logical index len) of the sequence in amortized $O(1)$ time.

Signatures and Ring-Buffer Mechanics

impl<T> VecDeque<T> {
    pub fn push_front(&mut self, value: T);
    pub fn push_back(&mut self, value: T);
}
Initial Ring Buffer (capacity = 4, head = 0, len = 2):
+------+------+------+------+
|  10  |  20  |  --  |  --  |   Logical view: [10, 20]
+------+------+------+------+
  [0]    [1]    [2]    [3]
   ▲
  head

1. q.push_back(30)  ──> writes at (head + len) % 4 = [2], len becomes 3:
+------+------+------+------+
|  10  |  20  |  30  |  --  |   Logical view: [10, 20, 30]
+------+------+------+------+

2. q.push_front(5)  ──> decrements head modulo 4 to [3], writes 5 at [3], len becomes 4:
+------+------+------+------+
|  10  |  20  |  30  |   5  |   Logical view: [5, 10, 20, 30]
+------+------+------+------+
                        ▲
                       head

Notice that q.push_front(5) wraps head around to the end of the physical buffer ([3]) without moving 10, 20, or 30!

Building a Deque from Both Ends

push_front and push_back allow you to prioritize urgent items at the front of a work queue while appending normal items to the back:

use std::collections::VecDeque;

fn main() {
    let mut jobs = VecDeque::new();

    // Normal jobs go to the back (FIFO):
    jobs.push_back("sync_logs");
    jobs.push_back("generate_report");

    // High-priority interrupt goes to the front (LIFO / urgent):
    jobs.push_front("handle_healthcheck");

    println!("Execution order: {jobs:?}");
}
Execution order: ["handle_healthcheck", "sync_logs", "generate_report"]

Sliding Window / Bounded History Buffer Pattern

Combining push_back with pop_front when len == max_len maintains a fixed-capacity rolling history of the most recent $N$ events in $O(1)$ time per event with zero reallocations after warm-up:

use std::collections::VecDeque;

struct RecentHistory<T> {
    buf: VecDeque<T>,
    max_items: usize,
}

impl<T> RecentHistory<T> {
    fn new(max_items: usize) -> Self {
        Self {
            buf: VecDeque::with_capacity(max_items),
            max_items,
        }
    }

    fn record(&mut self, item: T) {
        if self.buf.len() == self.max_items {
            self.buf.pop_front(); // Evict oldest item in O(1)
        }
        self.buf.push_back(item); // Append newest item in O(1)
    }
}

fn main() {
    let mut history = RecentHistory::new(3);
    for cmd in ["ls", "cd src", "cargo check", "cargo test"] {
        history.record(cmd);
    }

    println!("Last 3 commands: {:?}", history.buf);
}
Last 3 commands: ["cd src", "cargo check", "cargo test"]