use serde::de::DeserializeOwned;
use std::path::PathBuf;
use std::{fs, io::BufReader, path::Path};
pub trait JsonSource {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error>;
}
impl JsonSource for &Path {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_reader(BufReader::new(fs::File::open(self)?))?)
}
}
impl JsonSource for &PathBuf {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_reader(BufReader::new(fs::File::open(self)?))?)
}
}
impl JsonSource for fs::File {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_reader(BufReader::new(self))?)
}
}
impl<R: std::io::Read> JsonSource for BufReader<R> {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_reader(self)?)
}
}
impl JsonSource for &Vec<u8> {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_slice(self)?)
}
}
impl JsonSource for &[u8] {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_slice(self)?)
}
}
impl<const N: usize> JsonSource for &[u8; N] {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_slice(self)?)
}
}
impl JsonSource for serde_json::Value {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_value(self)?)
}
}
impl JsonSource for &str {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_str(self)?)
}
}
impl JsonSource for &String {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_str(self)?)
}
}
pub struct Reader<R: std::io::Read>(pub R);
impl<R: std::io::Read> JsonSource for Reader<R> {
fn parse<T: DeserializeOwned>(self) -> Result<T, std::io::Error> {
Ok(serde_json::from_reader(self.0)?)
}
}
#[cfg(test)]
mod test {
use super::*;
use std::io::{Cursor, Seek, SeekFrom, Write};
#[derive(Debug, serde::Deserialize)]
struct TestDocument {}
fn load<T: JsonSource>(source: T) -> std::io::Result<TestDocument> {
source.parse()
}
#[test]
fn from_str() {
let _ = load("{}").expect("must load");
}
#[test]
fn from_slice() {
let _ = load(&b"{}"[..]).expect("must load");
}
#[test]
fn from_array() {
let _ = load(b"{}").expect("must load");
}
#[test]
fn from_file() {
let mut t = tempfile::tempfile().expect("must create temp file");
t.write_all(br#"{}"#).expect("must write to temp file");
t.seek(SeekFrom::Start(0)).expect("must seek");
let _ = load(t).expect("must load");
}
#[test]
fn from_path() {
let t = tempfile::tempdir().expect("must create temp dir");
let path = t.path().join("test.json");
fs::write(&path, br#"{}"#).expect("must write to temp file");
let _ = load(&path).expect("must load");
let _ = load(&path as &Path).expect("must load");
t.close().expect("must close file");
}
#[test]
fn from_any_reader() {
let s = br#"{}"#;
let c = Cursor::new(s);
let _ = load(Reader(c)).expect("must load");
}
}