0

Serialization and deserialization for most of my structs and enums can be easily implemented using #[derive(Serialize, Deserialize)].

A few structs require careful crafting to implement. I am new to serde. I succeeded in implementing the From trait to convert one particularly tricky compositional hierarchy of structs and enums with Rcs and RefCells and Options and such to and from serde_json::Value. Since I have this conversion working, can I leverage it to implement the Serialize and Deserialize traits? My ultimate goal is to-and-from JSON conversion for use with web service REST calls.

For example, I have conversion from one of my types named ShyValue to Value, in two parts:

impl From<&ShyScalar> for Value {
    /// Create a Serde Value from a ShyScalar.
    /// Since Serde Values can only represent what is valid for JSON (e.g. no NaN values),
    /// encode unsupported values as Value::Strings, often by prepending a suffix.
    /// The reverse conversion will need to parse these strings out and reconstruct the proper ShyValue.
    fn from(s: &ShyScalar) -> Self {
        match s {
            // ... lots of code removed ...
        }
    }
}

impl From<&ShyValue> for Value {
    fn from(v: &ShyValue) -> Self {
        match v {
            ShyValue::Scalar(scalar) => scalar.into(),
            // ... lots more code removed ...
        }
    }
}

Then I have a conversion in the other direction:

impl From<&Value> for ShyValue {
    fn from(v: &Value) -> Self {
        match v {
            Value::Null => ShyValue::Scalar(ShyScalar::Null),
            Value::Bool(b) => b.into(),

            // A Value::String may represent any of several ShyValue variants, so must be parsed.
            // The prefix (if any) usually determines which variant to create.
            Value::String(ref nan) if nan.to_lowercase() == "nan" => {
                ShyValue::Scalar(f64::NAN.into())
            }
            Value::String(ref err) if err.starts_with("Error: ") => {
                ShyValue::error(err[7..].into())
            }
            Value::String(ref func_name) if func_name.starts_with("FunctionName: ") => {
                ShyValue::FunctionName(func_name[13..].into())
            }
            Value::String(ref prop_chain) if prop_chain.starts_with("PropertyChain: ") => {
                ShyValue::property_chain(prop_chain[15..].into())
            }
            Value::String(ref variable) if variable.starts_with("Variable: ") => {
                ShyValue::Variable(variable[10..].into())
            }
            Value::String(s) => s.clone().into(),

            Value::Number(ref n) if (*n).is_i64() => {
                ShyValue::Scalar(ShyScalar::Integer(n.as_i64().unwrap()))
            }
            Value::Number(ref f) => ShyValue::Scalar(ShyScalar::Rational(f.as_f64().unwrap())),
            Value::Array(a) => ShyValue::Vector(
                a.iter()
                    .map(|item| match item {
                        Value::Null => ShyScalar::Null,
                        Value::Bool(b) => (*b).into(),
                        Value::String(s) => s.clone().into(),
                        Value::Number(ref n) if (*n).is_i64() => {
                            ShyScalar::Integer(n.as_i64().unwrap())
                        }
                        Value::Number(ref f) => ShyScalar::Rational(f.as_f64().unwrap()),
                        _ => ShyScalar::Error("Unsupported type of scalar".into()),
                    })
                    .collect(),
            ),
            Value::Object(o) => {
                let shy_object = ShyObject::empty();
                {
                    let mut assoc = shy_object.as_deref_mut();
                    for (key, value) in o {
                        assoc.set(key, value.into());
                    }
                }
                ShyValue::Object(shy_object)
            }
        }
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Paul Chernoch
  • 5,275
  • 3
  • 52
  • 73
  • It looks like your question might be answered by the answers of [How to transform fields during serialization using Serde?](https://stackoverflow.com/q/39383809/155423) / [How to transform fields during deserialization using Serde?](https://stackoverflow.com/q/46753955/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Oct 14 '19 at 19:26
  • 1
    Thank you! One of those answers looks like it might work. – Paul Chernoch Oct 14 '19 at 19:30
  • 1
    [The duplicate applied to a similar situation as yours](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4e98ec91d349949a5ec95a21794720d9). – Shepmaster Oct 14 '19 at 19:31

0 Answers0