cooplan_config_reader/
reader.rs

1use std::io::{Error, ErrorKind};
2use serde::Deserialize;
3use serde_json::Value;
4
5pub async fn try_read<T: for<'de> Deserialize<'de>>(file_path: &str) -> Result<T, Error> {
6    let value = match tokio::fs::read_to_string(file_path).await {
7        Ok(file_content) => try_deserialize(file_content)?,
8        Err(error) => {
9            return Err(error);
10        }
11    };
12
13    Ok(value)
14}
15
16fn try_deserialize<T: for<'de> Deserialize<'de>>(file_content: String) -> Result<T, Error> {
17    match serde_json::from_str::<Value>(&file_content) {
18        Ok(value) => match serde_json::from_value::<T>(value) {
19            Ok(value) => Ok(value),
20            Err(error) => {
21                return Err(Error::new(
22                    ErrorKind::InvalidData,
23                    format!("failed to deserialize file's content: {}", error),
24                ));
25            }
26        },
27        Err(error) => {
28            Err(Error::new(
29                ErrorKind::InvalidData,
30                format!("failed to deserialize file's content: {}", error),
31            ))
32        }
33    }
34}
35
36#[cfg(test)]
37#[test]
38pub fn converts_string_into_expected_value() {
39    #[derive(Deserialize)]
40    struct Example {
41        a: u32,
42        b: String,
43        c: bool,
44    }
45
46    let first_json = r#"{"a": 1, "b": "2", "c": true}"#;
47    let second_json = r#"{"a": 3, "b": "4", "c": false}"#;
48
49    let first = try_deserialize::<Example>(first_json.to_string()).unwrap();
50    let second = try_deserialize::<Example>(second_json.to_string()).unwrap();
51
52    assert_eq!(first.a, 1);
53    assert_eq!(first.b, "2");
54    assert_eq!(first.c, true);
55
56    assert_eq!(second.a, 3);
57    assert_eq!(second.b, "4");
58    assert_eq!(second.c, false);
59}