Skip to main content

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#[derive(Debug, Default, Clone, PartialEq, Eq, Plural)]
231#[plural(len, is_empty, iter, into_iter, new)]
232pub struct NodeArray(Vec<NodeId>);
233
234#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Plural)]
235#[plural(len, is_empty, iter, into_iter, new)]
236pub struct NodeTuple(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    pub fn to_vec(&self) -> Vec<NodeId> {
262        self.0.clone()
263    }
264
265    pub fn from_vec(vec: Vec<NodeId>) -> Self {
266        Self(vec)
267    }
268}
269
270impl NodeArray {
271    pub fn get(&self, index: usize) -> Option<NodeId> {
272        self.0.get(index).copied()
273    }
274
275    pub fn push(&mut self, node_id: NodeId) -> Result<(), InsertErrorKind> {
276        self.0.push(node_id);
277        Ok(())
278    }
279
280    pub fn add_at(&mut self, index: usize, node_id: NodeId) -> Result<(), InsertErrorKind> {
281        if index != self.0.len() {
282            return Err(InsertErrorKind::ArrayIndexInvalid {
283                index,
284                expected_index: self.0.len(),
285            });
286        }
287        self.0.insert(index, node_id);
288        Ok(())
289    }
290
291    pub fn to_vec(&self) -> Vec<NodeId> {
292        self.0.clone()
293    }
294
295    pub fn from_vec(vec: Vec<NodeId>) -> Self {
296        Self(vec)
297    }
298}
299
300#[cfg(test)]
301mod tests {
302    use super::*;
303
304    fn identifier(s: &str) -> Identifier {
305        s.parse().unwrap()
306    }
307
308    #[test]
309    fn test_require_map_on_uninitialized() {
310        let mut node = Node {
311            content: NodeValue::hole(),
312            extensions: Map::new(),
313        };
314
315        let map = node.require_map().expect("Should convert to map");
316        assert_eq!(map.len(), 0);
317
318        // Verify content was changed
319        assert!(node.as_map().is_some());
320    }
321
322    #[test]
323    fn test_require_map_on_existing_map() {
324        let mut node = Node {
325            content: NodeValue::Map(Default::default()),
326            extensions: Map::new(),
327        };
328
329        let map = node.require_map().expect("Should return existing map");
330        assert_eq!(map.len(), 0);
331    }
332
333    #[test]
334    fn test_require_map_on_wrong_type() {
335        let mut node = Node {
336            content: NodeValue::Primitive(PrimitiveValue::Null),
337            extensions: Map::new(),
338        };
339
340        let result = node.require_map();
341        assert_eq!(result, Err(InsertErrorKind::ExpectedMap));
342    }
343
344    #[test]
345    fn test_require_tuple_on_uninitialized() {
346        let mut node = Node {
347            content: NodeValue::hole(),
348            extensions: Map::new(),
349        };
350
351        let tuple = node.require_tuple().expect("Should convert to tuple");
352        assert_eq!(tuple.len(), 0);
353
354        // Verify content was changed
355        assert!(node.as_tuple().is_some());
356    }
357
358    #[test]
359    fn test_require_tuple_on_existing_tuple() {
360        let mut node = Node {
361            content: NodeValue::Tuple(Default::default()),
362            extensions: Map::new(),
363        };
364
365        let tuple = node.require_tuple().expect("Should return existing tuple");
366        assert_eq!(tuple.len(), 0);
367    }
368
369    #[test]
370    fn test_require_tuple_on_wrong_type() {
371        let mut node = Node {
372            content: NodeValue::Primitive(PrimitiveValue::Null),
373            extensions: Map::new(),
374        };
375
376        let result = node.require_tuple();
377        assert_eq!(result, Err(InsertErrorKind::ExpectedTuple));
378    }
379
380    #[test]
381    fn test_require_array_on_uninitialized() {
382        let mut node = Node {
383            content: NodeValue::hole(),
384            extensions: Map::new(),
385        };
386
387        let array = node.require_array().expect("Should convert to array");
388        assert_eq!(array.len(), 0);
389
390        // Verify content was changed
391        assert!(node.as_array().is_some());
392    }
393
394    #[test]
395    fn test_require_array_on_existing_array() {
396        let mut node = Node {
397            content: NodeValue::Array(Default::default()),
398            extensions: Map::new(),
399        };
400
401        let array = node.require_array().expect("Should return existing array");
402        assert_eq!(array.len(), 0);
403    }
404
405    #[test]
406    fn test_require_array_on_wrong_type() {
407        let mut node = Node {
408            content: NodeValue::Primitive(PrimitiveValue::Null),
409            extensions: Map::new(),
410        };
411
412        let result = node.require_array();
413        assert_eq!(result, Err(InsertErrorKind::ExpectedArray));
414    }
415
416    #[test]
417    fn test_node_get_extension_exists() {
418        let mut doc = EureDocument::new();
419        let root_id = doc.get_root_id();
420        let ext_identifier = identifier("test_ext");
421
422        // Add an extension
423        let ext_node_id = doc
424            .add_extension(ext_identifier.clone(), root_id)
425            .expect("Failed to add extension")
426            .node_id;
427
428        // Test get_extension on the node
429        let root_node = doc.node(root_id);
430        let result = root_node.get_extension(&ext_identifier);
431
432        assert!(result.is_some());
433        assert_eq!(result.unwrap(), ext_node_id);
434    }
435
436    #[test]
437    fn test_node_get_extension_missing() {
438        let doc = EureDocument::new();
439        let root_id = doc.get_root_id();
440        let ext_identifier = identifier("nonexistent");
441
442        // Test get_extension for a missing extension
443        let root_node = doc.node(root_id);
444        let result = root_node.get_extension(&ext_identifier);
445
446        assert!(result.is_none());
447    }
448
449    #[test]
450    fn test_node_mut_get_extension_exists() {
451        let mut doc = EureDocument::new();
452        let root_id = doc.get_root_id();
453        let ext_identifier = identifier("test_ext");
454
455        // Add an extension
456        let ext_node_id = doc
457            .add_extension(ext_identifier.clone(), root_id)
458            .expect("Failed to add extension")
459            .node_id;
460
461        // Test NodeMut::get_extension
462        let node_mut = NodeMut::new(&mut doc, root_id);
463        let result = node_mut.get_extension(&ext_identifier);
464
465        assert!(result.is_some());
466        let ext_node_mut = result.unwrap();
467        assert_eq!(ext_node_mut.node_id, ext_node_id);
468    }
469
470    #[test]
471    fn test_node_mut_get_extension_missing() {
472        let mut doc = EureDocument::new();
473        let root_id = doc.get_root_id();
474        let ext_identifier = identifier("nonexistent");
475
476        // Test NodeMut::get_extension for a missing extension
477        let node_mut = NodeMut::new(&mut doc, root_id);
478        let result = node_mut.get_extension(&ext_identifier);
479
480        assert!(result.is_none());
481    }
482
483    #[test]
484    fn test_node_mut_debug_valid_node() {
485        let mut doc = EureDocument::new();
486        let root_id = doc.get_root_id();
487
488        // Create a NodeMut with valid node_id
489        let node_mut = NodeMut::new(&mut doc, root_id);
490        let debug_output = alloc::format!("{:?}", node_mut);
491
492        // Should contain NodeMut, node_id, and delegate to Node's Debug
493        assert!(debug_output.contains("NodeMut"));
494        assert!(debug_output.contains("NodeId"));
495        assert!(debug_output.contains("Node"));
496        assert!(debug_output.contains("Hole"));
497    }
498
499    #[test]
500    fn test_node_mut_debug_invalid_node() {
501        let mut doc = EureDocument::new();
502        let invalid_id = NodeId(999999); // Invalid NodeId
503
504        // Create a NodeMut with invalid node_id
505        let node_mut = NodeMut::new(&mut doc, invalid_id);
506        let debug_output = alloc::format!("{:?}", node_mut);
507
508        // Should contain NodeMut and "<invalid>"
509        assert!(debug_output.contains("NodeMut"));
510        assert!(debug_output.contains("<invalid>"));
511    }
512}