use scheme_edit::{list, sym, Item, Node};
pub struct RecordView<'a> {
node: &'a Node,
}
impl<'a> RecordView<'a> {
pub fn new(node: &'a Node) -> Option<Self> {
node.head_symbol()?;
Some(Self { node })
}
pub fn record_name(&self) -> &'a str {
self.node.head_symbol().unwrap_or_default()
}
pub fn field(&self, name: &str) -> Option<&'a Node> {
field_value(self.node, name)
}
pub fn symbol_field(&self, name: &str) -> Option<&'a str> {
self.field(name)?.as_symbol()
}
pub fn string_field(&self, name: &str) -> Option<String> {
self.field(name)?.as_string_lit()
}
}
pub struct RecordViewMut<'a> {
node: &'a mut Node,
}
impl<'a> RecordViewMut<'a> {
pub fn new(node: &'a mut Node) -> Option<Self> {
node.head_symbol()?;
Some(Self { node })
}
pub fn record_name(&self) -> &str {
self.node.head_symbol().unwrap_or_default()
}
pub fn field(&self, name: &str) -> Option<&Node> {
field_value(self.node, name)
}
pub fn symbol_field(&self, name: &str) -> Option<&str> {
self.field(name)?.as_symbol()
}
pub fn string_field(&self, name: &str) -> Option<String> {
self.field(name)?.as_string_lit()
}
pub fn field_mut(&mut self, name: &str) -> Option<&mut Node> {
let idx = self.node.position_of(|n| n.head_symbol() == Some(name))?;
self.node.data_child_mut(idx)?.data_child_mut(1)
}
pub fn set_field(&mut self, name: &str, value: Node) {
if let Node::List { items, .. } = &mut *self.node {
for item in items.iter_mut() {
if let Item::Node(n) = item {
if n.head_symbol() == Some(name) {
if n.data_len() >= 2 {
n.replace_child(1, value);
} else {
n.push_child(value);
}
return;
}
}
}
}
self.node.push_child(list(vec![sym(name), value]));
}
pub fn remove_field(&mut self, name: &str) -> bool {
let Some(idx) = self.node.position_of(|n| n.head_symbol() == Some(name)) else {
return false;
};
self.node.remove_child(idx, true).is_some()
}
}
fn field_value<'n>(node: &'n Node, name: &str) -> Option<&'n Node> {
node.list_nodes()
.skip(1)
.find(|n| n.head_symbol() == Some(name))?
.data_child(1)
}