dofus_framework/io/file/
deserializer.rs

1use std::fs;
2
3use serde::Deserialize;
4use thiserror::Error;
5
6use crate::io::file::deserializer::DeserializationError::{EmptyFile, IOError, InvalidInput};
7
8#[derive(Debug, Error)]
9pub enum DeserializationError {
10    #[error("Format {0} yet to be implemented")]
11    NotImplemented(String),
12    #[error("Cannot deserialize data:\n\n{0}\n\nas {1} format")]
13    InvalidInput(String, &'static str),
14    #[error("File {0} is empty")]
15    EmptyFile(String),
16    #[error("Error while trying to read the contents of the file")]
17    IOError {
18        path: String,
19        source: std::io::Error,
20    },
21}
22
23pub trait Deserializer {
24    fn deserialize<E>(&self, data: &str) -> Result<E, DeserializationError>
25    where
26        E: for<'a> Deserialize<'a>;
27}
28
29#[derive(Debug)]
30pub enum Format {
31    Json,
32    Yaml,
33    Xml,
34    Toml,
35}
36
37impl Deserializer for Format {
38    fn deserialize<E>(&self, data: &str) -> Result<E, DeserializationError>
39    where
40        E: for<'a> Deserialize<'a>,
41    {
42        match self {
43            Format::Json => deserialize_with_context(|x| serde_json::from_str(x), data, "JSON"),
44            Format::Yaml => deserialize_with_context(serde_yaml::from_str, data, "YAML"),
45            Format::Xml => deserialize_with_context(serde_xml_rs::from_str, data, "XML"),
46            Format::Toml => deserialize_with_context(|x| toml::from_str(x), data, "TOML"),
47            //_ => Err(NotImplemented(format!("{:?}", self))),
48        }
49    }
50}
51
52fn deserialize_with_context<T, E>(
53    result: fn(&str) -> Result<T, E>,
54    data: &str,
55    format: &'static str,
56) -> Result<T, DeserializationError> {
57    result(data).map_err(|_| InvalidInput(data.to_string(), format))
58}
59
60pub fn deserialize_from_file<E, T>(
61    file_path: &str,
62    deserializer: T,
63) -> Result<E, DeserializationError>
64where
65    E: for<'a> Deserialize<'a>,
66    T: Deserializer,
67{
68    fs::read_to_string(file_path)
69        .map_err(|err| IOError {
70            path: file_path.to_string(),
71            source: err,
72        })
73        .map(|file_data| {
74            if file_data.is_empty() {
75                return Err(EmptyFile(file_path.to_string()));
76            }
77            deserializer.deserialize(file_data.as_str())
78        })?
79}