causal_hub/io/
json.rs

1/// A trait for reading and writing JSON files.
2pub trait JsonIO {
3    /// Create an instance of the type from a JSON string.
4    ///
5    /// # Arguments
6    ///
7    /// * `json` - The JSON string to parse.
8    ///
9    /// # Returns
10    ///
11    /// An instance of the type.
12    ///
13    fn from_json(json: &str) -> Self;
14
15    /// Convert the instance to a JSON string.
16    ///
17    /// # Returns
18    ///
19    /// A JSON string representation of the instance.
20    ///
21    fn to_json(&self) -> String;
22
23    /// Create an instance of the type from a JSON file.
24    ///
25    /// # Arguments
26    ///
27    /// * `path` - The path to the JSON file.
28    ///
29    /// # Returns
30    ///
31    /// An instance of the type.
32    ///
33    fn read_json(path: &str) -> Self;
34
35    /// Write the instance to a JSON file.
36    ///
37    /// # Arguments
38    ///
39    /// * `path` - The path to the JSON file.
40    ///
41    fn write_json(&self, path: &str);
42}
43
44/// A macro to implement the `JsonIO` trait for a given type.
45#[macro_export]
46macro_rules! impl_json_io {
47    ($type:ty) => {
48        impl $crate::io::JsonIO for $type {
49            fn from_json(json: &str) -> Self {
50                // Parse the JSON string.
51                let json = serde_json::from_str(json).unwrap();
52                // Get the JSON Schema id.
53                let id = concat!(paste::paste! { stringify!([<$type:lower>]) }, ".schema.json");
54                // Load the JSON Schema validator.
55                let validator = jsonschema::options()
56                    .with_retriever(&*$crate::assets::JSON_SCHEMA_RETRIEVER)
57                    .build(&serde_json::json!({"$ref": id}))
58                    .unwrap();
59                // Validate the JSON against the schema.
60                validator.validate(&json).unwrap();
61                // Convert the parsed JSON to the type.
62                serde_json::from_value(json).unwrap()
63            }
64
65            fn to_json(&self) -> String {
66                serde_json::to_string(self).unwrap()
67            }
68
69            fn read_json(path: &str) -> Self {
70                use std::{fs::File, io::BufReader};
71                // Open the file.
72                let file = File::open(path).unwrap();
73                // Create a buffered reader.
74                let reader = BufReader::new(file);
75                // Parse the JSON string.
76                let json = serde_json::from_reader(reader).unwrap();
77                // Get the JSON Schema id.
78                let id = concat!(paste::paste! { stringify!([<$type:lower>]) }, ".schema.json");
79                // Load the JSON Schema validator.
80                let validator = jsonschema::options()
81                    .with_retriever(&*$crate::assets::JSON_SCHEMA_RETRIEVER)
82                    .build(&serde_json::json!({"$ref": id}))
83                    .unwrap();
84                // Validate the JSON against the schema.
85                validator.validate(&json).unwrap();
86                // Convert the parsed JSON to the type.
87                serde_json::from_value(json).unwrap()
88            }
89
90            fn write_json(&self, path: &str) {
91                use std::{fs::File, io::BufWriter};
92                let file = File::create(path).unwrap();
93                let writer = BufWriter::new(file);
94                serde_json::to_writer(writer, self).unwrap()
95            }
96        }
97    };
98}