How can I force serde to parse a JSON Number as a Rust u16 type?
Below I parse a JSON file. json_data
is of type Value. This only has a as_u64()
method, no as_u16()
. As a result I first have to parse the JSON Number as a u64, then try and parse that as u16. This seems fairly convoluted. Is there some way I can force serde_json to parse this value as a u16 to avoid this?
(As a side note, the JSON data has already been validated using a JSON schema, which checks the value of x is within the bounds of u16).
$ cat test.json
{
"x": 100
}
use serde_json::Value;
use std::fs::File;
use std::io::BufReader;
pub struct Test {
pub x: u16,
}
fn main() {
let filename = "test.json";
let file =
File::open(filename).unwrap_or_else(|e| panic!("Unable to open file {}: {}", filename, e));
let reader = BufReader::new(file);
let json_data: Value = serde_json::from_reader(reader)
.unwrap_or_else(|e| panic!("Unable to parse JSON file {}: {}", filename, e));
assert!(json_data["x"].is_u64());
let mut t = Test { x: 5 };
if json_data["x"].is_u64() {
let _new_x: u64 = json_data["x"].as_u64().expect("Unable to parse x");
t.x = u16::try_from(_new_x).expect("Unable to convert x to u16");
}
}
Don't use the raw serde_json::Value
type for this usecase.
While it is possible, it is not what serde
is intended for; instead, serde
is meant to deserialize directly into your struct.
The magic here is adding a #[derive(Deserialize)]
to your struct. Be aware that you need to activate the derive
feature of serde
for this.
Like so:
use serde::Deserialize;
use std::fs::File;
use std::io::BufReader;
#[derive(Debug, Deserialize)]
pub struct Test {
pub x: u16,
}
fn main() {
let filename = "test.json";
let file =
File::open(filename).unwrap_or_else(|e| panic!("Unable to open file {}: {}", filename, e));
let reader = BufReader::new(file);
let json_data: Test = serde_json::from_reader(reader)
.unwrap_or_else(|e| panic!("Unable to parse JSON file {}: {}", filename, e));
println!("{:?}", json_data)
}
Test { x: 100 }
If you now change the test.json
to:
{
"x": 123456
}
You get:
thread 'main' panicked at src\main.rs:16:29:
Unable to parse JSON file test.json: invalid value: integer `123456`, expected u16 at line 2 column 16