Rustc serialization of custom enum decoding

I have a JSON structure where one of the structure fields can be either an object or an object identifier in the database. Let's say the document looks like this: both possible structure formats:

[
   {
      "name":"pebbles",
      "car":1
   },
   {
      "name":"pebbles",
      "car":{
         "id":1,
         "color":"green"
      }
   }
]

I am trying to find a better way to implement a custom decoder for this. So far I have tried several different ways, and I am stuck here now:

extern crate rustc_serialize;

use rustc_serialize::{Decodable, Decoder, json};

#[derive(RustcDecodable, Debug)]
struct Car {
  id: u64,
  color: String
}

#[derive(Debug)]
enum OCar {
  Id(u64),
  Car(Car)
}

#[derive(Debug)]
struct Person {
  name: String,
  car: OCar
}

impl Decodable for Person {
  fn decode<D: Decoder>(d: &mut D) -> Result<Person, D::Error> {
    d.read_struct("root", 2, |d| {
      let mut car: OCar;

      // What magic must be done here to get the right OCar?

      /* I tried something akin to this:
      let car = try!(d.read_struct_field("car", 0, |r| {
        let r1 = Car::decode(r);
        let r2 = u64::decode(r);

        // Compare both R1 and R2, but return code for Err() was tricky
      }));
      */

      /* And this got me furthest */
      match d.read_struct_field("car", 0, u64::decode) {
        Ok(x) => {
          car = OCar::Id(x);
        },
        Err(_) => {
          car = OCar::Car(try!(d.read_struct_field("car", 0, Car::decode)));
        }
      }


      Ok(Person {
        name: try!(d.read_struct_field("name", 0, Decodable::decode)),
        car: car
      })
    })
  }
}

fn main() {
  // Vector of both forms
  let input = "[{\"name\":\"pebbles\",\"car\":1},{\"name\":\"pebbles\",\"car\":{\"id\":1,\"color\":\"green\"}}]";

  let output: Vec<Person> = json::decode(&input).unwrap();

  println!("Debug: {:?}", output);
}

The above panic attacks with EOL, which is the sentinel value of rustc-serialize, use several of its error enumerations. Full line

thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: EOF', src/libcore/result.rs:785

What is the right way to do this?

+4
source share
1 answer

rustc-serialize , , JSON, . read_struct_field ( ), , : , , , , -, , EOF.

Serde. Deserializing in Serde : , , , , , Serde visitor, , Serde , . , . , , OCar::Id OCar::Car.

:

#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate serde_json;

use serde::de::{Deserialize, Deserializer, Error, MapVisitor, Visitor};
use serde::de::value::MapVisitorDeserializer;

#[derive(Deserialize, Debug)]
struct Car {
    id: u64,
    color: String
}

#[derive(Debug)]
enum OCar {
    Id(u64),
    Car(Car),
}

struct OCarVisitor;

#[derive(Deserialize, Debug)]
struct Person {
    name: String,
    car: OCar,
}

impl Deserialize for OCar {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
        deserializer.deserialize(OCarVisitor)
    }
}

impl Visitor for OCarVisitor {
    type Value = OCar;

    fn visit_u64<E>(&mut self, v: u64) -> Result<Self::Value, E> where E: Error {
        Ok(OCar::Id(v))
    }

    fn visit_map<V>(&mut self, visitor: V) -> Result<Self::Value, V::Error> where V: MapVisitor {
        Ok(OCar::Car(try!(Car::deserialize(&mut MapVisitorDeserializer::new(visitor)))))
    }
}

fn main() {
    // Vector of both forms
    let input = "[{\"name\":\"pebbles\",\"car\":1},{\"name\":\"pebbles\",\"car\":{\"id\":1,\"color\":\"green\"}}]";

    let output: Vec<Person> = serde_json::from_str(input).unwrap();

    println!("Debug: {:?}", output);
}

:

Debug: [Person { name: "pebbles", car: Id(1) }, Person { name: "pebbles", car: Car(Car { id: 1, color: "green" }) }]

Cargo.toml:

[dependencies]
serde = "0.7"
serde_json = "0.7"
serde_macros = "0.7"
+5

Source: https://habr.com/ru/post/1648899/


All Articles