use serde_json::{Number, Value};
use crate::error::Error;
use crate::op::{DataOperation, LazyOperation, Operation};
use crate::Parser;
#[derive(Debug)]
pub enum Parsed<'a> {
Operation(Operation<'a>),
LazyOperation(LazyOperation<'a>),
DataOperation(DataOperation<'a>),
Raw(Raw<'a>),
}
impl<'a> Parsed<'a> {
pub fn from_value(value: &'a Value) -> Result<Self, Error> {
Operation::from_value(value)?
.map(Self::Operation)
.or(LazyOperation::from_value(value)?.map(Self::LazyOperation))
.or(DataOperation::from_value(value)?.map(Self::DataOperation))
.or(Raw::from_value(value)?.map(Self::Raw))
.ok_or_else(|| {
Error::UnexpectedError(format!("Failed to parse Value {:?}", value))
})
}
pub fn from_values(values: Vec<&'a Value>) -> Result<Vec<Self>, Error> {
values
.into_iter()
.map(Self::from_value)
.collect::<Result<Vec<Self>, Error>>()
}
pub fn evaluate(&self, data: &'a Value) -> Result<Evaluated, Error> {
match self {
Self::Operation(op) => op.evaluate(data),
Self::LazyOperation(op) => op.evaluate(data),
Self::DataOperation(op) => op.evaluate(data),
Self::Raw(val) => val.evaluate(data),
}
}
}
impl From<Parsed<'_>> for Value {
fn from(item: Parsed) -> Value {
match item {
Parsed::Operation(op) => Value::from(op),
Parsed::LazyOperation(op) => Value::from(op),
Parsed::DataOperation(op) => Value::from(op),
Parsed::Raw(raw) => Value::from(raw),
}
}
}
#[derive(Debug)]
pub struct Raw<'a> {
value: &'a Value,
}
impl<'a> Parser<'a> for Raw<'a> {
fn from_value(value: &'a Value) -> Result<Option<Self>, Error> {
Ok(Some(Self { value }))
}
fn evaluate(&self, _data: &Value) -> Result<Evaluated, Error> {
Ok(Evaluated::Raw(self.value))
}
}
impl From<Raw<'_>> for Value {
fn from(raw: Raw) -> Self {
raw.value.clone()
}
}
#[derive(Debug)]
pub enum Evaluated<'a> {
New(Value),
Raw(&'a Value),
}
impl From<Evaluated<'_>> for Value {
fn from(item: Evaluated) -> Self {
match item {
Evaluated::Raw(val) => val.clone(),
Evaluated::New(val) => val,
}
}
}
pub fn to_number_value(number: f64) -> Result<Value, Error> {
if number.fract() == 0.0 {
Ok(Value::Number(Number::from(number as i64)))
} else {
Number::from_f64(number)
.ok_or_else(|| {
Error::UnexpectedError(format!(
"Could not make JSON number from result {:?}",
number
))
})
.map(Value::Number)
}
}