Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pattern match to get at the numbers that serde_json has parsed?

Tags:

json

rust

serde

I want to convert 3rd party library enums to and from JSON. As I don't want to edit the 3rd party source code I don't want to use the derive macros.

I want to handwrite the serde_json deserialize method. I am thinking that pattern matching is the way to go but the things I need to match on are not public:

extern crate serde_json;

#[test]
fn test_parse_from_json() {
    let s = r#"{
                    "e": 0,
                    "c": 1,
                    "n": 2
                  }"#;

    let v: Map<String, Value> = serde_json::from_str(&s).unwrap();

    match (&v["e"], &v["c"], &v["n"]) {
        (&Value::Number(ref e), &Value::Number(ref c), &Value::Number(ref n)) => {
            // e is a PosInt(u64) but that isn't public to match one nor access its methods!
            let value = e.n; // error[E0616]: field `n` of struct `serde_json::Number` is private
        }
        _ => (),
    }

}

That doesn't compile. If I replace that inner bit with something I can set a breakpoint on, I can see in the debugger that e is a Number which contains a PosInt(0).

like image 266
simbo1905 Avatar asked Dec 05 '25 14:12

simbo1905


1 Answers

You cannot pattern match on private fields because they are private. You have to use the accessors the library decides to provide. The serde_json documentation for Number shows that it has methods like as_u64:

let value = e.as_u64().expect("not a u64");

As I don't want to edit the 3rd party source code I don't want to use the derive macros.

You may be suffering from the X-Y problem. For example, the Serde docs describe how to implement the traits for a "remote type".

You could also create your own type that you deserialize into and construct a transformation to and from the library type:

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[derive(Deserialize)]
struct Mine {
    e: u64,
    c: u64,
    n: u64,
}

#[test]
fn test_parse_from_json() {
    let s = r#"{
        "e": 0,
        "c": 1,
        "n": 2
    }"#;

    let v: Mine = serde_json::from_str(&s).unwrap();
    println!("{:?}", (v.e, v.c, v.n));
}
like image 77
Shepmaster Avatar answered Dec 07 '25 10:12

Shepmaster