zeph_memory/semantic/
write_buffer.rs1use std::collections::VecDeque;
11
12use crate::types::{ConversationId, MemoryTier};
13
14pub enum BufferedWrite {
16 SaveMessage {
18 conversation_id: ConversationId,
19 role: String,
20 content: String,
21 tier: MemoryTier,
22 },
23 UpsertPersonaFact {
25 category: String,
26 content: String,
27 confidence: f64,
28 source_conversation_id: Option<i64>,
29 supersedes_id: Option<i64>,
30 },
31 StoreEmbedding {
33 collection: String,
34 point_id: String,
35 vector: Vec<f32>,
36 payload: serde_json::Value,
37 },
38}
39
40pub struct WriteBuffer {
45 pending: VecDeque<BufferedWrite>,
46 capacity: usize,
48}
49
50impl WriteBuffer {
51 #[must_use]
55 pub fn new(capacity: usize) -> Self {
56 Self {
57 pending: VecDeque::with_capacity(capacity),
58 capacity,
59 }
60 }
61
62 pub fn push(&mut self, write: BufferedWrite) -> bool {
67 self.pending.push_back(write);
68 self.pending.len() >= self.capacity
69 }
70
71 pub fn drain(&mut self) -> Vec<BufferedWrite> {
75 self.pending.drain(..).collect()
76 }
77
78 #[must_use]
79 pub fn len(&self) -> usize {
80 self.pending.len()
81 }
82
83 #[must_use]
84 pub fn is_empty(&self) -> bool {
85 self.pending.is_empty()
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use crate::types::{ConversationId, MemoryTier};
93
94 fn make_save_message() -> BufferedWrite {
95 BufferedWrite::SaveMessage {
96 conversation_id: ConversationId(1),
97 role: "user".into(),
98 content: "hello".into(),
99 tier: MemoryTier::Episodic,
100 }
101 }
102
103 #[test]
104 fn push_increases_len() {
105 let mut buf = WriteBuffer::new(5);
106 assert!(buf.is_empty());
107 buf.push(make_save_message());
108 assert_eq!(buf.len(), 1);
109 }
110
111 #[test]
112 fn push_returns_false_below_capacity() {
113 let mut buf = WriteBuffer::new(3);
114 let at_capacity = buf.push(make_save_message());
115 assert!(!at_capacity);
116 let at_capacity = buf.push(make_save_message());
117 assert!(!at_capacity);
118 }
119
120 #[test]
121 fn push_returns_true_at_capacity() {
122 let mut buf = WriteBuffer::new(2);
123 buf.push(make_save_message());
124 let at_capacity = buf.push(make_save_message());
125 assert!(at_capacity);
126 }
127
128 #[test]
129 fn drain_returns_all_items_and_clears_buffer() {
130 let mut buf = WriteBuffer::new(10);
131 buf.push(make_save_message());
132 buf.push(make_save_message());
133 buf.push(make_save_message());
134
135 let drained = buf.drain();
136 assert_eq!(drained.len(), 3);
137 assert!(buf.is_empty());
138 assert_eq!(buf.len(), 0);
139 }
140
141 #[test]
142 fn drain_on_empty_buffer_returns_empty_vec() {
143 let mut buf = WriteBuffer::new(5);
144 let drained = buf.drain();
145 assert!(drained.is_empty());
146 }
147
148 #[test]
149 fn capacity_one_signals_on_first_push() {
150 let mut buf = WriteBuffer::new(1);
151 let at_capacity = buf.push(make_save_message());
152 assert!(at_capacity);
153 }
154}