eure_document/parse/
object_key.rs

1//! ParseObjectKey trait and implementations for object key types.
2
3use crate::{parse::ParseErrorKind, prelude_internal::*};
4use num_bigint::BigInt;
5
6/// Trait for types that can be used as object keys when parsing from Eure documents.
7///
8/// This trait abstracts over key types that can be used in `Map<K, V>`, supporting
9/// owned (`ObjectKey`), borrowed (`&'doc ObjectKey`), and primitive types (`bool`,
10/// `BigInt`, `String`) for type-constrained maps.
11///
12/// # Lifetime Parameter
13///
14/// The `'doc` lifetime ties the parsed key to the document's lifetime, allowing
15/// zero-copy parsing for reference types.
16///
17/// # Type Constraints
18///
19/// Implementors must satisfy:
20/// - `Eq + Hash` for use with `AHashMap` (std feature)
21/// - `Ord` for use with `BTreeMap` (no_std)
22///
23/// # Examples
24///
25/// ```ignore
26/// use eure_document::{EureDocument, Map, ObjectKey, ParseDocument};
27///
28/// // Parse map with borrowed keys (zero-copy)
29/// let map: Map<&ObjectKey, String> = doc.parse(root_id)?;
30///
31/// // Parse map with owned keys
32/// let map: Map<ObjectKey, String> = doc.parse(root_id)?;
33///
34/// // Parse map with type-constrained keys
35/// let map: Map<String, i32> = doc.parse(root_id)?;
36/// ```
37pub trait ParseObjectKey<'doc>: Sized + Eq + core::hash::Hash + Ord {
38    /// Parse an object key from the given ObjectKey reference in the document.
39    ///
40    /// # Arguments
41    ///
42    /// * `key` - Reference to the ObjectKey in the document's NodeMap
43    ///
44    /// # Returns
45    ///
46    /// Returns `Self` on success, or `ParseErrorKind` if the key cannot be
47    /// converted to the target type (e.g., trying to parse a Bool as String).
48    ///
49    /// # Errors
50    ///
51    /// Returns `ParseErrorKind::TypeMismatch` when the ObjectKey variant doesn't
52    /// match the expected type.
53    fn from_object_key(key: &'doc ObjectKey) -> Result<Self, ParseErrorKind>;
54}
55
56// ============================================================================
57// Implementation for &'doc ObjectKey (borrowed, zero-copy)
58// ============================================================================
59
60impl<'doc> ParseObjectKey<'doc> for &'doc ObjectKey {
61    fn from_object_key(key: &'doc ObjectKey) -> Result<Self, ParseErrorKind> {
62        Ok(key)
63    }
64}
65
66// ============================================================================
67// Implementation for ObjectKey (owned, cloned)
68// ============================================================================
69
70impl ParseObjectKey<'_> for ObjectKey {
71    fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
72        Ok(key.clone())
73    }
74}
75
76// ============================================================================
77// Implementation for bool (type-constrained)
78// ============================================================================
79
80impl ParseObjectKey<'_> for bool {
81    fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
82        match key {
83            ObjectKey::Bool(b) => Ok(*b),
84            _ => Err(ParseErrorKind::TypeMismatch {
85                expected: crate::value::ValueKind::Bool,
86                actual: key_to_value_kind(key),
87            }),
88        }
89    }
90}
91
92// ============================================================================
93// Implementation for BigInt (type-constrained)
94// ============================================================================
95
96impl ParseObjectKey<'_> for BigInt {
97    fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
98        match key {
99            ObjectKey::Number(n) => Ok(n.clone()),
100            _ => Err(ParseErrorKind::TypeMismatch {
101                expected: crate::value::ValueKind::Integer,
102                actual: key_to_value_kind(key),
103            }),
104        }
105    }
106}
107
108// ============================================================================
109// Implementation for String (type-constrained)
110// ============================================================================
111
112impl ParseObjectKey<'_> for String {
113    fn from_object_key(key: &ObjectKey) -> Result<Self, ParseErrorKind> {
114        match key {
115            ObjectKey::String(s) => Ok(s.clone()),
116            _ => Err(ParseErrorKind::TypeMismatch {
117                expected: crate::value::ValueKind::Text,
118                actual: key_to_value_kind(key),
119            }),
120        }
121    }
122}
123
124// ============================================================================
125// Helper function to convert ObjectKey to ValueKind for error messages
126// ============================================================================
127
128fn key_to_value_kind(key: &ObjectKey) -> crate::value::ValueKind {
129    match key {
130        ObjectKey::Bool(_) => crate::value::ValueKind::Bool,
131        ObjectKey::Number(_) => crate::value::ValueKind::Integer,
132        ObjectKey::String(_) => crate::value::ValueKind::Text,
133        ObjectKey::Tuple(_) => crate::value::ValueKind::Tuple,
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140    use crate::value::Tuple;
141
142    #[test]
143    fn test_parse_object_key_borrowed() {
144        let key = ObjectKey::String("test".into());
145        let borrowed: &ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
146        assert_eq!(borrowed, &key);
147    }
148
149    #[test]
150    fn test_parse_object_key_owned() {
151        let key = ObjectKey::Bool(true);
152        let owned: ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
153        assert_eq!(owned, key);
154    }
155
156    #[test]
157    fn test_borrowed_key_is_zero_copy() {
158        let key = ObjectKey::String("test".into());
159        let borrowed: &ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
160        assert!(core::ptr::eq(&key, borrowed));
161    }
162
163    #[test]
164    #[allow(clippy::bool_assert_comparison)]
165    fn test_parse_bool_key() {
166        let key = ObjectKey::Bool(true);
167        let b: bool = ParseObjectKey::from_object_key(&key).unwrap();
168        assert_eq!(b, true);
169    }
170
171    #[test]
172    fn test_parse_bool_key_type_mismatch() {
173        let key = ObjectKey::String("not a bool".into());
174        let result: Result<bool, _> = ParseObjectKey::from_object_key(&key);
175        assert!(result.is_err());
176    }
177
178    #[test]
179    fn test_parse_bigint_key() {
180        let key = ObjectKey::Number(BigInt::from(42));
181        let n: BigInt = ParseObjectKey::from_object_key(&key).unwrap();
182        assert_eq!(n, BigInt::from(42));
183    }
184
185    #[test]
186    fn test_parse_bigint_key_type_mismatch() {
187        let key = ObjectKey::Bool(false);
188        let result: Result<BigInt, _> = ParseObjectKey::from_object_key(&key);
189        assert!(result.is_err());
190    }
191
192    #[test]
193    fn test_parse_string_key() {
194        let key = ObjectKey::String("hello".into());
195        let s: String = ParseObjectKey::from_object_key(&key).unwrap();
196        assert_eq!(s, "hello");
197    }
198
199    #[test]
200    fn test_parse_string_key_type_mismatch() {
201        let key = ObjectKey::Number(BigInt::from(123));
202        let result: Result<String, _> = ParseObjectKey::from_object_key(&key);
203        assert!(result.is_err());
204    }
205
206    #[test]
207    fn test_parse_tuple_key() {
208        let key = ObjectKey::Tuple(Tuple(vec![
209            ObjectKey::String("a".into()),
210            ObjectKey::Number(BigInt::from(1)),
211        ]));
212        let owned: ObjectKey = ParseObjectKey::from_object_key(&key).unwrap();
213        assert_eq!(owned, key);
214    }
215}