esexpr-json 0.1.20

ESExpr serialization JSON encoding mappings.
Documentation
use base64::{Engine, prelude::BASE64_STANDARD};
use esexpr::{ESExpr, ESExprCodec};
use num_bigint::{BigInt, BigUint};



use core::f32;
use std::collections::HashMap;

#[derive(ESExprCodec, Debug, PartialEq)]
pub enum JsonExpr {
    Obj {
        #[dict]
        values: HashMap<String, JsonExpr>,
    },

    #[inline_value]
    Arr(Vec<JsonExpr>),

    #[inline_value]
    Str(String),

    #[inline_value]
    Num(f64),

    #[inline_value]
    Bool(bool),

    #[inline_value]
    Null(()),
}

impl JsonExpr {
    pub fn from_json(value: serde_json::Value) -> JsonExpr {
        match value {
            serde_json::Value::Null => JsonExpr::Null(()),
            serde_json::Value::Bool(b) => JsonExpr::Bool(b),
            serde_json::Value::Number(n) => JsonExpr::Num(n.as_f64().unwrap()),
            serde_json::Value::String(s) => JsonExpr::Str(s),
            serde_json::Value::Array(arr) => JsonExpr::Arr(arr.into_iter().map(Self::from_json).collect()),
            serde_json::Value::Object(obj) => {
                let values: HashMap<_, _> = obj.into_iter()
                    .map(|(k, v)| (k, Self::from_json(v)))
                    .collect();

                JsonExpr::Obj { values }
            },
        }
    }

    pub fn into_json(self) -> serde_json::Value {
        match self {
            JsonExpr::Obj { values } => {
                let obj: serde_json::Map<_, _> = values.into_iter()
                    .map(|(k, v)| (k, v.into_json()))
                    .collect();

                serde_json::Value::Object(obj)
            },
            JsonExpr::Arr(arr) => serde_json::Value::Array(arr.into_iter().map(Self::into_json).collect()),
            JsonExpr::Str(s) => serde_json::Value::String(s),
            JsonExpr::Num(n) => serde_json::Value::Number(serde_json::Number::from_f64(n).unwrap()),
            JsonExpr::Bool(b) => serde_json::Value::Bool(b),
            JsonExpr::Null(_) => serde_json::Value::Null,
        }
    }
}


#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum JsonEncodedESExpr {
    Constructor {
        constructor_name: String,
        args: Option<Vec<JsonEncodedESExpr>>,
        kwargs: Option<HashMap<String, JsonEncodedESExpr>>,
    },
    List(Vec<JsonEncodedESExpr>),

    Bool(bool),
    Int {
        int: JsonBigIntValue,
    },
    Str(String),
    Binary {
        base64: Base64Value,
    },
    Float32 {
        #[serde(deserialize_with="deserialize_f32", serialize_with="serialize_f32")]
        float32: f32,
    },
    Float64 {
        #[serde(deserialize_with="deserialize_f64", serialize_with="serialize_f64")]
        float64: f64,
    },
    Null(()),
    NullLevel {
        null: JsonBigIntValue,
    },

}

impl JsonEncodedESExpr {
    pub fn from_esexpr(expr: ESExpr) -> Self {
        match expr {
            ESExpr::Constructor { name, args, kwargs } =>
                JsonEncodedESExpr::Constructor {
                    constructor_name: name,
                    args: Some(
                        args
                            .into_iter()
                            .map(Self::from_esexpr)
                            .collect()
                    ),
                    kwargs: Some(
                        kwargs
                            .into_iter()
                            .map(|(k, v)| (k, Self::from_esexpr(v)))
                            .collect()
                    ),
                },
            ESExpr::Bool(b) => JsonEncodedESExpr::Bool(b),
            ESExpr::Int(i) => JsonEncodedESExpr::Int { int: JsonBigIntValue(i) },
            ESExpr::Str(s) => JsonEncodedESExpr::Str(s),
            ESExpr::Binary(b) => JsonEncodedESExpr::Binary { base64: Base64Value(b) },
            ESExpr::Float32(float32) => JsonEncodedESExpr::Float32 { float32 },
            ESExpr::Float64(float64) => JsonEncodedESExpr::Float64 { float64 },
            ESExpr::Null(level) if level == BigUint::ZERO => JsonEncodedESExpr::Null(()),
            ESExpr::Null(level) => JsonEncodedESExpr::NullLevel { null: JsonBigIntValue(level.into()) },
        }
    } 

