use std::io::{Read, Write};
pub trait JsonIO {
fn from_json_reader<R: Read>(reader: R) -> Self;
fn to_json_writer<W: Write>(&self, writer: W);
fn from_json_string(json: &str) -> Self;
fn to_json_string(&self) -> String;
fn from_json_file(path: &str) -> Self;
fn to_json_file(&self, path: &str);
}
#[macro_export]
macro_rules! impl_json_io {
($type:ty) => {
impl $crate::io::JsonIO for $type {
fn from_json_reader<R: std::io::Read>(reader: R) -> Self {
let reader = std::io::BufReader::new(reader);
let json = serde_json::from_reader(reader)
.expect("Failed to parse JSON from reader.");
let id = concat!(
paste::paste! { stringify!([<$type:lower>]) },
".schema.json"
);
let validator = jsonschema::options()
.with_retriever(&*$crate::assets::JSON_SCHEMA_RETRIEVER)
.build(&serde_json::json!({"$ref": id}))
.expect("Failed to build JSON Schema validator.");
validator
.validate(&json)
.expect("Failed to validate JSON against schema.");
serde_json::from_value(json)
.expect("Failed to convert JSON to type.")
}
fn to_json_writer<W: std::io::Write>(&self, writer: W) {
let writer = std::io::BufWriter::new(writer);
serde_json::to_writer(writer, self)
.expect("Failed to write JSON to writer.");
}
fn from_json_string(json: &str) -> Self {
Self::from_json_reader(json.as_bytes())
}
fn to_json_string(&self) -> String {
let mut buffer = Vec::new();
self.to_json_writer(&mut buffer);
String::from_utf8(buffer)
.expect("Failed to convert JSON to string.")
}
fn from_json_file(path: &str) -> Self {
let file = std::fs::File::open(path)
.expect("Failed to open JSON file.");
let reader = std::io::BufReader::new(file);
Self::from_json_reader(reader)
}
fn to_json_file(&self, path: &str) {
let file = std::fs::File::create(path)
.expect("Failed to create JSON file.");
let writer = std::io::BufWriter::new(file);
self.to_json_writer(writer);
}
}
};
}