mod aggregate;
mod array;
mod misc;
mod object;
use simd_json::OwnedValue as Value;
use simd_json::StaticNode;
use simd_json::prelude::*;
use crate::error::EvalError;
pub(crate) fn type_error(message: String) -> EvalError {
EvalError::TypeError {
message,
position: 0, }
}
#[derive(Debug, Clone, PartialEq)]
pub enum Builtin {
Length,
Keys,
Values,
Type,
First,
Last,
Reverse,
Sort,
Min,
Max,
Unique,
Flatten,
Add,
Empty,
Not,
ToEntries,
FromEntries,
Csv,
Tsv,
}
impl Builtin {
pub fn from_name(name: &str) -> Option<Self> {
match name {
"length" => Some(Builtin::Length),
"keys" => Some(Builtin::Keys),
"values" => Some(Builtin::Values),
"type" => Some(Builtin::Type),
"first" => Some(Builtin::First),
"last" => Some(Builtin::Last),
"reverse" => Some(Builtin::Reverse),
"sort" => Some(Builtin::Sort),
"min" => Some(Builtin::Min),
"max" => Some(Builtin::Max),
"unique" => Some(Builtin::Unique),
"flatten" => Some(Builtin::Flatten),
"add" => Some(Builtin::Add),
"empty" => Some(Builtin::Empty),
"not" => Some(Builtin::Not),
"to_entries" => Some(Builtin::ToEntries),
"from_entries" => Some(Builtin::FromEntries),
_ => None,
}
}
}
pub fn eval(builtin: &Builtin, value: &Value) -> Result<Vec<Value>, EvalError> {
match builtin {
Builtin::Length => Ok(vec![aggregate::eval_length(value)?]),
Builtin::Keys => Ok(vec![object::eval_keys(value)?]),
Builtin::Values => Ok(vec![object::eval_values(value)?]),
Builtin::Type => Ok(vec![misc::eval_type(value)]),
Builtin::First => Ok(vec![array::eval_first(value)?]),
Builtin::Last => Ok(vec![array::eval_last(value)?]),
Builtin::Reverse => Ok(vec![array::eval_reverse(value)?]),
Builtin::Sort => Ok(vec![array::eval_sort(value)?]),
Builtin::Min => Ok(vec![aggregate::eval_min(value)?]),
Builtin::Max => Ok(vec![aggregate::eval_max(value)?]),
Builtin::Unique => Ok(vec![array::eval_unique(value)?]),
Builtin::Flatten => Ok(vec![array::eval_flatten(value)?]),
Builtin::Add => Ok(vec![aggregate::eval_add(value)?]),
Builtin::Empty => Ok(vec![]), Builtin::Not => Ok(vec![misc::eval_not(value)]),
Builtin::ToEntries => Ok(vec![object::eval_to_entries(value)?]),
Builtin::FromEntries => Ok(vec![object::eval_from_entries(value)?]),
Builtin::Csv => Ok(vec![misc::eval_csv(value)?]),
Builtin::Tsv => Ok(vec![misc::eval_tsv(value)?]),
}
}
pub(crate) fn json_cmp(a: &Value, b: &Value) -> std::cmp::Ordering {
use std::cmp::Ordering;
fn type_order(v: &Value) -> u8 {
match v {
Value::Static(StaticNode::Null) => 0,
Value::Static(StaticNode::Bool(false)) => 1,
Value::Static(StaticNode::Bool(true)) => 2,
Value::Static(StaticNode::I64(_) | StaticNode::U64(_) | StaticNode::F64(_)) => 3,
Value::String(_) => 4,
Value::Array(_) => 5,
Value::Object(_) => 6,
}
}
let type_cmp = type_order(a).cmp(&type_order(b));
if type_cmp != Ordering::Equal {
return type_cmp;
}
match (a, b) {
(Value::Static(sa), Value::Static(sb)) => {
let af = match sa {
StaticNode::I64(n) => *n as f64,
StaticNode::U64(n) => *n as f64,
StaticNode::F64(n) => *n,
_ => return Ordering::Equal,
};
let bf = match sb {
StaticNode::I64(n) => *n as f64,
StaticNode::U64(n) => *n as f64,
StaticNode::F64(n) => *n,
_ => return Ordering::Equal,
};
af.partial_cmp(&bf).unwrap_or(Ordering::Equal)
}
(Value::String(a), Value::String(b)) => a.cmp(b),
(Value::Array(a), Value::Array(b)) => {
for (av, bv) in a.iter().zip(b.iter()) {
let cmp = json_cmp(av, bv);
if cmp != Ordering::Equal {
return cmp;
}
}
a.len().cmp(&b.len())
}
(Value::Object(a), Value::Object(b)) => {
let mut keys_a: Vec<&String> = a.keys().collect();
let mut keys_b: Vec<&String> = b.keys().collect();
keys_a.sort();
keys_b.sort();
for (ka, kb) in keys_a.iter().zip(keys_b.iter()) {
let cmp = ka.cmp(kb);
if cmp != Ordering::Equal {
return cmp;
}
}
let len_cmp = keys_a.len().cmp(&keys_b.len());
if len_cmp != Ordering::Equal {
return len_cmp;
}
for key in keys_a {
let cmp = json_cmp(&a[key.as_str()], &b[key.as_str()]);
if cmp != Ordering::Equal {
return cmp;
}
}
Ordering::Equal
}
_ => Ordering::Equal,
}
}