use crate::ig::node::Node;
use crate::ig::symbols::{Symbol, SymbolTable};
use std::borrow::Cow;
use std::fmt::{Debug, Formatter};
use std::slice::Iter;
pub struct Doc {
root: Node,
symbols: SymbolTable,
}
#[derive(Copy, Clone)]
pub struct Element<'a> {
doc: &'a Doc,
node: &'a Node,
}
pub struct ElementIter<'a> {
doc: &'a Doc,
iter: Option<Iter<'a, Node>>,
}
pub struct EntryIter<'a> {
doc: &'a Doc,
iter: Option<Iter<'a, (Symbol, Node)>>,
}
#[derive(Clone)]
pub struct Query {
path: Vec<Symbol>,
}
impl Query {
pub fn is_root_node_query(&self) -> bool {
self.path.is_empty()
}
}
impl Doc {
pub fn empty() -> Self {
Doc {
symbols: SymbolTable::new(),
root: Node::Empty,
}
}
pub fn new(symbols: SymbolTable, root: Node) -> Self {
Doc { root, symbols }
}
pub fn root(&'_ self) -> Element<'_> {
Element {
doc: self,
node: &self.root,
}
}
pub fn compile(&self, query: impl AsRef<str>) -> Query {
let query = query.as_ref();
if "." == query {
return Query { path: Vec::new() };
}
let mut path = Vec::new();
for part in query.split('.') {
if let Some(symbol) = self.symbols.resolve(part) {
path.push(symbol);
} else {
return Query { path: vec![-1] };
}
}
Query { path }
}
pub fn symbols_mut(&mut self) -> &mut SymbolTable {
&mut self.symbols
}
pub fn symbols(&self) -> &SymbolTable {
&self.symbols
}
pub fn allocated_size(&self) -> usize {
self.root.allocated_size() + self.symbols.allocated_size()
}
}
impl<'a> Element<'a> {
pub fn query(self, query: impl AsRef<str>) -> Element<'a> {
self.doc.compile(query).execute(self)
}
pub fn is_empty(&self) -> bool {
matches!(self.node, Node::Empty)
}
pub fn as_str(&self) -> Option<&'a str> {
match self.node {
Node::InlineString(str) => Some(str.as_ref()),
Node::BoxedString(str) => Some(str.as_ref()),
_ => None,
}
}
pub fn to_str(&'_ self) -> Cow<'_, str> {
match self.node {
Node::InlineString(str) => Cow::Borrowed(str.as_ref()),
Node::BoxedString(str) => Cow::Borrowed(str.as_ref()),
Node::Integer(value) => Cow::Owned(format!("{}", value)),
Node::Boolean(true) => Cow::Borrowed("true"),
Node::Boolean(false) => Cow::Borrowed("false"),
Node::Symbol(symbol) => Cow::Borrowed(self.doc.symbols.lookup(*symbol)),
_ => Cow::Borrowed(""),
}
}
pub fn as_int(&self) -> Option<i64> {
if let Node::Integer(value) = self.node {
Some(*value)
} else {
None
}
}
pub fn try_as_bool(&self) -> Option<bool> {
if let Node::Boolean(value) = self.node {
Some(*value)
} else {
None
}
}
pub fn as_bool(&self) -> bool {
if let Node::Boolean(value) = self.node {
*value
} else {
false
}
}
pub fn is_list(&self) -> bool {
matches!(self.node, Node::List(_))
}
pub fn is_object(&self) -> bool {
matches!(self.node, Node::Object(_))
}
pub fn len(&self) -> usize {
match self.node {
Node::List(list) => list.len(),
Node::Object(map) => map.len(),
_ => 0,
}
}
pub fn at(&self, index: usize) -> Element<'a> {
if let Node::List(list) = self.node {
if let Some(node) = list.get(index) {
return Element {
doc: self.doc,
node,
};
}
}
Element {
doc: self.doc,
node: &Node::Empty,
}
}
pub fn iter(&'a self) -> ElementIter<'a> {
if let Node::List(list) = self.node {
ElementIter {
doc: self.doc,
iter: Some(list.iter()),
}
} else {
ElementIter {
doc: self.doc,
iter: None,
}
}
}
pub fn entries(self) -> EntryIter<'a> {
if let Node::Object(map) = self.node {
EntryIter {
doc: self.doc,
iter: Some(map.entries()),
}
} else {
EntryIter {
doc: self.doc,
iter: None,
}
}
}
}
impl Query {
pub fn execute<'a>(&self, element: Element<'a>) -> Element<'a> {
let mut current_node = element.node;
for key in self.path.iter() {
if let Node::Object(map) = current_node {
current_node = map.get(*key).unwrap_or(&Node::Empty);
} else {
current_node = &Node::Empty;
}
}
Element {
doc: element.doc,
node: current_node,
}
}
pub fn execute_all<'a>(&self, element: Element<'a>) -> Vec<Element<'a>> {
let mut result = Vec::new();
self.execute_into(0, element.doc, element.node, &mut result);
result
}
fn execute_into<'a>(
&self,
index: usize,
doc: &'a Doc,
node: &'a Node,
results: &mut Vec<Element<'a>>,
) {
if let Some(key) = self.path.get(index) {
if let Node::Object(map) = node {
self.execute_into(
index + 1,
doc,
map.get(*key).unwrap_or(&Node::Empty),
results,
);
} else if let Node::List(list) = node {
for child in list {
self.execute_into(index, doc, child, results);
}
}
} else {
results.push(Element { doc, node });
}
}
}
impl Debug for Element<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.node {
Node::Empty => write!(f, "(Empty)"),
Node::Integer(value) => write!(f, "{}", value),
Node::Boolean(value) => write!(f, "{}", value),
Node::InlineString(value) => write!(f, "{}", value.as_ref()),
Node::BoxedString(value) => write!(f, "{}", value.as_ref()),
Node::List(_) => f.debug_list().entries(self.iter()).finish(),
Node::Object(_) => {
let mut helper = f.debug_map();
for (name, value) in self.entries() {
let _ = helper.key(&name).value(&value);
}
helper.finish()
}
Node::Symbol(value) => write!(f, "{} ({})", value, self.doc.symbols.lookup(*value)),
}
}
}
impl<'a> Iterator for ElementIter<'a> {
type Item = Element<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(ref mut iter) = self.iter {
if let Some(node) = iter.next() {
Some(Element {
doc: self.doc,
node,
})
} else {
None
}
} else {
None
}
}
}
impl<'a> Iterator for EntryIter<'a> {
type Item = (&'a str, Element<'a>);
fn next(&mut self) -> Option<Self::Item> {
if let Some(ref mut iter) = self.iter {
if let Some((symbol, node)) = iter.next() {
Some((
self.doc.symbols.lookup(*symbol),
Element {
doc: self.doc,
node,
},
))
} else {
None
}
} else {
None
}
}
}