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 Rc
s and RefCell
s and Option
s 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)
}
}
}
}