eure_document/document/
node.rs

1use crate::{prelude_internal::*, value::ValueKind};
2
3#[derive(Debug, Clone)]
4/// A node in the Eure document.
5///
6/// This does not implement PartialEq since content may refer to other nodes, and so equality is not well-defined.
7pub struct Node {
8    pub content: NodeValue,
9    pub extensions: Map<Identifier, NodeId>,
10}
11
12pub struct NodeMut<'d> {
13    document: &'d mut EureDocument,
14    pub node_id: NodeId,
15}
16
17impl<'d> core::fmt::Debug for NodeMut<'d> {
18    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19        match self.document.get_node(self.node_id) {
20            Some(node) => f
21                .debug_tuple("NodeMut")
22                .field(&self.node_id)
23                .field(node)
24                .finish(),
25            None => f
26                .debug_tuple("NodeMut")
27                .field(&self.node_id)
28                .field(&"<invalid>")
29                .finish(),
30        }
31    }
32}
33
34impl<'d> NodeMut<'d> {
35    pub fn new(document: &'d mut EureDocument, node_id: NodeId) -> Self {
36        Self { document, node_id }
37    }
38
39    pub fn add_map_child(self, object_key: ObjectKey) -> Result<NodeMut<'d>, InsertErrorKind> {
40        self.document.add_map_child(object_key, self.node_id)
41    }
42
43    pub fn add_extension(self, identifier: Identifier) -> Result<NodeMut<'d>, InsertErrorKind> {
44        self.document.add_extension(identifier, self.node_id)
45    }
46
47    pub fn add_tuple_element(self, index: u8) -> Result<NodeMut<'d>, InsertErrorKind> {
48        self.document.add_tuple_element(index, self.node_id)
49    }
50
51    pub fn add_array_element(self, index: Option<usize>) -> Result<NodeMut<'d>, InsertErrorKind> {
52        self.document.add_array_element(index, self.node_id)
53    }
54
55    pub fn add_child_by_segment(
56        self,
57        segment: PathSegment,
58    ) -> Result<NodeMut<'d>, InsertErrorKind> {
59        self.document.add_child_by_segment(segment, self.node_id)
60    }
61
62    pub fn get_extension(self, ident: &Identifier) -> Option<NodeMut<'d>> {
63        let node_id = self.document.node(self.node_id).extensions.get(ident)?;
64        Some(NodeMut::new(self.document, *node_id))
65    }
66
67    // Content access methods
68
69    pub fn as_map(self) -> Option<&'d NodeMap> {
70        self.document.node(self.node_id).as_map()
71    }
72
73    pub fn as_array(self) -> Option<&'d NodeArray> {
74        self.document.node(self.node_id).as_array()
75    }
76
77    pub fn as_tuple(self) -> Option<&'d NodeTuple> {
78        self.document.node(self.node_id).as_tuple()
79    }
80
81    pub fn require_map(self) -> Result<&'d mut NodeMap, InsertErrorKind> {
82        self.document.node_mut(self.node_id).require_map()
83    }
84
85    pub fn require_tuple(self) -> Result<&'d mut NodeTuple, InsertErrorKind> {
86        self.document.node_mut(self.node_id).require_tuple()
87    }
88
89    pub fn require_array(self) -> Result<&'d mut NodeArray, InsertErrorKind> {
90        self.document.node_mut(self.node_id).require_array()
91    }
92}
93
94impl Node {
95    pub fn as_map(&self) -> Option<&NodeMap> {
96        match &self.content {
97            NodeValue::Map(map) => Some(map),
98            _ => None,
99        }
100    }
101
102    pub fn as_array(&self) -> Option<&NodeArray> {
103        match &self.content {
104            NodeValue::Array(array) => Some(array),
105            _ => None,
106        }
107    }
108
109    pub fn as_tuple(&self) -> Option<&NodeTuple> {
110        match &self.content {
111            NodeValue::Tuple(tuple) => Some(tuple),
112            _ => None,
113        }
114    }
115
116    pub fn as_primitive(&self) -> Option<&PrimitiveValue> {
117        match &self.content {
118            NodeValue::Primitive(primitive) => Some(primitive),
119            _ => None,
120        }
121    }
122
123    pub fn get_extension(&self, ident: &Identifier) -> Option<NodeId> {
124        self.extensions.get(ident).copied()
125    }
126
127    pub(crate) fn require_map(&mut self) -> Result<&mut NodeMap, InsertErrorKind> {
128        if self.content.is_hole() {
129            self.content = NodeValue::Map(Default::default());
130            let NodeValue::Map(map) = &mut self.content else {
131                unreachable!();
132            };
133            Ok(map)
134        } else if let NodeValue::Map(map) = &mut self.content {
135            Ok(map)
136        } else {
137            Err(InsertErrorKind::ExpectedMap)
138        }
139    }
140
141    pub(crate) fn require_tuple(&mut self) -> Result<&mut NodeTuple, InsertErrorKind> {
142        if self.content.is_hole() {
143            self.content = NodeValue::Tuple(Default::default());
144            let NodeValue::Tuple(tuple) = &mut self.content else {
145                unreachable!();
146            };
147            Ok(tuple)
148        } else if let NodeValue::Tuple(tuple) = &mut self.content {
149            Ok(tuple)
150        } else {
151            Err(InsertErrorKind::ExpectedTuple)
152        }
153    }
154
155    pub(crate) fn require_array(&mut self) -> Result<&mut NodeArray, InsertErrorKind> {
156        if self.content.is_hole() {
157            self.content = NodeValue::Array(Default::default());
158            let NodeValue::Array(array) = &mut self.content else {
159                unreachable!();
160            };
161            Ok(array)
162        } else if let NodeValue::Array(array) = &mut self.content {
163            Ok(array)
164        } else {
165            Err(InsertErrorKind::ExpectedArray)
166        }
167    }
168}
169
170#[derive(Debug, PartialEq, Clone)]
171pub enum NodeValue {
172    /// A hole represents an uninitialized or placeholder value.
173    /// Optionally includes a label for identification (e.g., `!todo`, `!wip`).
174    Hole(Option<Identifier>),
175    Primitive(PrimitiveValue),
176    Array(NodeArray),
177    Map(NodeMap),
178    Tuple(NodeTuple),
179}
180
181impl NodeValue {
182    /// Creates an anonymous hole (no label).
183    pub fn hole() -> Self {
184        Self::Hole(None)
185    }
186
187    /// Creates a labeled hole.
188    pub fn labeled_hole(label: Identifier) -> Self {
189        Self::Hole(Some(label))
190    }
191
192    /// Returns true if this is a hole (labeled or anonymous).
193    pub fn is_hole(&self) -> bool {
194        matches!(self, Self::Hole(_))
195    }
196
197    pub fn empty_map() -> Self {
198        Self::Map(NodeMap::new())
199    }
200
201    pub fn empty_array() -> Self {
202        Self::Array(NodeArray::new())
203    }
204
205    pub fn empty_tuple() -> Self {
206        Self::Tuple(NodeTuple::new())
207    }
208
209    pub fn value_kind(&self) -> Option<ValueKind> {
210        match self {
211            Self::Hole(_) => None,
212            Self::Primitive(primitive) => Some(primitive.kind()),
213            Self::Array(_) => Some(ValueKind::Array),
214            Self::Map(_) => Some(ValueKind::Map),
215            Self::Tuple(_) => Some(ValueKind::Tuple),
216        }
217    }
218}
219
220// ============================================================================
221// From implementations for NodeValue
222// ============================================================================
223
224impl From<PrimitiveValue> for NodeValue {
225    fn from(p: PrimitiveValue) -> Self {
226        NodeValue::Primitive(p)
227    }
228}
229
230// TODO: Remove `pub`
231#[derive(Debug, Default, Clone, PartialEq, Eq, Plural)]
232pub struct NodeArray(pub Vec<NodeId>);
233
234// TODO: Remove `pub`
235#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Plural)]
236pub struct NodeTuple(pub Vec<NodeId>);
237
238pub type NodeMap = Map<ObjectKey, NodeId>;
239
240impl NodeTuple {
241    pub fn get(&self, index: usize) -> Option<NodeId> {
242        self.0.get(index).copied()
243    }
244
245    pub fn push(&mut self, node_id: NodeId) -> Result<(), InsertErrorKind> {
246        self.0.push(node_id);
247        Ok(())
248    }
249
250    pub fn add_at(&mut self, index: u8, node_id: NodeId) -> Result<(), InsertErrorKind> {
251        if index as usize != self.0.len() {
252            return Err(InsertErrorKind::TupleIndexInvalid {
253                index,
254                expected_index: self.0.len(),
255            });
256        }
257        self.0.insert(index as usize, node_id);
258        Ok(())
259    }
260}
261
262impl NodeArray {
263    pub fn get(&self, index: usize) -> Option<NodeId> {
264        self.0.get(index).copied()
265    }
266
267    pub fn push(&mut self, node_id: NodeId) -> Result<(), InsertErrorKind> {
268        self.0.push(node_id);
269        Ok(())
270    }
271
272    pub fn add_at(&mut self, index: usize, node_id: NodeId) -> Result<(), InsertErrorKind> {
273        if index != self.0.len() {
274            return Err(InsertErrorKind::ArrayIndexInvalid {
275                index,
276                expected_index: self.0.len(),
277            });
278        }
279        self.0.insert(index, node_id);
280        Ok(())
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use super::*;
287
288    fn identifier(s: &str) -> Identifier {
289        s.parse().unwrap()
290    }
291
292    #[test]
293    fn test_require_map_on_uninitialized() {
294        let mut node = Node {
295            content: NodeValue::hole(),
296            extensions: Map::new(),
297        };
298
299        let map = node.require_map().expect("Should convert to map");
300        assert_eq!(map.0.len(), 0);
301
302        // Verify content was changed
303        assert!(node.as_map().is_some());
304    }
305
306    #[test]
307    fn test_require_map_on_existing_map() {
308        let mut node = Node {
309            content: NodeValue::Map(Default::default()),
310            extensions: Map::new(),
311        };
312
313        let map = node.require_map().expect("Should return existing map");
314        assert_eq!(map.0.len(), 0);
315    }
316
317    #[test]
318    fn test_require_map_on_wrong_type() {
319        let mut node = Node {
320            content: NodeValue::Primitive(PrimitiveValue::Null),
321            extensions: Map::new(),
322        };
323
324        let result = node.require_map();
325        assert_eq!(result, Err(InsertErrorKind::ExpectedMap));
326    }
327
328    #[test]
329    fn test_require_tuple_on_uninitialized() {
330        let mut node = Node {
331            content: NodeValue::hole(),
332            extensions: Map::new(),
333        };
334
335        let tuple = node.require_tuple().expect("Should convert to tuple");
336        assert_eq!(tuple.0.len(), 0);
337
338        // Verify content was changed
339        assert!(node.as_tuple().is_some());
340    }
341
342    #[test]
343    fn test_require_tuple_on_existing_tuple() {
344        let mut node = Node {
345            content: NodeValue::Tuple(Default::default()),
346            extensions: Map::new(),
347        };
348
349        let tuple = node.require_tuple().expect("Should return existing tuple");
350        assert_eq!(tuple.0.len(), 0);
351    }
352
353    #[test]
354    fn test_require_tuple_on_wrong_type() {
355        let mut node = Node {
356            content: NodeValue::Primitive(PrimitiveValue::Null),
357            extensions: Map::new(),
358        };
359
360        let result = node.require_tuple();
361        assert_eq!(result, Err(InsertErrorKind::ExpectedTuple));
362    }
363
364    #[test]
365    fn test_require_array_on_uninitialized() {
366        let mut node = Node {
367            content: NodeValue::hole(),
368            extensions: Map::new(),
369        };
370
371        let array = node.require_array().expect("Should convert to array");
372        assert_eq!(array.0.len(), 0);
373
374        // Verify content was changed
375        assert!(node.as_array().is_some());
376    }
377
378    #[test]
379    fn test_require_array_on_existing_array() {
380        let mut node = Node {
381            content: NodeValue::Array(Default::default()),
382            extensions: Map::new(),
383        };
384
385        let array = node.require_array().expect("Should return existing array");
386        assert_eq!(array.0.len(), 0);
387    }
388
389    #[test]
390    fn test_require_array_on_wrong_type() {
391        let mut node = Node {
392            content: NodeValue::Primitive(PrimitiveValue::Null),
393            extensions: Map::new(),
394        };
395
396        let result = node.require_array();
397        assert_eq!(result, Err(InsertErrorKind::ExpectedArray));
398    }
399
400    #[test]
401    fn test_node_get_extension_exists() {
402        let mut doc = EureDocument::new();
403        let root_id = doc.get_root_id();
404        let ext_identifier = identifier("test_ext");
405
406        // Add an extension
407        let ext_node_id = doc
408            .add_extension(ext_identifier.clone(), root_id)
409            .expect("Failed to add extension")
410            .node_id;
411
412        // Test get_extension on the node
413        let root_node = doc.node(root_id);
414        let result = root_node.get_extension(&ext_identifier);
415
416        assert!(result.is_some());
417        assert_eq!(result.unwrap(), ext_node_id);
418    }
419
420    #[test]
421    fn test_node_get_extension_missing() {
422        let doc = EureDocument::new();
423        let root_id = doc.get_root_id();
424        let ext_identifier = identifier("nonexistent");
425
426        // Test get_extension for a missing extension
427        let root_node = doc.node(root_id);
428        let result = root_node.get_extension(&ext_identifier);
429
430        assert!(result.is_none());
431    }
432
433    #[test]
434    fn test_node_mut_get_extension_exists() {
435        let mut doc = EureDocument::new();
436        let root_id = doc.get_root_id();
437        let ext_identifier = identifier("test_ext");
438
439        // Add an extension
440        let ext_node_id = doc
441            .add_extension(ext_identifier.clone(), root_id)
442            .expect("Failed to add extension")
443            .node_id;
444
445        // Test NodeMut::get_extension
446        let node_mut = NodeMut::new(&mut doc, root_id);
447        let result = node_mut.get_extension(&ext_identifier);
448
449        assert!(result.is_some());
450        let ext_node_mut = result.unwrap();
451        assert_eq!(ext_node_mut.node_id, ext_node_id);
452    }
453
454    #[test]
455    fn test_node_mut_get_extension_missing() {
456        let mut doc = EureDocument::new();
457        let root_id = doc.get_root_id();
458        let ext_identifier = identifier("nonexistent");
459
460        // Test NodeMut::get_extension for a missing extension
461        let node_mut = NodeMut::new(&mut doc, root_id);
462        let result = node_mut.get_extension(&ext_identifier);
463
464        assert!(result.is_none());
465    }
466
467    #[test]
468    fn test_node_mut_debug_valid_node() {
469        let mut doc = EureDocument::new();
470        let root_id = doc.get_root_id();
471
472        // Create a NodeMut with valid node_id
473        let node_mut = NodeMut::new(&mut doc, root_id);
474        let debug_output = alloc::format!("{:?}", node_mut);
475
476        // Should contain NodeMut, node_id, and delegate to Node's Debug
477        assert!(debug_output.contains("NodeMut"));
478        assert!(debug_output.contains("NodeId"));
479        assert!(debug_output.contains("Node"));
480        assert!(debug_output.contains("Hole"));
481    }
482
483    #[test]
484    fn test_node_mut_debug_invalid_node() {
485        let mut doc = EureDocument::new();
486        let invalid_id = NodeId(999999); // Invalid NodeId
487
488        // Create a NodeMut with invalid node_id
489        let node_mut = NodeMut::new(&mut doc, invalid_id);
490        let debug_output = alloc::format!("{:?}", node_mut);
491
492        // Should contain NodeMut and "<invalid>"
493        assert!(debug_output.contains("NodeMut"));
494        assert!(debug_output.contains("<invalid>"));
495    }
496}