summaryrefslogtreecommitdiff
path: root/systems/asset/src/rw.rs
blob: 784d44d45c93eea4bd4d16257caa8a1622ecc35b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use std::path::PathBuf;

use crate::error::{DataReadError, DataWriteError};

pub trait RWData<DataType> {
    type DataType;

    /// Implement read logic
    /// Given a path, return the specific data
    fn read(path: &PathBuf) -> impl Future<Output = Result<DataType, DataReadError>> + Send + Sync;

    /// Implement write logic
    /// Given data and a path, write to the filesystem
    fn write(
        data: DataType,
        path: &PathBuf,
    ) -> impl Future<Output = Result<(), DataWriteError>> + Send + Sync;

    /// Provide test data
    fn test_data() -> DataType;

    /// Given two sets of data, determine if they are equal
    ///
    /// Add RWDataTest derive to your struct to automatically generate tests
    /// ```ignore
    /// #[derive(RWDataTest)]
    /// struct FooData;
    /// ```
    fn verify_data(data_a: DataType, data_b: DataType) -> bool;
}

#[macro_export]
macro_rules! ensure_eq {
    ($a:expr, $b:expr) => {
        if $a != $b {
            return false;
        }
    };
}

// Test Data
pub struct FooData {
    pub age: i32,
    pub name: String,
}

impl RWData<FooData> for FooData {
    type DataType = FooData;

    async fn read(path: &PathBuf) -> Result<FooData, DataReadError> {
        let content = tokio::fs::read_to_string(path)
            .await
            .map_err(|e| DataReadError::IoError(e))?;
        let parts: Vec<&str> = content.split('=').collect();
        if parts.len() != 2 {
            return Err(DataReadError::ParseError("Invalid format".to_string()));
        }
        let name = parts[0].to_string();
        let age: i32 = parts[1]
            .parse()
            .map_err(|_| DataReadError::ParseError("Invalid age".to_string()))?;
        Ok(FooData { age, name })
    }

    async fn write(data: FooData, path: &PathBuf) -> Result<(), DataWriteError> {
        let content = format!("{}={}", data.name, data.age);
        tokio::fs::write(path, content)
            .await
            .map_err(|e| DataWriteError::IoError(e))?;
        Ok(())
    }

    fn test_data() -> FooData {
        FooData {
            age: 24,
            name: "OneOneFourFiveOneFour".to_string(),
        }
    }

    fn verify_data(data_a: FooData, data_b: FooData) -> bool {
        crate::ensure_eq!(data_a.age, data_b.age);
        crate::ensure_eq!(data_a.name, data_b.name);
        return true;
    }
}