use core::slice;
use std::fmt;
use crate::binary::{
BArray, BKeyValue, BMap, BReference, Binary, TYPE_ARRAY, TYPE_KEYVAL, TYPE_MAP,
};
use crate::error::DaptResult;
use crate::{Error, Path};
use super::parser::Node;
pub trait Aquireable {
fn aquire(&self, bin: &mut Binary, b: BReference) -> DaptResult<BKeyValue>;
}
pub trait Discoverable {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference);
}
#[derive(Debug, PartialEq, Clone)]
pub struct FieldLiteral {
name: String,
}
impl FieldLiteral {
pub fn new(name: &str) -> FieldLiteral {
FieldLiteral {
name: name.to_string(),
}
}
pub fn from_escaped(name: &str) -> FieldLiteral {
let mut c = name.chars().peekable();
let mut name = String::with_capacity(name.len());
while let Some(character) = c.next() {
match character {
'\\' => {
if let Some(next) = c.next() {
name.push(next);
}
}
'"' => (),
_ => name.push(character),
}
}
FieldLiteral { name }
}
}
impl Discoverable for FieldLiteral {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference),
{
let n = match b.val_at(bin) {
Some(n) => n,
None => return,
};
match n.get_type(bin) {
TYPE_MAP => {
let bcoll = BMap::from(n);
if let Some(child_location) = bcoll.child_key(&self.name, bin) {
f(child_location);
}
}
_ => (),
};
}
}
impl Aquireable for FieldLiteral {
fn aquire(&self, bin: &mut Binary, b: BReference) -> DaptResult<BKeyValue> {
let mut reg = None;
self.find(bin, b, &mut |x| reg = Some(x));
if reg.is_some() {
return Ok(reg
.unwrap()
.key_at(bin)
.ok_or_else(|| Error::CanNotAquire(format!("could not aquire {}", self)))?);
}
match b.token_at(bin) {
None => {
let (key_bref, bkv) = BKeyValue::new(None, BReference::from(0), &self.name, bin);
let (map_bref, _) = BMap::new(Some(b), slice::from_ref(&key_bref), bin);
b.set_index(bin, *map_bref);
Ok(bkv)
}
Some(tok) if tok.get_type(bin) == TYPE_MAP => {
let (key_bref, bkv) = BKeyValue::new(
Some(tok.get_reference(bin)),
BReference::from(0),
&self.name,
bin,
);
let bcoll = BMap::from(tok);
bcoll.add_child(key_bref, bin);
Ok(bkv)
}
Some(tok) if tok.get_type(bin) == TYPE_KEYVAL => {
let orig_bkv = BKeyValue::from(tok);
let child = orig_bkv.child(bin);
if child.is_some() {
return self.aquire(bin, child.unwrap());
}
let (key_bref, bkv) = BKeyValue::new(None, BReference::from(0), &self.name, bin);
let (map_bref, _) = BMap::new(Some(b), slice::from_ref(&key_bref), bin);
orig_bkv.set_child(map_bref, bin);
Ok(bkv)
}
Some(_) => Err("Cannot add a field to a non map type".into()),
}
}
}
impl fmt::Display for FieldLiteral {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.name.contains('.') || self.name.contains('"') || self.name.contains(' ') {
write!(f, "\"")?;
let c = self.name.chars();
for character in c {
match character {
'"' => {
write!(f, "\\\"")?;
}
_ => write!(f, "{}", character)?,
}
}
write!(f, "\"")
} else {
write!(f, "{}", self.name)
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Array {
index: Option<usize>,
}
impl Array {
pub fn new(index: Option<usize>) -> Array {
Array { index }
}
}
impl Discoverable for Array {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference),
{
let n = match b.val_at(bin) {
Some(n) => n,
None => return,
};
match n.get_type(bin) {
TYPE_ARRAY => {
let bcoll = BArray::from(n);
if let None = self.index {
for i in 0..bcoll.length(bin) {
f(bcoll.child_index(bin, i).unwrap());
}
} else {
if let Some(child_location) = bcoll.child_index(bin, self.index.unwrap()) {
f(child_location);
}
}
}
_ => (),
};
}
}
impl fmt::Display for Array {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.index {
Some(i) => write!(f, "[{}]", i),
None => write!(f, "[]"),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Wildcard;
impl Discoverable for Wildcard {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference),
{
let n = match b.val_at(bin) {
Some(n) => n,
None => return,
};
match n.get_type(bin) {
TYPE_MAP => {
let bcoll = BMap::from(n);
for i in 0..bcoll.length(bin) {
f(bcoll.child_index(bin, i).unwrap());
}
}
_ => (),
};
}
}
impl fmt::Display for Wildcard {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "*")
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Recursive {
child: Box<Node>,
}
impl Recursive {
pub fn new(child: Node) -> Recursive {
Recursive {
child: Box::new(child),
}
}
}
impl Discoverable for Recursive {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference),
{
b.walk(bin, &mut |childref| {
self.child.find(bin, childref, f);
true
});
}
}
impl fmt::Display for Recursive {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "~.{}", self.child)
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct First {
paths: Vec<Path>,
}
impl First {
pub fn new(paths: Vec<Path>) -> First {
First { paths }
}
}
impl Discoverable for First {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference),
{
for path in &self.paths {
let ptrs = path.find_simple(bin, b);
match ptrs.get(0) {
Some(p) => {
f(*p);
return;
}
None => (),
}
}
}
}
impl fmt::Display for First {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{")?;
for (x, path) in self.paths.iter().enumerate() {
if x > 0 {
write!(f, ",")?;
}
write!(f, "{}", path)?;
}
write!(f, "}}")?;
Ok(())
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Multi {
paths: Vec<Path>,
}
impl Multi {
pub fn new(paths: Vec<Path>) -> Multi {
Multi { paths }
}
}
impl Discoverable for Multi {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference),
{
for path in &self.paths {
path.find_simple(bin, b).iter().for_each(|p| f(*p));
}
}
}
impl fmt::Display for Multi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(")?;
for (x, path) in self.paths.iter().enumerate() {
if x > 0 {
write!(f, "|")?;
}
write!(f, "{}", path)?;
}
write!(f, ")")?;
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Regexp {
name: regex::Regex,
}
impl Regexp {
pub fn new(name: &str) -> Regexp {
Regexp {
name: regex::Regex::new(name).unwrap(),
}
}
}
impl PartialEq for Regexp {
fn eq(&self, other: &Self) -> bool {
self.name.as_str() == other.name.as_str()
}
}
impl Discoverable for Regexp {
fn find<F>(&self, bin: &Binary, b: BReference, f: &mut F)
where
F: FnMut(BReference),
{
let n = match b.val_at(bin) {
Some(n) => n,
None => return,
};
match n.get_type(bin) {
TYPE_MAP => {
let bcoll = BMap::from(n);
for i in 0..bcoll.length(bin) {
let child = bcoll.child_index(bin, i).unwrap();
if self.name.is_match(child.key_at(bin).unwrap().key(bin)) {
f(child);
}
}
}
_ => (),
};
}
}
impl fmt::Display for Regexp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "/{}/", self.name)
}
}