parsing_custom_struct/
parsing-custom-struct.rs1#![allow(unused)]
2
3#[derive(Debug)]
4struct Person {
5 name: String,
6 age: u8,
7 alive: bool,
8}
9
10const PEOPLE: [&str; 14] = [
11 r#"{ "name": "Zen", "age": 10, "alive": true }"#,
12 "",
13 ";",
14 "0",
15 "{}",
16 r#"{ "name": 0 }"#,
17 r#"{ "name": " " }"#,
18 r#"{ "name": "Katya" }"#,
19 r#"{ "name": "Katya", "age": null }"#,
20 r#"{ "name": "Katya", "age": 0.1 }"#,
21 r#"{ "name": "Katya", "age": -1 }"#,
22 r#"{ "name": "Katya", "age": 8 }"#,
23 r#"{ "name": "Katya", "age": 8, "alive": [] }"#,
24 r#"{ "name": "Katya", "age": 8, "alive": false }"#,
25];
26
27fn main() {
28 for json in PEOPLE {
29 match parse_person(json) {
30 Ok(p) => println!("{p:#?}"),
31 Err(err) => eprintln!("failed to parse r#\"{json}\"#: {err:?}"),
32 }
33 }
34}
35
36#[derive(Debug)]
37enum ParsePersonError {
38 JsonParse(jso::parse::Error),
39 JsonNotAnObject,
40 Custom(&'static str),
41}
42
43fn parse_person(s: &str) -> Result<Person, ParsePersonError> {
44 use ParsePersonError::*;
45
46 let json = jso::parse(s).map_err(JsonParse)?;
47 let mut o = json.obj().ok_or(JsonNotAnObject)?;
48
49 let name = o
50 .remove("name")
51 .ok_or(Custom("missing \"name\""))?
52 .str()
53 .ok_or(Custom("\"name\" is not a string"))?
54 .trim()
55 .to_string();
56
57 if name.is_empty() {
58 return Err(Custom("\"name\" empty"));
59 }
60
61 let age = o
62 .remove("age")
63 .ok_or(Custom("missing \"age\""))?
64 .num()
65 .ok_or(Custom("\"age\" is not a number"))?;
66
67 if age.fract() != 0. {
68 return Err(Custom("\"age\" must be an integer"));
69 }
70
71 if !(0.0..=255.0).contains(&age) {
72 return Err(Custom("\"age\" must be between 0-255"));
73 }
74
75 let age = age as u8;
76
77 let alive = o
78 .remove("alive")
79 .ok_or(Custom("missing \"alive\""))?
80 .bool()
81 .ok_or(Custom("\"alive\" not a boolean"))?;
82
83 Ok(Person { name, age, alive })
84}