Skip to main content

aam_core/aaml/
lookup.rs

1//! Key lookup methods for [`AAML`](AAML).
2
3use super::{AAML, Hasher};
4use crate::found_value::FoundValue;
5use std::collections::HashSet;
6
7impl AAML {
8    /// Looks up `key` in the map. If not found as a key, performs a reverse
9    /// lookup — searching for an entry whose *value* matches `key`.
10    #[must_use]
11    pub fn find_obj(&self, key: &str) -> Option<FoundValue> {
12        self.map
13            .get(key)
14            .map(|v| FoundValue::new(v))
15            .or_else(|| self.find_key(key))
16    }
17
18    /// Reverse lookup: finds the key whose value equals `value`.
19    #[must_use]
20    pub fn find_key(&self, value: &str) -> Option<FoundValue> {
21        self.map
22            .iter()
23            .find_map(|(k, v)| (&**v == value).then(|| FoundValue::new(k)))
24    }
25
26    /// Follows a chain of key -> value -> key lookups until a terminal value
27    /// is reached or a cycle is detected.
28    #[must_use]
29    pub fn find_deep(&self, key: &str) -> Option<FoundValue> {
30        let mut current_key = key;
31        let mut last_found = None;
32        let mut visited: HashSet<&str, Hasher> = HashSet::with_hasher(Hasher::default());
33
34        while let Some(next_val) = self.map.get(current_key) {
35            if !visited.insert(current_key) {
36                break;
37            }
38            if visited.contains(&**next_val) {
39                if last_found.is_none() {
40                    last_found = Some(next_val);
41                }
42                break;
43            }
44            last_found = Some(next_val);
45            current_key = next_val;
46        }
47
48        last_found.map(|v| FoundValue::new(v))
49    }
50}