Skip to main content

marisa/
agent.rs

1//! Agent for trie operations.
2//!
3//! Ported from:
4//! - include/marisa/agent.h
5//! - lib/marisa/agent.cc
6
7use crate::grimoire::trie::state::{State, StatusCode};
8use crate::key::Key;
9use crate::query::Query;
10use std::io;
11
12/// Agent encapsulates query, key, and state for trie operations.
13///
14/// An agent is used for:
15/// - Lookup operations (query → key with ID)
16/// - Reverse lookup (query with ID → key with string)
17/// - Common prefix search
18/// - Predictive search
19pub struct Agent {
20    /// Query for search operations.
21    query: Query,
22    /// Key result from operations.
23    key: Key,
24    /// Optional state for complex searches.
25    state: Option<Box<State>>,
26}
27
28impl Default for Agent {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl Clone for Agent {
35    fn clone(&self) -> Self {
36        let mut cloned = Agent {
37            query: self.query.clone(),
38            key: self.key.clone(),
39            state: self.state.as_ref().map(|s| Box::new((**s).clone())),
40        };
41
42        // Update agent after copying state
43        let should_update = cloned.state.is_some();
44        if should_update {
45            if let Some(ref state) = cloned.state {
46                let status = state.status_code();
47                match status {
48                    StatusCode::ReadyToPredictiveSearch | StatusCode::EndOfPredictiveSearch => {
49                        // Key points into state buffer - repoint after copy
50                        let key_buf = state.key_buf();
51                        cloned.key.set_bytes(key_buf);
52                    }
53                    _ => {
54                        // Key is null or points to query - no update needed
55                    }
56                }
57            }
58        }
59
60        cloned
61    }
62}
63
64impl Agent {
65    /// Creates a new empty agent.
66    pub fn new() -> Self {
67        Agent {
68            query: Query::new(),
69            key: Key::new(),
70            state: None,
71        }
72    }
73
74    /// Returns a reference to the query.
75    pub fn query(&self) -> &Query {
76        &self.query
77    }
78
79    /// Returns a mutable reference to the query.
80    pub fn query_mut(&mut self) -> &mut Query {
81        &mut self.query
82    }
83
84    /// Returns a reference to the key.
85    pub fn key(&self) -> &Key {
86        &self.key
87    }
88
89    /// Returns a mutable reference to the key.
90    pub fn key_mut(&mut self) -> &mut Key {
91        &mut self.key
92    }
93
94    /// Sets the query from a string slice.
95    pub fn set_query_str(&mut self, s: &str) {
96        if let Some(ref mut state) = self.state {
97            state.reset();
98        }
99        self.query.set_str(s);
100    }
101
102    /// Sets the query from a byte slice.
103    pub fn set_query_bytes(&mut self, bytes: &[u8]) {
104        if let Some(ref mut state) = self.state {
105            state.reset();
106        }
107        self.query.set_bytes(bytes);
108    }
109
110    /// Sets the query from a key ID for reverse lookup.
111    pub fn set_query_id(&mut self, key_id: usize) {
112        if let Some(ref mut state) = self.state {
113            state.reset();
114        }
115        self.query.set_id(key_id);
116    }
117
118    /// Returns a reference to the state if it exists.
119    pub fn state(&self) -> Option<&State> {
120        self.state.as_deref()
121    }
122
123    /// Returns a mutable reference to the state if it exists.
124    pub fn state_mut(&mut self) -> Option<&mut State> {
125        self.state.as_deref_mut()
126    }
127
128    /// Sets the key from a string slice.
129    pub fn set_key_str(&mut self, s: &str) {
130        self.key.set_str(s);
131    }
132
133    /// Sets the key from a byte slice.
134    pub fn set_key_bytes(&mut self, bytes: &[u8]) {
135        self.key.set_bytes(bytes);
136    }
137
138    /// Sets the key ID.
139    pub fn set_key_id(&mut self, id: usize) {
140        self.key.set_id(id);
141    }
142
143    /// Sets the key to point to the state's key buffer.
144    ///
145    /// This is used after operations like reverse_lookup that build
146    /// the key in the state's buffer.
147    pub fn set_key_from_state_buf(&mut self) {
148        if let Some(ref state) = self.state {
149            let buf = state.key_buf();
150            // Set key to point to state's buffer
151            // SAFETY: The buffer is owned by state which is owned by self,
152            // so it will live as long as self lives.
153            self.key.set_bytes(buf);
154        } else {
155            panic!("Agent must have state to set key from state buffer");
156        }
157    }
158
159    /// Sets the key to point to the query buffer.
160    ///
161    /// This is used after a successful lookup to set the result key
162    /// to the query string that was searched for.
163    pub fn set_key_from_query(&mut self) {
164        let bytes = self.query.as_bytes();
165        self.key.set_bytes(bytes);
166    }
167
168    /// Sets the key to point to a prefix of the query buffer.
169    ///
170    /// This is used during prefix searches to set the result key
171    /// to a prefix of the query string.
172    ///
173    /// # Arguments
174    ///
175    /// * `length` - Length of the prefix
176    pub fn set_key_from_query_prefix(&mut self, length: usize) {
177        let bytes = self.query.as_bytes();
178        assert!(length <= bytes.len(), "Prefix length out of bounds");
179        self.key.set_bytes(&bytes[..length]);
180    }
181
182    /// Returns true if the agent has state.
183    pub fn has_state(&self) -> bool {
184        self.state.is_some()
185    }
186
187    /// Initializes state for complex searches.
188    ///
189    /// # Errors
190    ///
191    /// Returns an error if state is already initialized.
192    pub fn init_state(&mut self) -> io::Result<()> {
193        if self.state.is_some() {
194            return Err(io::Error::new(
195                io::ErrorKind::AlreadyExists,
196                "State already initialized",
197            ));
198        }
199        self.state = Some(Box::new(State::new()));
200        Ok(())
201    }
202
203    /// Clears the agent to empty state.
204    pub fn clear(&mut self) {
205        *self = Agent::new();
206    }
207
208    /// Swaps with another agent.
209    pub fn swap(&mut self, other: &mut Agent) {
210        std::mem::swap(self, other);
211    }
212}
213
214/// Updates agent's key pointer after copying state.
215///
216/// In predictive search states, the agent's key points into the state's
217/// key buffer. After copying state, we need to update the pointer.
218#[allow(dead_code)]
219fn update_agent_after_copying_state(state: &State, agent: &mut Agent) {
220    match state.status_code() {
221        StatusCode::ReadyToPredictiveSearch | StatusCode::EndOfPredictiveSearch => {
222            // Key points into state buffer - repoint after copy
223            let key_buf = state.key_buf();
224            agent.key.set_bytes(key_buf);
225        }
226        _ => {
227            // Key is null or points to query - no update needed
228        }
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235
236    #[test]
237    fn test_agent_new() {
238        let agent = Agent::new();
239        assert_eq!(agent.query().length(), 0);
240        assert_eq!(agent.key().length(), 0);
241        assert!(!agent.has_state());
242    }
243
244    #[test]
245    fn test_agent_default() {
246        let agent = Agent::default();
247        assert_eq!(agent.query().length(), 0);
248    }
249
250    #[test]
251    fn test_agent_set_query_str() {
252        let mut agent = Agent::new();
253        agent.set_query_str("hello");
254
255        assert_eq!(agent.query().as_str(), "hello");
256        assert_eq!(agent.query().length(), 5);
257    }
258
259    #[test]
260    fn test_agent_set_query_bytes() {
261        let mut agent = Agent::new();
262        agent.set_query_bytes(b"world");
263
264        assert_eq!(agent.query().as_bytes(), b"world");
265        assert_eq!(agent.query().length(), 5);
266    }
267
268    #[test]
269    fn test_agent_set_query_id() {
270        let mut agent = Agent::new();
271        agent.set_query_id(42);
272
273        assert_eq!(agent.query().id(), 42);
274    }
275
276    #[test]
277    fn test_agent_set_key_str() {
278        let mut agent = Agent::new();
279        agent.set_key_str("test");
280
281        assert_eq!(agent.key().as_str(), "test");
282    }
283
284    #[test]
285    fn test_agent_set_key_id() {
286        let mut agent = Agent::new();
287        agent.set_key_id(100);
288
289        assert_eq!(agent.key().id(), 100);
290    }
291
292    #[test]
293    fn test_agent_init_state() {
294        let mut agent = Agent::new();
295        assert!(!agent.has_state());
296
297        agent.init_state().unwrap();
298        assert!(agent.has_state());
299    }
300
301    #[test]
302    fn test_agent_init_state_already_exists() {
303        let mut agent = Agent::new();
304        agent.init_state().unwrap();
305
306        let result = agent.init_state();
307        assert!(result.is_err());
308    }
309
310    #[test]
311    fn test_agent_state_reset_on_set_query() {
312        let mut agent = Agent::new();
313        agent.init_state().unwrap();
314
315        {
316            let state = agent.state_mut().unwrap();
317            state.set_status_code(StatusCode::EndOfPredictiveSearch);
318        }
319
320        // Setting query should reset state status code
321        agent.set_query_str("new query");
322
323        let state = agent.state().unwrap();
324        assert_eq!(state.status_code(), StatusCode::ReadyToAll);
325    }
326
327    #[test]
328    fn test_agent_clear() {
329        let mut agent = Agent::new();
330        agent.set_query_str("test");
331        agent.set_key_id(10);
332        agent.init_state().unwrap();
333
334        agent.clear();
335
336        assert_eq!(agent.query().length(), 0);
337        assert_eq!(agent.key().length(), 0);
338        assert!(!agent.has_state());
339    }
340
341    #[test]
342    fn test_agent_swap() {
343        let s1 = "query1";
344        let s2 = "query2";
345
346        let mut a1 = Agent::new();
347        a1.set_query_str(s1);
348        a1.set_key_id(1);
349
350        let mut a2 = Agent::new();
351        a2.set_query_str(s2);
352        a2.set_key_id(2);
353        a2.init_state().unwrap();
354
355        a1.swap(&mut a2);
356
357        assert_eq!(a1.query().as_str(), "query2");
358        assert_eq!(a1.key().id(), 2);
359        assert!(a1.has_state());
360
361        assert_eq!(a2.query().as_str(), "query1");
362        assert_eq!(a2.key().id(), 1);
363        assert!(!a2.has_state());
364    }
365
366    #[test]
367    fn test_agent_clone() {
368        let mut agent = Agent::new();
369        agent.set_query_str("original");
370        agent.set_key_id(42);
371        agent.init_state().unwrap();
372
373        let cloned = agent.clone();
374
375        assert_eq!(cloned.query().as_str(), "original");
376        assert_eq!(cloned.key().id(), 42);
377        assert!(cloned.has_state());
378    }
379
380    #[test]
381    fn test_agent_query_mut() {
382        let mut agent = Agent::new();
383        agent.query_mut().set_str("mutable");
384
385        assert_eq!(agent.query().as_str(), "mutable");
386    }
387
388    #[test]
389    fn test_agent_key_mut() {
390        let mut agent = Agent::new();
391        agent.key_mut().set_id(99);
392
393        assert_eq!(agent.key().id(), 99);
394    }
395}