amebazii/conf/
mod.rs

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use serde::{Deserialize, Serialize};
use std::fs;

pub mod pt;
pub use pt::{PartitionItemCfg, PartitionTableCfg};

pub mod sysctrl;
pub use sysctrl::SystemDataCfg;

#[macro_export]
macro_rules! expect_length {
    ($value:expr, $expected:literal) => {
        if $value.len() != $expected {
            return Err(crate::error::Error::InvalidState(format!(
                "Expected {} characters in hex string, got {}",
                $expected,
                $value.len()
            )));
        }
    };
}

/// A struct representing an array of bytes of a fixed size, which can be either
/// loaded from a file or encoded as a hexadecimal string.
#[derive(Debug)]
pub struct DataArray<const N: usize> {
    /// The byte array that holds the data.
    pub data: [u8; N],

    /// The optional file path from which the data was loaded (if applicable).
    pub path: Option<String>,
}

impl<const N: usize> DataArray<N> {
    /// Creates a new `DataArray` from a string that is either a file path or a hexadecimal string.
    /// If the path exists, it loads the data from the file. Otherwise, it treats the string as a hex string.
    ///
    /// # Parameters
    /// - `data`: A string which could either be a file path or a hex string.
    ///
    /// # Returns
    /// - A `Result` containing the `DataArray` object or an error if the data is invalid.
    pub fn new(data: String) -> Result<Self, crate::error::Error> {
        if let Ok(exists) = fs::exists(&data) {
            if exists {
                // If the path exists, load data from the file
                return DataArray::load(data);
            }
        }
        // Otherwise, treat the data as a hex string
        DataArray::from_string(data)
    }

    /// Creates a `DataArray` from a hexadecimal string.
    ///
    /// # Parameters
    /// - `data`: A hexadecimal string to decode into the byte array.
    ///
    /// # Returns
    /// - A `Result` containing the `DataArray` object or an error if the data length is invalid.
    pub fn from_string(data: String) -> Result<Self, crate::error::Error> {
        let mut obj = DataArray {
            data: [0; N], // Initialize with an array of zeros
            path: None,   // No file path initially
        };

        // Decode the hexadecimal string into a byte array
        let decoded = hex::decode(data)?;

        // Ensure the decoded data matches the expected length
        if decoded.len() != N {
            return Err(crate::error::Error::InvalidState(format!(
                "Expected {} bytes in hex string, got {}",
                N,
                decoded.len()
            )));
        }

        // Copy the decoded bytes into the `data` field
        obj.data.copy_from_slice(&decoded);
        Ok(obj)
    }

    /// Loads the data from a file at the given path.
    ///
    /// # Parameters
    /// - `path`: The file path to load the data from.
    ///
    /// # Returns
    /// - A `Result` containing the `DataArray` object or an error if the data length is invalid.
    pub fn load(path: String) -> Result<Self, crate::error::Error> {
        // Read the file content into a buffer
        let buffer = fs::read(&path)?;
        let mut obj = DataArray {
            data: [0; N],     // Initialize with an array of zeros
            path: Some(path), // Store the file path
        };

        // Ensure the file contains the expected number of bytes
        if buffer.len() != N {
            return Err(crate::error::Error::InvalidState(format!(
                "Expected {} bytes in file, got {}",
                N,
                buffer.len()
            )));
        }

        // Copy the file data into the `data` field
        obj.data.copy_from_slice(&buffer);
        Ok(obj)
    }
}

impl<'de, const N: usize> Deserialize<'de> for DataArray<N> {
    /// Custom deserialization logic for `DataArray`. It reads the input as a string, which can either be a file path or a hex string.
    ///
    /// # Parameters
    /// - `deserializer`: The deserializer used to read the input.
    ///
    /// # Returns
    /// - A `Result` containing the `DataArray` object or an error.
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        // Deserialize the input string (either a path or hex string)
        let s = String::deserialize(deserializer)?;
        // Use `DataArray::new` to create the object from the string
        DataArray::new(s).map_err(serde::de::Error::custom)
    }
}

impl<const N: usize> Serialize for DataArray<N> {
    /// Custom serialization logic for `DataArray`. If the data was loaded from a file, it writes the data to the file and serializes the path.
    /// If the data was provided as a hex string, it serializes the hex string.
    ///
    /// # Parameters
    /// - `serializer`: The serializer used to write the output.
    ///
    /// # Returns
    /// - A `Result` containing the serialized object or an error.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match &self.path {
            Some(path) => {
                // If the data has a path, write the data to the file and serialize the path
                fs::write(path, &self.data).map_err(serde::ser::Error::custom)?;
                serializer.serialize_str(path)
            }
            None => {
                // If there's no path, serialize the data as a hex string
                serializer.serialize_str(&hex::encode(&self.data))
            }
        }
    }
}