evobench_tools/serde_util/
mod.rs

1//! Utilities for working with serde
2
3pub mod json5_from_str;
4
5use std::{cell::RefCell, fmt::Display, path::Path};
6
7use anyhow::Result;
8use serde::de::DeserializeOwned;
9use serde_json::Value;
10
11use crate::ctx;
12
13/// Read the file at `path` to RAM, then deserialize it using
14/// `serde_json`. If you want to support json5 or ron, use
15/// `config_file.rs` instead.
16pub fn serde_read_json<T: DeserializeOwned>(path: &Path) -> Result<T> {
17    (|| -> Result<_> {
18        let s = std::fs::read_to_string(path)?;
19        Ok(serde_json::from_str(&s)?)
20    })()
21    .map_err(ctx!("reading file {path:?}"))
22}
23
24pub struct CanonicalJson<'t>(pub &'t Value);
25
26fn display_canonical_json(json: &Value, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27    match json {
28        Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) | Value::Array(_) => {
29            write!(f, "{}", json)
30        }
31        Value::Object(map) => {
32            let display_keyval =
33                |(key, val, _): &(&String, &Value, _), f: &mut std::fmt::Formatter<'_>| {
34                    // XX oh, clone the string for no good reason;
35                    // another way to get printing?
36                    write!(f, "{}:", Value::String((*key).to_owned()))?;
37                    display_canonical_json(val, f)
38                };
39
40            f.write_str("{")?;
41            let mut keyvals: Vec<(&String, &Value, RefCell<Option<String>>)> = map
42                .iter()
43                .map(|(key, val)| (key, val, RefCell::new(None)))
44                .collect();
45            if !keyvals.is_empty() {
46                keyvals.sort_by(|a, b| {
47                    a.0.cmp(b.0).then_with(|| {
48                        let mut ar = a.2.borrow_mut();
49                        if ar.is_none() {
50                            *ar = Some(CanonicalJson(&a.1).to_string());
51                        }
52                        let mut br = b.2.borrow_mut();
53                        if br.is_none() {
54                            *br = Some(CanonicalJson(&b.1).to_string());
55                        }
56                        ar.as_ref()
57                            .expect("just set")
58                            .cmp(br.as_ref().expect("just_set"))
59                    })
60                });
61                for keyval in &keyvals[0..keyvals.len() - 1] {
62                    display_keyval(keyval, f)?;
63                    f.write_str(",")?;
64                }
65                display_keyval(keyvals.last().expect("checked non-empty"), f)?;
66            }
67            f.write_str("}")
68        }
69    }
70}
71
72impl<'t> Display for CanonicalJson<'t> {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        display_canonical_json(&self.0, f)
75    }
76}