Skip to main content

module_util/file/
format.rs

1//! File formats.
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use serde::Deserialize;
7
8use crate::evaluator::Imports;
9
10///////////////////////////////////////////////////////////////////////////////
11
12/// A template module that all file formats should deserialize into.
13#[derive(Debug, Clone, Deserialize)]
14pub struct Module<T> {
15    /// Imports of the module.
16    #[serde(default)]
17    pub imports: Imports<PathBuf>,
18
19    /// Module body.
20    #[serde(flatten)]
21    pub body: T,
22}
23
24/// A file format.
25///
26/// This trait describes how to read and deserialize the contents of a file into
27/// a module.
28pub trait Format<T> {
29    /// Error for [`Format::read`].
30    type Error: std::error::Error + 'static;
31
32    /// Read the file at `path` and deserialize the module in it.
33    fn read(&mut self, path: &Path) -> Result<Module<T>, Self::Error>;
34}
35
36///////////////////////////////////////////////////////////////////////////////
37
38#[cfg(feature = "json")]
39mod json {
40    use super::*;
41
42    use std::io;
43
44    /// The [JSON](https://www.json.org/json-en.html) file format.
45    #[derive(Debug, Default, Clone, Copy)]
46    pub struct Json;
47
48    impl<T> Format<T> for Json
49    where
50        T: for<'de> Deserialize<'de>,
51    {
52        type Error = io::Error;
53
54        fn read(&mut self, path: &Path) -> Result<Module<T>, Self::Error> {
55            let mut reader = fs::File::open(path).map(io::BufReader::new)?;
56            serde_json::from_reader(&mut reader).map_err(Into::into)
57        }
58    }
59}
60
61#[cfg(feature = "json")]
62pub use self::json::Json;
63
64///////////////////////////////////////////////////////////////////////////////
65
66#[cfg(feature = "toml")]
67mod toml {
68    use super::*;
69
70    use ::toml::de::Error;
71    use serde::de::Error as _;
72
73    /// The [TOML](https://toml.io/en/) file format.
74    #[derive(Debug, Default, Clone, Copy)]
75    pub struct Toml;
76
77    impl<T> Format<T> for Toml
78    where
79        T: for<'de> Deserialize<'de>,
80    {
81        type Error = Error;
82
83        fn read(&mut self, path: &Path) -> Result<Module<T>, Self::Error> {
84            let bytes = fs::read(path).map_err(Error::custom)?;
85            ::toml::from_slice(&bytes)
86        }
87    }
88}
89
90#[cfg(feature = "toml")]
91pub use self::toml::Toml;