6

I'm relatively new to Rust, and even more so to Serde, so I'm having trouble finding out if this is even doable. I have a JSON file which has two different representations for the same key:

"coordinates": [
  [
    [
      121.423364,
      24.9913596
    ],
    [
      121.4233327,
      24.9912977
    ],
  ]
]

and this:

"coordinates": [
  [
    121.4472492,
    25.0052053
  ],
  [
    121.4466457,
    25.0028547
  ]
]

There is a two dimensional array and a three dimensional array representing ways in the same attribute. This makes the file hard to serialize.

Here is the code that I implemented:

#[derive(Serialize, Deserialize, Debug)]
struct Geometry {
    #[serde(deserialize_with = "string_or_number", rename = "type")]
    geometry_type: Value,
    #[serde(default, skip_serializing_if = "Vec::is_empty", rename = "coordinates")]
    geometry_coor: Vec<Coordinates>,
    #[serde(default, skip_serializing_if = "Vec::is_empty", rename = "coordinates")]
    geometry_coor2: Vec<Vec<Coordinates>>,
}

#[derive(Serialize, Deserialize, Debug)]
struct Coordinates {
    #[serde(deserialize_with = "string_or_number")]
    longitude: Value,
    #[serde(deserialize_with = "string_or_number")]
    latitude: Value,
}

fn string_or_number<'de, D>(de: D) -> Result<Value, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let helper: Value = Deserialize::deserialize(de)?;

    match helper {
        Value::Number(n) => {
            println!("{:#?}", n.as_f64().unwrap().to_string());
            Ok(Value::Number(n))
        }
        Value::String(s) => Ok(json!(s)),
        _ => Ok(json!(null)),
    }
}

I have trouble in struct Geometry which serializes the file of coordinates.

Are there any ways that I can deal with this kind of form?

0

1 Answer 1

3

I got help from the serde-rs developer:

I would recommend using an untagged enum to represent a coordinate array that can be 2d or 3d. Playground link

Here is the code after modification:

#[derive(Serialize, Deserialize, Debug)]
struct Geometry {
    #[serde(deserialize_with = "string_or_number", rename = "type")]
    geometry_type: Value,
    #[serde(default, skip_serializing_if = "Vec::is_empty", rename = "coordinates")]
    geometry_coor: Vec<Coordinates_form>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
enum Coordinates_form {
    #[serde(skip_serializing)]
    OneD(Coordinates),
    #[serde(skip_serializing)]
    TwoD(Vec<Coordinates>),
    #[serde(skip_serializing)]
    ThreeD(Vec<Vec<Coordinates>>),
}

#[derive(Deserialize, Debug)]
struct Coordinates {
    #[serde(deserialize_with = "string_or_number")]
    longitude: Value, 
    #[serde(deserialize_with = "string_or_number")]
    latitude: Value,
}

fn string_or_number<'de, D>(de: D) -> Result<Value, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let helper: Value = Deserialize::deserialize(de)?;

    match helper {
        Value::Number(n) => {
            println!("{:#?}", n.as_f64().unwrap().to_string());
            Ok(Value::Number(n))
        }
        Value::String(s) => Ok(json!(s)),
        _ => Ok(json!(null)),
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.