pub(crate) mod traversal;
use std::cmp::Ordering;
use std::convert::{TryFrom, TryInto};
use serde::{Deserialize, Serialize, Serializer};
use std::fmt::Formatter;
use crate::rules::evaluate::{resolve_query, AutoReport};
use crate::rules::EvaluationType;
use super::errors::Error;
use super::exprs::{QueryPart, SliceDisplay};
use super::{Evaluate, EvaluationContext, Status};
use super::values::*;
use crate::rules::exprs::LetValue;
use fancy_regex::Regex;
use serde::ser::{SerializeMap, SerializeStruct};
use std::hash::{Hash, Hasher};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub(crate) struct Location {
pub(crate) line: usize,
pub(crate) col: usize,
}
impl Location {
#[cfg(test)]
pub(crate) fn new(line: usize, col: usize) -> Self {
Location { line, col }
}
}
impl std::fmt::Display for Location {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("L:{},C:{}", self.line, self.col))
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub(crate) struct Path(pub(crate) String, pub(crate) Location);
impl Path {
#[cfg(test)]
pub(crate) fn new(path: String, line: usize, col: usize) -> Path {
Path(path, Location::new(line, col))
}
pub(crate) fn with_location(&self, loc: Location) -> Self {
Path(self.0.clone(), loc)
}
}
impl std::fmt::Display for Path {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}[{}]", self.0, self.1))
}
}
impl Path {
pub(crate) fn root() -> Self {
Path("".to_string(), Location::default())
}
pub(crate) fn relative(&self) -> &str {
match self.0.rfind('/') {
Some(pos) => &self.0[pos + 1..],
None => &self.0,
}
}
}
impl TryFrom<&str> for Path {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(Path(value.to_string(), Location::default()))
}
}
impl TryFrom<&[&str]> for Path {
type Error = Error;
fn try_from(value: &[&str]) -> Result<Self, Self::Error> {
Ok(Path(
value
.iter()
.map(|s| (*s).to_string())
.fold(String::from(""), |mut acc, part| {
if acc.is_empty() {
acc.push_str(part.as_str());
} else {
acc.push('/');
acc.push_str(part.as_str());
}
acc
}),
Location::default(),
))
}
}
impl TryFrom<&[String]> for Path {
type Error = Error;
fn try_from(value: &[String]) -> Result<Self, Self::Error> {
let vec = value.iter().map(String::as_str).collect::<Vec<&str>>();
Path::try_from(vec.as_slice())
}
}
impl Path {
pub(crate) fn extend_str(&self, part: &str) -> Path {
let mut copy = self.0.clone();
copy.push('/');
copy.push_str(part);
Path(copy, self.1)
}
pub(crate) fn extend_string(&self, part: &str) -> Path {
self.extend_str(part)
}
pub(crate) fn extend_usize(&self, part: usize) -> Path {
let as_str = part.to_string();
self.extend_string(&as_str)
}
}
#[derive(Debug, Clone, Deserialize)]
pub(crate) struct MapValue {
pub(crate) keys: Vec<PathAwareValue>,
pub(crate) values: indexmap::IndexMap<String, PathAwareValue>,
}
impl Serialize for MapValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(self.values.len()))?;
for (key, value) in self.values.iter() {
map.serialize_entry(key, value)?;
}
map.end()
}
}
impl PartialEq for MapValue {
fn eq(&self, other: &Self) -> bool {
self.values == other.values
}
}
impl Eq for MapValue {}
impl MapValue {
pub(crate) fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
#[derive(Debug, Clone, Deserialize)]
pub(crate) enum PathAwareValue {
Null(Path),
String((Path, String)),
Regex((Path, String)),
Bool((Path, bool)),
Int((Path, i64)),
Float((Path, f64)),
Char((Path, char)),
List((Path, Vec<PathAwareValue>)),
Map((Path, MapValue)),
RangeInt((Path, RangeType<i64>)),
RangeFloat((Path, RangeType<f64>)),
RangeChar((Path, RangeType<char>)),
}
impl Hash for PathAwareValue {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
PathAwareValue::String((_, s)) | PathAwareValue::Regex((_, s)) => {
s.hash(state);
}
PathAwareValue::Char((_, c)) => {
c.hash(state);
}
PathAwareValue::Int((_, i)) => {
i.hash(state);
}
PathAwareValue::Null(_) => {
"NULL".hash(state);
}
PathAwareValue::Float((_, f)) => {
(*f as u64).hash(state);
}
PathAwareValue::RangeChar((_, r)) => {
r.lower.hash(state);
r.upper.hash(state);
r.inclusive.hash(state);
}
PathAwareValue::RangeInt((_, r)) => {
r.lower.hash(state);
r.upper.hash(state);
r.inclusive.hash(state);
}
PathAwareValue::RangeFloat((_, r)) => {
(r.lower as u64).hash(state);
(r.upper as u64).hash(state);
r.inclusive.hash(state);
}
PathAwareValue::Bool((_, b)) => {
b.hash(state);
}
PathAwareValue::List((_, l)) => {
for each in l {
each.hash(state);
}
}
PathAwareValue::Map((_, map)) => {
for (key, value) in map.values.iter() {
key.hash(state);
value.hash(state);
}
}
}
}
}
impl PartialEq for PathAwareValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(PathAwareValue::Map((_, map)), PathAwareValue::Map((_, map2))) => map == map2,
(PathAwareValue::List((_, list)), PathAwareValue::List((_, list2))) => list == list2,
(PathAwareValue::Bool((_, b1)), PathAwareValue::Bool((_, b2))) => b1 == b2,
(PathAwareValue::String((_, s)), PathAwareValue::Regex((_, r))) => {
if let Ok(regex) = Regex::new(r.as_str()) {
regex.is_match(s.as_str()).unwrap() } else {
false
}
}
(PathAwareValue::Regex((_, r)), PathAwareValue::String((_, s))) => {
if let Ok(regex) = Regex::new(r.as_str()) {
regex.is_match(s.as_str()).unwrap() } else {
false
}
}
(PathAwareValue::Regex((_, r)), PathAwareValue::Regex((_, s))) => r == s,
(PathAwareValue::Int((_, value)), PathAwareValue::RangeInt((_, r))) => {
value.is_within(r)
}
(PathAwareValue::Float((_, value)), PathAwareValue::RangeFloat((_, r))) => {
value.is_within(r)
}
(PathAwareValue::Char((_, value)), PathAwareValue::RangeChar((_, r))) => {
value.is_within(r)
}
(rest, rest2) => match compare_values(rest, rest2) {
Ok(ordering) => matches!(ordering, Ordering::Equal),
Err(_) => false,
},
}
}
}
impl Eq for PathAwareValue {}
impl TryFrom<&str> for PathAwareValue {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let value = Value::try_from(value)?;
PathAwareValue::try_from((&value, Path::try_from("")?))
}
}
impl TryFrom<(&str, Path)> for PathAwareValue {
type Error = Error;
fn try_from(value: (&str, Path)) -> Result<Self, Self::Error> {
let parsed = Value::try_from(value.0)?;
PathAwareValue::try_from((&parsed, value.1))
}
}
impl TryFrom<(&serde_json::Value, Path)> for PathAwareValue {
type Error = Error;
fn try_from(incoming: (&serde_json::Value, Path)) -> Result<Self, Self::Error> {
let root = incoming.0;
let path = incoming.1;
let value = Value::try_from(root)?;
PathAwareValue::try_from((&value, path))
}
}
impl TryFrom<(&serde_yaml::Value, Path)> for PathAwareValue {
type Error = Error;
fn try_from(incoming: (&serde_yaml::Value, Path)) -> Result<Self, Self::Error> {
let root = incoming.0;
let path = incoming.1;
let value = Value::try_from(root)?;
PathAwareValue::try_from((&value, path))
}
}
impl TryFrom<Value> for PathAwareValue {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
PathAwareValue::try_from((&value, Path::root()))
}
}
impl TryFrom<serde_yaml::Value> for PathAwareValue {
type Error = Error;
fn try_from(value: serde_yaml::Value) -> Result<Self, Self::Error> {
PathAwareValue::try_from((&value, Path::root()))
}
}
impl TryFrom<serde_json::Value> for PathAwareValue {
type Error = Error;
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
PathAwareValue::try_from((&value, Path::root()))
}
}
impl TryFrom<(&Value, Path)> for PathAwareValue {
type Error = Error;
fn try_from(incoming: (&Value, Path)) -> Result<Self, Self::Error> {
let root = incoming.0;
let path = incoming.1;
match root {
Value::String(s) => Ok(PathAwareValue::String((path, s.to_owned()))),
Value::Int(num) => Ok(PathAwareValue::Int((path, *num))),
Value::Float(flt) => Ok(PathAwareValue::Float((path, *flt))),
Value::Regex(s) => Ok(PathAwareValue::Regex((path, s.clone()))),
Value::Char(c) => Ok(PathAwareValue::Char((path, *c))),
Value::RangeChar(r) => Ok(PathAwareValue::RangeChar((path, r.clone()))),
Value::RangeInt(r) => Ok(PathAwareValue::RangeInt((path, r.clone()))),
Value::RangeFloat(r) => Ok(PathAwareValue::RangeFloat((path, r.clone()))),
Value::Bool(b) => Ok(PathAwareValue::Bool((path, *b))),
Value::Null => Ok(PathAwareValue::Null(path)),
Value::List(v) => {
let mut result: Vec<PathAwareValue> = Vec::with_capacity(v.len());
for (idx, each) in v.iter().enumerate() {
let sub_path = path.extend_usize(idx);
let value = PathAwareValue::try_from((each, sub_path.clone()))?;
result.push(value);
}
Ok(PathAwareValue::List((path, result)))
}
Value::Map(map) => {
let mut keys = Vec::with_capacity(map.len());
let mut values = indexmap::IndexMap::with_capacity(map.len());
for each_key in map.keys() {
let sub_path = path.extend_string(each_key);
let value = PathAwareValue::String((sub_path, each_key.to_string()));
keys.push(value);
}
for (each_key, each_value) in map {
let sub_path = path.extend_string(each_key);
let value = PathAwareValue::try_from((each_value, sub_path))?;
values.insert(each_key.to_owned(), value);
}
Ok(PathAwareValue::Map((path, MapValue { keys, values })))
}
}
}
}
impl TryFrom<MarkedValue> for PathAwareValue {
type Error = Error;
fn try_from(value: MarkedValue) -> Result<Self, Self::Error> {
Self::try_from((value, Path::root()))
}
}
impl TryFrom<(MarkedValue, Path)> for PathAwareValue {
type Error = Error;
fn try_from(incoming: (MarkedValue, Path)) -> Result<Self, Self::Error> {
let root = incoming.0;
let path = incoming.1;
match root {
MarkedValue::String(s, loc) => Ok(PathAwareValue::String((path.with_location(loc), s))),
MarkedValue::Int(num, loc) => Ok(PathAwareValue::Int((path.with_location(loc), num))),
MarkedValue::Float(flt, loc) => {
Ok(PathAwareValue::Float((path.with_location(loc), flt)))
}
MarkedValue::Regex(s, loc) => Ok(PathAwareValue::Regex((path.with_location(loc), s))),
MarkedValue::Char(c, loc) => Ok(PathAwareValue::Char((path.with_location(loc), c))),
MarkedValue::RangeChar(r, loc) => {
Ok(PathAwareValue::RangeChar((path.with_location(loc), r)))
}
MarkedValue::RangeInt(r, loc) => {
Ok(PathAwareValue::RangeInt((path.with_location(loc), r)))
}
MarkedValue::RangeFloat(r, loc) => {
Ok(PathAwareValue::RangeFloat((path.with_location(loc), r)))
}
MarkedValue::Bool(b, loc) => Ok(PathAwareValue::Bool((path.with_location(loc), b))),
MarkedValue::Null(loc) => Ok(PathAwareValue::Null(path.with_location(loc))),
MarkedValue::List(v, _) => {
let mut result: Vec<PathAwareValue> = Vec::with_capacity(v.len());
for (idx, each) in v.into_iter().enumerate() {
let sub_path = path.extend_usize(idx);
let loc = *each.location();
let value = PathAwareValue::try_from((each, sub_path.with_location(loc)))?;
result.push(value);
}
Ok(PathAwareValue::List((path, result)))
}
MarkedValue::Map(map, loc) => {
let mut keys = Vec::with_capacity(map.len());
let mut values = indexmap::IndexMap::with_capacity(map.len());
for ((each_key, loc), each_value) in map {
let sub_path = path.extend_string(&each_key);
let sub_path = sub_path.with_location(*each_value.location());
let value = PathAwareValue::try_from((each_value, sub_path))?;
values.insert(each_key.to_owned(), value);
keys.push(PathAwareValue::String((
path.with_location(loc),
each_key.to_string(),
)));
}
Ok(PathAwareValue::Map((
path.with_location(loc),
MapValue { keys, values },
)))
}
MarkedValue::BadValue(val, loc) => Err(Error::ParseError(format!(
"Bad Value encountered parsing incoming file Value = {}, Loc = {}",
val, loc
))),
}
}
}
impl<'a> TryInto<(String, serde_json::Value)> for &'a PathAwareValue {
type Error = Error;
fn try_into(self) -> Result<(String, serde_json::Value), Self::Error> {
let top = self.self_path().0.clone();
match self {
PathAwareValue::Null(_) => Ok((top, serde_json::Value::Null)),
PathAwareValue::String((_, s)) => Ok((top, serde_json::Value::String(s.clone()))),
PathAwareValue::Regex((_, r)) => {
Ok((top, serde_json::Value::String(format!("/{}/", r))))
}
PathAwareValue::Bool((_, bool_)) => Ok((top, serde_json::Value::Bool(*bool_))),
PathAwareValue::Int((_, i64_)) => Ok((
top,
serde_json::Value::Number(serde_json::Number::from(*i64_)),
)),
PathAwareValue::Float((_, f64_)) => Ok((
top,
serde_json::Value::Number(match serde_json::Number::from_f64(*f64_) {
Some(num) => num,
None => {
return Err(Error::IncompatibleError(format!(
"Could not convert float {} to serde::Value::Number",
*f64_
)))
}
}),
)),
PathAwareValue::Char((_, char_)) => {
Ok((top, serde_json::Value::String(char_.to_string())))
}
PathAwareValue::List((_, list)) => {
let mut values = Vec::with_capacity(list.len());
for each in list {
let (_, val): (String, serde_json::Value) = each.try_into()?;
values.push(val);
}
Ok((top, serde_json::Value::Array(values)))
}
PathAwareValue::Map((_, map)) => {
let mut values = serde_json::Map::new();
for (key, value) in map.values.iter() {
let (_, val): (String, serde_json::Value) = value.try_into()?;
values.insert(key.clone(), val);
}
Ok((top, serde_json::Value::Object(values)))
}
PathAwareValue::RangeFloat((_, range_)) => {
let range_encoding = format!(
"{}{},{}{}",
if range_.inclusive & LOWER_INCLUSIVE > 0 {
"["
} else {
"("
},
range_.lower,
range_.upper,
if range_.inclusive & UPPER_INCLUSIVE > 0 {
"]"
} else {
")"
},
);
Ok((top, serde_json::Value::String(range_encoding)))
}
PathAwareValue::RangeChar((_, range_)) => {
let range_encoding = format!(
"{}{},{}{}",
if range_.inclusive & LOWER_INCLUSIVE > 0 {
"["
} else {
"("
},
range_.lower,
range_.upper,
if range_.inclusive & UPPER_INCLUSIVE > 0 {
"]"
} else {
")"
},
);
Ok((top, serde_json::Value::String(range_encoding)))
}
PathAwareValue::RangeInt((_, range_)) => {
let range_encoding = format!(
"{}{},{}{}",
if range_.inclusive & LOWER_INCLUSIVE > 0 {
"["
} else {
"("
},
range_.lower,
range_.upper,
if range_.inclusive & UPPER_INCLUSIVE > 0 {
"]"
} else {
")"
},
);
Ok((top, serde_json::Value::String(range_encoding)))
}
}
}
}
pub(crate) trait QueryResolver {
fn select(
&self,
all: bool,
query: &[QueryPart<'_>],
eval: &dyn EvaluationContext,
) -> Result<Vec<&PathAwareValue>, Error>;
}
impl QueryResolver for PathAwareValue {
fn select(
&self,
all: bool,
query: &[QueryPart<'_>],
resolver: &dyn EvaluationContext,
) -> Result<Vec<&PathAwareValue>, Error> {
if query.is_empty() {
return Ok(vec![self]);
}
match &query[0] {
QueryPart::This => self.select(all, &query[1..], resolver),
QueryPart::Key(key) => {
match key.parse::<i32>() {
Ok(index) => match self {
PathAwareValue::List((_, list)) => {
PathAwareValue::retrieve_index(self, index, list, query).map_or_else(
|e| self.map_error_or_empty(all, e),
|val| val.select(all, &query[1..], resolver),
)
}
_ => self.map_some_or_error_all(all, query),
},
Err(_) => match self {
PathAwareValue::Map((path, map)) => {
if query[0].is_variable() {
let var = query[0].variable().unwrap();
let keys = resolver.resolve_variable(var)?;
let mut acc = Vec::with_capacity(keys.len());
let keys = if query.len() > 1 {
match query[1] {
QueryPart::AllIndices(_) | QueryPart::Key(_) => keys,
QueryPart::Index(index) => {
let check = if index >= 0 { index } else { -index } as usize;
if check < keys.len() {
vec![keys[check]]
} else {
self.map_some_or_error_all(all, query)?
}
},
_ => return Err(Error::IncompatibleError(
format!("THIS type of variable interpolation is not supported {}, {}", self.type_info(), SliceDisplay(query))
))
}
} else {
keys
};
for each_key in keys {
if let PathAwareValue::String((_, k)) = each_key {
if let Some(next) = map.values.get(k) {
acc.extend(next.select(all, &query[1..], resolver)?);
} else if all {
return Err(Error::
RetrievalError(
format!("Could not locate key = {} inside object/map = {:?}, Path = {}, remaining query = {}",
key, self, path, SliceDisplay(query))
));
}
} else {
return Err(Error
::NotComparable(
format!("Variable projections inside Query {}, is returning a non-string value for key {}, {:?}",
SliceDisplay(query),
each_key.type_info(),
each_key.self_value()
)
));
}
}
Ok(acc)
} else if let Some(next) = map.values.get(key) {
next.select(all, &query[1..], resolver)
} else {
self.map_some_or_error_all(all, query)
}
}
_ => self.map_some_or_error_all(all, query),
},
}
}
QueryPart::Index(array_idx) => match self {
PathAwareValue::List((_path, vec)) => {
PathAwareValue::retrieve_index(self, *array_idx, vec, query).map_or_else(
|e| self.map_error_or_empty(all, e),
|val| val.select(all, &query[1..], resolver),
)
}
_ => self.map_some_or_error_all(all, query),
},
QueryPart::AllIndices(_name) => {
match self {
PathAwareValue::List((_path, elements)) => {
PathAwareValue::accumulate(self, all, &query[1..], elements, resolver)
}
rest => rest.select(all, &query[1..], resolver),
}
}
QueryPart::AllValues(_name) => {
match self {
PathAwareValue::List((_path, elements)) => {
PathAwareValue::accumulate(self, all, &query[1..], elements, resolver)
}
PathAwareValue::Map((_path, map)) => {
let values: Vec<&PathAwareValue> = map.values.values().collect();
let mut resolved = Vec::with_capacity(values.len());
for each in values {
resolved.extend(each.select(all, &query[1..], resolver)?);
}
Ok(resolved)
}
rest => rest.select(all, &query[1..], resolver),
}
}
QueryPart::MapKeyFilter(_name, filter) => match self {
PathAwareValue::Map((_, map)) => {
let mut selected = Vec::with_capacity(map.values.len());
match &filter.compare_with {
LetValue::AccessClause(query) => {
let values = resolve_query(false, &query.query, self, resolver)?;
for key in map.keys.iter() {
if values.contains(&key) {
match key {
PathAwareValue::String((_, v)) => {
selected.push(map.values.get(v).unwrap());
}
_ => unreachable!(),
}
}
}
}
LetValue::Value(path_value) => {
for key in map.keys.iter() {
if key == path_value {
match key {
PathAwareValue::String((_, v)) => {
selected.push(map.values.get(v).unwrap());
}
_ => unreachable!(),
}
}
}
}
LetValue::FunctionCall(_) => unreachable!(),
};
if query.len() > 1 {
let mut acc = Vec::with_capacity(selected.len());
for each in selected {
acc.extend(each.select(all, &query[1..], resolver)?)
}
Ok(acc)
} else {
Ok(selected)
}
}
_ => self.map_some_or_error_all(all, query),
},
QueryPart::Filter(_name, conjunctions) => {
match self {
PathAwareValue::List((path, vec)) => {
let mut selected = Vec::with_capacity(vec.len());
let context = format!("Path={},Type=Array", path);
for each in vec {
let mut filter =
AutoReport::new(EvaluationType::Filter, resolver, &context);
match conjunctions.evaluate(each, resolver) {
Err(Error::RetrievalError(e)) => {
if all {
return Err(Error::RetrievalError(e));
}
}
Err(Error::IncompatibleRetrievalError(e)) => {
if all {
return Err(Error::IncompatibleRetrievalError(e));
}
}
Err(e) => return Err(e),
Ok(status) => match status {
Status::PASS => {
filter.status(Status::PASS);
let index: usize = if query.len() > 1 {
match &query[1] {
QueryPart::AllIndices(_) => 2,
_ => 1,
}
} else {
1
};
selected.extend(each.select(
all,
&query[index..],
resolver,
)?);
}
rest => {
filter.status(rest);
}
},
}
}
Ok(selected)
}
PathAwareValue::Map((path, _map)) => {
let context = format!("Path={},Type=MapElement", path);
let mut filter =
AutoReport::new(EvaluationType::Filter, resolver, &context);
conjunctions.evaluate(self, resolver).map_or_else(
|e| self.map_error_or_empty(all, e),
|status| match status {
Status::PASS => {
filter.status(Status::PASS);
self.select(all, &query[1..], resolver)
}
rest => {
filter.status(rest);
Ok(vec![])
}
},
)
}
_ => self.map_some_or_error_all(all, query),
}
}
}
}
}
impl Serialize for PathAwareValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let result: crate::rules::Result<(String, serde_json::Value)> = self.try_into();
match result {
Ok((path, value)) => {
let mut struct_ser = serializer.serialize_struct("PathAwareValue", 2)?;
struct_ser.serialize_field("path", &path)?;
struct_ser.serialize_field("value", &value)?;
struct_ser.end()
}
Err(e) => Err(serde::ser::Error::custom(e)),
}
}
}
impl PartialOrd for PathAwareValue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.self_path().0.partial_cmp(&other.self_path().0)
}
}
impl PathAwareValue {
pub(crate) fn merge(mut self, other: PathAwareValue) -> crate::rules::Result<PathAwareValue> {
match (&mut self, other) {
(PathAwareValue::List((_path, vec)), PathAwareValue::List((_p2, other_vec))) => {
vec.extend(other_vec)
}
(PathAwareValue::Map((_, map)), PathAwareValue::Map((path, other_map))) => {
for (key, value) in other_map.values {
if map.values.contains_key(&key) {
return Err(Error::MultipleValues(format!(
"Key {}, already exists in map",
key
)));
}
map.values.insert(key.clone(), value);
map.keys
.push(PathAwareValue::String((path.extend_str(&key), key)));
}
}
(this, that) => {
return Err(Error::IncompatibleError(format!(
"Types are not compatible for merges {}, {}",
this.type_info(),
that.type_info()
)))
}
}
Ok(self)
}
pub(crate) fn is_list(&self) -> bool {
matches!(self, PathAwareValue::List((_, _)))
}
pub(crate) fn is_map(&self) -> bool {
matches!(self, PathAwareValue::Map((_, _)))
}
pub(crate) fn is_null(&self) -> bool {
matches!(self, PathAwareValue::Null(_))
}
fn map_error_or_empty(&self, all: bool, e: Error) -> Result<Vec<&PathAwareValue>, Error> {
if !all {
match e {
Error::IncompatibleRetrievalError(_) | Error::RetrievalError(_) => Ok(vec![]),
rest => Err(rest),
}
} else {
Err(e)
}
}
fn map_some_or_error_all(
&self,
all: bool,
query: &[QueryPart<'_>],
) -> Result<Vec<&PathAwareValue>, Error> {
if all {
Err(Error::IncompatibleRetrievalError(
format!("Attempting to retrieve array index or key from map at path = {} , Type was not an array/object {}, Remaining Query = {}",
self.self_value().0, self.type_info(), SliceDisplay(query))
))
} else {
Ok(vec![])
}
}
pub(crate) fn is_scalar(&self) -> bool {
!self.is_list() && !self.is_map()
}
pub(crate) fn self_path(&self) -> &Path {
self.self_value().0
}
pub(crate) fn self_value(&self) -> (&Path, &PathAwareValue) {
match self {
PathAwareValue::Null(path) => (path, self),
PathAwareValue::String((path, _)) => (path, self),
PathAwareValue::Regex((path, _)) => (path, self),
PathAwareValue::Bool((path, _)) => (path, self),
PathAwareValue::Int((path, _)) => (path, self),
PathAwareValue::Float((path, _)) => (path, self),
PathAwareValue::Char((path, _)) => (path, self),
PathAwareValue::List((path, _)) => (path, self),
PathAwareValue::Map((path, _)) => (path, self),
PathAwareValue::RangeInt((path, _)) => (path, self),
PathAwareValue::RangeFloat((path, _)) => (path, self),
PathAwareValue::RangeChar((path, _)) => (path, self),
}
}
pub(crate) fn type_info(&self) -> &'static str {
match self {
PathAwareValue::Null(_path) => "null",
PathAwareValue::String((_path, _)) => "String",
PathAwareValue::Regex((_path, _)) => "Regex",
PathAwareValue::Bool((_path, _)) => "bool",
PathAwareValue::Int((_path, _)) => "int",
PathAwareValue::Float((_path, _)) => "float",
PathAwareValue::Char((_path, _)) => "char",
PathAwareValue::List((_path, _)) => "array",
PathAwareValue::Map((_path, _)) => "map",
PathAwareValue::RangeInt((_path, _)) => "range(int, int)",
PathAwareValue::RangeFloat((_path, _)) => "range(float, float)",
PathAwareValue::RangeChar((_path, _)) => "range(char, char)",
}
}
pub(crate) fn retrieve_index<'v>(
parent: &PathAwareValue,
index: i32,
list: &'v Vec<PathAwareValue>,
query: &[QueryPart<'_>],
) -> Result<&'v PathAwareValue, Error> {
let check = if index >= 0 { index } else { -index } as usize;
if check < list.len() {
Ok(&list[check])
} else {
Err(Error::
RetrievalError(
format!("Array Index out of bounds for path = {} on index = {} inside Array = {:?}, remaining query = {}",
parent.self_path(), index, list, SliceDisplay(query))
))
}
}
pub(crate) fn accumulate<'v>(
parent: &PathAwareValue,
all: bool,
query: &[QueryPart<'_>],
elements: &'v Vec<PathAwareValue>,
resolver: &dyn EvaluationContext,
) -> Result<Vec<&'v PathAwareValue>, Error> {
if elements.is_empty() && !query.is_empty() && all {
return Err(Error::RetrievalError(format!(
"No entries for path = {} . Remaining Query {}",
parent.self_path(),
SliceDisplay(query)
)));
}
let mut accumulated = Vec::with_capacity(elements.len());
for each in elements {
if !query.is_empty() {
accumulated.extend(each.select(all, query, resolver)?);
} else {
accumulated.push(each);
}
}
Ok(accumulated)
}
}
fn compare_values(first: &PathAwareValue, other: &PathAwareValue) -> Result<Ordering, Error> {
match (first, other) {
(PathAwareValue::Null(_), PathAwareValue::Null(_)) => Ok(Ordering::Equal),
(PathAwareValue::Int((_, i)), PathAwareValue::Int((_, o))) => Ok(i.cmp(o)),
(PathAwareValue::String((_, s)), PathAwareValue::String((_, o))) => Ok(s.cmp(o)),
(PathAwareValue::Float((_, f)), PathAwareValue::Float((_, s))) => match f.partial_cmp(s) {
Some(o) => Ok(o),
None => Err(Error::NotComparable(
"Float values are not comparable".to_owned(),
)),
},
(PathAwareValue::Char((_, f)), PathAwareValue::Char((_, s))) => Ok(f.cmp(s)),
(_, _) => Err(Error::NotComparable(format!(
"PathAwareValues are not comparable {}, {}",
first.type_info(),
other.type_info()
))),
}
}
#[allow(clippy::never_loop)]
pub(crate) fn compare_eq(first: &PathAwareValue, second: &PathAwareValue) -> Result<bool, Error> {
let (reg, s) = match (first, second) {
(PathAwareValue::String((_, s)), PathAwareValue::Regex((_, r))) => {
(Regex::try_from(r.as_str()).map_err(Box::new)?, s.as_str())
}
(PathAwareValue::Regex((_, r)), PathAwareValue::String((_, s))) => {
(Regex::try_from(r.as_str()).map_err(Box::new)?, s.as_str())
}
(PathAwareValue::String((_, s1)), PathAwareValue::String((_, s2))) => return Ok(s1 == s2),
(PathAwareValue::Map((_, map)), PathAwareValue::Map((_, map2))) => {
return Ok('result: loop {
if map.values.len() == map2.values.len() {
for (key, value) in map.values.iter() {
match map2.values.get(key) {
Some(value2) => {
if !compare_eq(value, value2)? {
break 'result false;
}
}
None => {
break 'result false;
}
}
}
break 'result true;
}
break 'result false;
})
}
(PathAwareValue::List((_, list)), PathAwareValue::List((_, list2))) => {
return Ok('result: loop {
if list.len() == list2.len() {
for (left, right) in list.iter().zip(list2.iter()) {
if !compare_eq(left, right)? {
break 'result false;
}
}
break 'result true;
}
break 'result false;
});
}
(PathAwareValue::Bool((_, b1)), PathAwareValue::Bool((_, b2))) => return Ok(b1 == b2),
(PathAwareValue::Regex((_, r)), PathAwareValue::Regex((_, s))) => return Ok(r == s),
(PathAwareValue::Int((_, value)), PathAwareValue::RangeInt((_, r))) => {
return Ok(value.is_within(r))
}
(PathAwareValue::Float((_, value)), PathAwareValue::RangeFloat((_, r))) => {
return Ok(value.is_within(r))
}
(PathAwareValue::Char((_, value)), PathAwareValue::RangeChar((_, r))) => {
return Ok(value.is_within(r))
}
(_, _) => {
return match compare_values(first, second)? {
Ordering::Equal => Ok(true),
_ => Ok(false),
}
}
};
let match_result = reg.is_match(s);
match match_result {
Ok(is_match) => Ok(is_match),
Err(error) => Err(Error::from(Box::new(error))),
}
}
pub(crate) fn compare_lt(first: &PathAwareValue, other: &PathAwareValue) -> Result<bool, Error> {
match compare_values(first, other) {
Ok(o) => match o {
Ordering::Equal | Ordering::Greater => Ok(false),
Ordering::Less => Ok(true),
},
Err(e) => Err(e),
}
}
pub(crate) fn compare_le(first: &PathAwareValue, other: &PathAwareValue) -> Result<bool, Error> {
match compare_values(first, other) {
Ok(o) => match o {
Ordering::Greater => Ok(false),
Ordering::Equal | Ordering::Less => Ok(true),
},
Err(e) => Err(e),
}
}
pub(crate) fn compare_gt(first: &PathAwareValue, other: &PathAwareValue) -> Result<bool, Error> {
match compare_values(first, other) {
Ok(o) => match o {
Ordering::Greater => Ok(true),
Ordering::Less | Ordering::Equal => Ok(false),
},
Err(e) => Err(e),
}
}
pub(crate) fn compare_ge(first: &PathAwareValue, other: &PathAwareValue) -> Result<bool, Error> {
match compare_values(first, other) {
Ok(o) => match o {
Ordering::Greater | Ordering::Equal => Ok(true),
Ordering::Less => Ok(false),
},
Err(e) => Err(e),
}
}
#[cfg(test)]
#[path = "path_value_tests.rs"]
mod path_value_tests;