    pub fn into_esexpr(self) -> ESExpr {
        match self {
            JsonEncodedESExpr::Constructor { constructor_name, args, kwargs } =>
                ESExpr::Constructor {
                    name: constructor_name,
                    args: args.unwrap_or_default()
                        .into_iter()
                        .map(Self::into_esexpr)
                        .collect(),
                    kwargs: kwargs.unwrap_or_default()
                        .into_iter()
                        .map(|(k, v)| (k, v.into_esexpr()))
                        .collect()
                },
            JsonEncodedESExpr::List(l) =>
                ESExpr::Constructor {
                    name: "list".to_owned(),
                    args: l.into_iter().map(Self::into_esexpr).collect(),
                    kwargs: Default::default(),
                },

            JsonEncodedESExpr::Bool(b) => ESExpr::Bool(b),
            JsonEncodedESExpr::Int { int } => ESExpr::Int(int.0),
            JsonEncodedESExpr::Str(s) => ESExpr::Str(s),
            JsonEncodedESExpr::Binary { base64 } => ESExpr::Binary(base64.0),
            JsonEncodedESExpr::Float32 { float32 } => ESExpr::Float32(float32),
            JsonEncodedESExpr::Float64 { float64 } => ESExpr::Float64(float64),
            JsonEncodedESExpr::Null(_) => ESExpr::Null(BigUint::ZERO),
            JsonEncodedESExpr::NullLevel { null } => ESExpr::Null(null.0.to_biguint().unwrap())
        }
    } 
}

#[derive(Debug, PartialEq)]
pub struct JsonBigIntValue(BigInt);


impl serde::Serialize for JsonBigIntValue {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&self.0.to_string())
    }
}

struct BigIntVisitor;

impl<'de> serde::de::Visitor<'de> for BigIntVisitor {
    type Value = BigInt;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a string containing a big integer")
    }

    fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<BigInt, E> {
        BigInt::parse_bytes(value.as_bytes(), 10)
            .ok_or_else(|| serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self))
    }
}

impl<'de> serde::Deserialize<'de> for JsonBigIntValue {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let int = deserializer.deserialize_str(BigIntVisitor)?;
        Ok(JsonBigIntValue(int))
    }
}



#[derive(Debug, PartialEq)]
pub struct Base64Value(Vec<u8>);

impl serde::Serialize for Base64Value {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
    {
        let encoded = BASE64_STANDARD.encode(&self.0);
        serializer.serialize_str(&encoded)
    }
}

struct Base64Visitor;

impl<'de> serde::de::Visitor<'de> for Base64Visitor {
    type Value = Vec<u8>;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a base64 encoded string")
    }

    fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Vec<u8>, E> {
        BASE64_STANDARD.decode(value).map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self))
    }
}

impl<'de> serde::Deserialize<'de> for Base64Value {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let bytes = deserializer.deserialize_str(Base64Visitor)?;
        Ok(Base64Value(bytes))
    }
}



fn serialize_f32<S: serde::Serializer>(f: &f32, serializer: S) -> Result<S::Ok, S::Error> {
    match *f {
        f if f.is_nan() => serializer.serialize_str("nan"),
        f if f.is_infinite() && f.is_sign_positive() => serializer.serialize_str("+inf"),
        f if f.is_infinite() && f.is_sign_negative() => serializer.serialize_str("-inf"),
        f => serializer.serialize_f32(f)
    }
}

fn deserialize_f32<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<f32, D::Error> {
    struct Float32ValueVisitor;

    impl<'de> serde::de::Visitor<'de> for Float32ValueVisitor {
        type Value = f32;

        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
            formatter.write_str("a number or a string containing nan, +inf, or -inf")
        }

        fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<f32, E> {
            Ok(v as f32)
        }

        fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<f32, E> {
            Ok(v as f32)
        }

        fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<f32, E> {
            Ok(v as f32)
        }

        fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<f32, E> {
            match value {
                "nan" => Ok(f32::NAN),
                "+inf" => Ok(f32::INFINITY),
                "-inf" => Ok(f32::NEG_INFINITY),
                _ => Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self)),
            }
        }
    }

    deserializer.deserialize_any(Float32ValueVisitor)
}


fn serialize_f64<S: serde::Serializer>(f: &f64, serializer: S) -> Result<S::Ok, S::Error> {
    match *f {
        f if f.is_nan() => serializer.serialize_str("nan"),
        f if f.is_infinite() && f.is_sign_positive() => serializer.serialize_str("+inf"),
        f if f.is_infinite() && f.is_sign_negative() => serializer.serialize_str("-inf"),
        f => serializer.serialize_f64(f)
    }
}

fn deserialize_f64<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<f64, D::Error> {
    struct Float64ValueVisitor;

    impl<'de> serde::de::Visitor<'de> for Float64ValueVisitor {
        type Value = f64;

        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
            formatter.write_str("a number or a string containing nan, +inf, or -inf")
        }

        fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<f64, E> {
            Ok(v as f64)
        }

        fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<f64, E> {
            Ok(v as f64)
        }

        fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<f64, E> {
            Ok(v)
        }

        fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<f64, E> {
            match value {
                "nan" => Ok(f64::NAN),
                "+inf" => Ok(f64::INFINITY),
                "-inf" => Ok(f64::NEG_INFINITY),
                _ => Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self)),
            }
        }
    }

    deserializer.deserialize_any(Float64ValueVisitor)
}