1use scheme_edit::{list, sym, Item, Node};
4
5pub struct RecordView<'a> {
7 node: &'a Node,
8}
9
10impl<'a> RecordView<'a> {
11 pub fn new(node: &'a Node) -> Option<Self> {
13 node.head_symbol()?;
14 Some(Self { node })
15 }
16
17 pub fn record_name(&self) -> &'a str {
18 self.node.head_symbol().unwrap_or_default()
20 }
21
22 pub fn field(&self, name: &str) -> Option<&'a Node> {
24 field_value(self.node, name)
25 }
26
27 pub fn symbol_field(&self, name: &str) -> Option<&'a str> {
28 self.field(name)?.as_symbol()
29 }
30
31 pub fn string_field(&self, name: &str) -> Option<String> {
32 self.field(name)?.as_string_lit()
33 }
34}
35
36pub struct RecordViewMut<'a> {
38 node: &'a mut Node,
39}
40
41impl<'a> RecordViewMut<'a> {
42 pub fn new(node: &'a mut Node) -> Option<Self> {
44 node.head_symbol()?;
45 Some(Self { node })
46 }
47
48 pub fn record_name(&self) -> &str {
49 self.node.head_symbol().unwrap_or_default()
50 }
51
52 pub fn field(&self, name: &str) -> Option<&Node> {
53 field_value(self.node, name)
54 }
55
56 pub fn symbol_field(&self, name: &str) -> Option<&str> {
57 self.field(name)?.as_symbol()
58 }
59
60 pub fn string_field(&self, name: &str) -> Option<String> {
61 self.field(name)?.as_string_lit()
62 }
63
64 pub fn field_mut(&mut self, name: &str) -> Option<&mut Node> {
67 let idx = self.node.position_of(|n| n.head_symbol() == Some(name))?;
68 self.node.data_child_mut(idx)?.data_child_mut(1)
69 }
70
71 pub fn set_field(&mut self, name: &str, value: Node) {
74 if let Node::List { items, .. } = &mut *self.node {
75 for item in items.iter_mut() {
76 if let Item::Node(n) = item {
77 if n.head_symbol() == Some(name) {
78 if n.data_len() >= 2 {
79 n.replace_child(1, value);
80 } else {
81 n.push_child(value);
82 }
83 return;
84 }
85 }
86 }
87 }
88 self.node.push_child(list(vec![sym(name), value]));
89 }
90
91 pub fn remove_field(&mut self, name: &str) -> bool {
93 let Some(idx) = self.node.position_of(|n| n.head_symbol() == Some(name)) else {
94 return false;
95 };
96 self.node.remove_child(idx, true).is_some()
97 }
98}
99
100fn field_value<'n>(node: &'n Node, name: &str) -> Option<&'n Node> {
101 node.list_nodes()
102 .skip(1)
103 .find(|n| n.head_symbol() == Some(name))?
104 .data_child(1)
105}