use std::{fmt, fmt::Debug, marker::PhantomData, str::FromStr};
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use crate::data_type::DataType;
use crate::{prelude::*, MakeOperators, MatchLiteral};
fn serialize<'a, T: Clone, S: Serializer, Ex: Express<'a, T>>(
serializer: S,
expr: &Ex,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(expr.unparse())
}
impl<T: DataType, OF: MakeOperators<T>, LMF: MatchLiteral> Serialize for FlatEx<T, OF, LMF>
where
<T as FromStr>::Err: Debug,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize(serializer, self)
}
}
impl<'de, T: DataType + 'de, OF: MakeOperators<T>, LMF: MatchLiteral> Deserialize<'de>
for FlatEx<T, OF, LMF>
where
<T as std::str::FromStr>::Err: Debug,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let visitor = FlatExVisitor {
lifetime_dummy: PhantomData,
of_dummy: PhantomData,
literal_matcher_dummy: PhantomData,
};
deserializer.deserialize_str(visitor)
}
}
#[derive(Debug)]
struct FlatExVisitor<'a, T, OF, LMF> {
lifetime_dummy: PhantomData<&'a T>,
of_dummy: PhantomData<OF>,
literal_matcher_dummy: PhantomData<LMF>,
}
impl<'de, T: DataType, OF: MakeOperators<T>, LMF: MatchLiteral> Visitor<'de>
for FlatExVisitor<'de, T, OF, LMF>
where
<T as std::str::FromStr>::Err: Debug,
{
type Value = FlatEx<T, OF, LMF>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "a borrowed &str that can be parsed by `exmex` crate")
}
fn visit_borrowed_str<E>(self, unparsed: &'de str) -> Result<Self::Value, E>
where
E: de::Error,
{
let flatex = Self::Value::parse(unparsed);
flatex.map_err(|epe| E::custom(format!("Parse error - {}", epe.msg())))
}
fn visit_str<E>(self, unparsed: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let flatex = Self::Value::parse(unparsed);
flatex.map_err(|epe| E::custom(format!("Parse error - {}", epe.msg())))
}
}
#[cfg(test)]
use crate::operators::{BinOp, Operator};
#[cfg(feature = "partial")]
#[cfg(test)]
use serde_test::Token;
#[cfg(feature = "partial")]
#[test]
fn test_ser_de() {
let test_inner = |exp, s| {
serde_test::assert_ser_tokens(&exp, &[Token::Str(s)]);
let serialized = serde_json::to_string(&exp).unwrap();
let deserialized = serde_json::from_str::<FlatEx<f64>>(serialized.as_str()).unwrap();
assert_eq!(s, format!("{}", deserialized));
};
let test = |s, s_1| {
let flatex = FlatEx::<f64>::parse(s).unwrap();
test_inner(flatex.clone(), s);
let dflatex_dy = flatex.clone().partial(1).unwrap();
println!("{:#?}", dflatex_dy);
test_inner(dflatex_dy.clone(), s_1);
};
test("{x}+{y}*2.0", "2.0");
test("{x}+sin(2.0*{y})", "2.0*cos(2.0*{y})");
test("1.0/{x}+cos({y})*2.0", "2.0*-(sin({y}))");
test("{y}*{x}*2.0", "2.0*{x}");
}
#[test]
fn test_ser_de_non_float() {
fn test(to_be_parsed: &str, ref_val: i32) {
#[derive(Clone, Debug)]
struct IntegerOps;
impl MakeOperators<i32> for IntegerOps {
fn make<'a>() -> Vec<Operator<'a, i32>> {
vec![
Operator::make_bin(
"%",
BinOp {
apply: |a: i32, b: i32| a % b,
prio: 1,
is_commutative: false,
},
),
Operator::make_bin(
"/",
BinOp {
apply: |a: i32, b: i32| a / b,
prio: 1,
is_commutative: false,
},
),
]
}
}
let expr = FlatEx::<i32, IntegerOps>::parse(to_be_parsed).unwrap();
let serialized = serde_json::to_string(&expr).unwrap();
let deserialized =
serde_json::from_str::<FlatEx<i32, IntegerOps>>(serialized.as_str()).unwrap();
assert_eq!(deserialized.eval(&[1]).unwrap(), ref_val);
}
test("19 % 5 / 2 / a", 2);
test("4 % 2 / a", 0);
test("4 / 2 / a", 2);
test("4 / 2 / 2 / a", 1);
}