Skip to main content

agent_io/memory/
buffer.rs

1//! Ring buffer for short-term memory
2
3use std::collections::VecDeque;
4
5/// A fixed-size ring buffer for storing recent items
6#[derive(Debug, Clone)]
7pub struct RingBuffer<T> {
8    buffer: VecDeque<T>,
9    capacity: usize,
10}
11
12impl<T> RingBuffer<T> {
13    /// Create a new ring buffer with the given capacity
14    pub fn new(capacity: usize) -> Self {
15        Self {
16            buffer: VecDeque::with_capacity(capacity),
17            capacity: capacity.max(1),
18        }
19    }
20
21    /// Push an item to the buffer, removing the oldest if at capacity
22    pub fn push(&mut self, item: T) {
23        if self.buffer.len() == self.capacity {
24            self.buffer.pop_front();
25        }
26        self.buffer.push_back(item);
27    }
28
29    /// Pop the most recent item
30    pub fn pop(&mut self) -> Option<T> {
31        self.buffer.pop_back()
32    }
33
34    /// Get the number of items in the buffer
35    pub fn len(&self) -> usize {
36        self.buffer.len()
37    }
38
39    /// Check if the buffer is empty
40    pub fn is_empty(&self) -> bool {
41        self.buffer.is_empty()
42    }
43
44    /// Check if the buffer is full
45    pub fn is_full(&self) -> bool {
46        self.buffer.len() == self.capacity
47    }
48
49    /// Get the capacity
50    pub fn capacity(&self) -> usize {
51        self.capacity
52    }
53
54    /// Iterate over items (most recent last)
55    pub fn iter(&self) -> impl Iterator<Item = &T> {
56        self.buffer.iter()
57    }
58
59    /// Iterate over items (most recent first)
60    pub fn iter_recent(&self) -> impl Iterator<Item = &T> {
61        self.buffer.iter().rev()
62    }
63
64    /// Get the most recent item
65    pub fn last(&self) -> Option<&T> {
66        self.buffer.back()
67    }
68
69    /// Get the oldest item
70    pub fn first(&self) -> Option<&T> {
71        self.buffer.front()
72    }
73
74    /// Clear the buffer
75    pub fn clear(&mut self) {
76        self.buffer.clear();
77    }
78
79    /// Get all items as a vector (oldest first)
80    pub fn to_vec(&self) -> Vec<T>
81    where
82        T: Clone,
83    {
84        self.buffer.iter().cloned().collect()
85    }
86
87    /// Get all items as a vector (most recent first)
88    pub fn to_vec_recent(&self) -> Vec<T>
89    where
90        T: Clone,
91    {
92        self.buffer.iter().rev().cloned().collect()
93    }
94}
95
96impl<T: Clone> RingBuffer<T> {
97    /// Create from an existing vector
98    pub fn from_vec(items: Vec<T>, capacity: usize) -> Self {
99        let capacity = capacity.max(1);
100        let mut buffer = VecDeque::with_capacity(capacity);
101
102        // Take only the most recent `capacity` items
103        let start = items.len().saturating_sub(capacity);
104        for item in items.into_iter().skip(start) {
105            if buffer.len() < capacity {
106                buffer.push_back(item);
107            }
108        }
109
110        Self { buffer, capacity }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_ring_buffer_basic() {
120        let mut buf: RingBuffer<i32> = RingBuffer::new(3);
121
122        buf.push(1);
123        buf.push(2);
124        buf.push(3);
125
126        assert_eq!(buf.len(), 3);
127        assert_eq!(buf.to_vec(), vec![1, 2, 3]);
128    }
129
130    #[test]
131    fn test_ring_buffer_overflow() {
132        let mut buf: RingBuffer<i32> = RingBuffer::new(3);
133
134        buf.push(1);
135        buf.push(2);
136        buf.push(3);
137        buf.push(4); // Should push out 1
138
139        assert_eq!(buf.len(), 3);
140        assert_eq!(buf.to_vec(), vec![2, 3, 4]);
141    }
142
143    #[test]
144    fn test_ring_buffer_iter_recent() {
145        let mut buf: RingBuffer<i32> = RingBuffer::new(3);
146
147        buf.push(1);
148        buf.push(2);
149        buf.push(3);
150
151        let recent: Vec<_> = buf.iter_recent().copied().collect();
152        assert_eq!(recent, vec![3, 2, 1]);
153    }
154
155    #[test]
156    fn test_ring_buffer_pop() {
157        let mut buf: RingBuffer<i32> = RingBuffer::new(3);
158
159        buf.push(1);
160        buf.push(2);
161
162        assert_eq!(buf.pop(), Some(2));
163        assert_eq!(buf.len(), 1);
164    }
165}