amebazii/conf/
mod.rs

1use serde::{Deserialize, Serialize};
2use std::fs;
3
4pub mod pt;
5pub use pt::{PartitionItemCfg, PartitionTableCfg};
6
7pub mod sysctrl;
8pub use sysctrl::SystemDataCfg;
9
10#[macro_export]
11macro_rules! expect_length {
12    ($value:expr, $expected:literal) => {
13        if $value.len() != $expected {
14            return Err(crate::error::Error::InvalidState(format!(
15                "Expected {} characters in hex string, got {}",
16                $expected,
17                $value.len()
18            )));
19        }
20    };
21}
22
23/// A struct representing an array of bytes of a fixed size, which can be either
24/// loaded from a file or encoded as a hexadecimal string.
25#[derive(Debug)]
26pub struct DataArray<const N: usize> {
27    /// The byte array that holds the data.
28    pub data: [u8; N],
29
30    /// The optional file path from which the data was loaded (if applicable).
31    pub path: Option<String>,
32}
33
34impl<const N: usize> DataArray<N> {
35    /// Creates a new `DataArray` from a string that is either a file path or a hexadecimal string.
36    /// If the path exists, it loads the data from the file. Otherwise, it treats the string as a hex string.
37    ///
38    /// # Parameters
39    /// - `data`: A string which could either be a file path or a hex string.
40    ///
41    /// # Returns
42    /// - A `Result` containing the `DataArray` object or an error if the data is invalid.
43    pub fn new(data: String) -> Result<Self, crate::error::Error> {
44        if let Ok(exists) = fs::exists(&data) {
45            if exists {
46                // If the path exists, load data from the file
47                return DataArray::load(data);
48            }
49        }
50        // Otherwise, treat the data as a hex string
51        DataArray::from_string(data)
52    }
53
54    /// Creates a `DataArray` from a hexadecimal string.
55    ///
56    /// # Parameters
57    /// - `data`: A hexadecimal string to decode into the byte array.
58    ///
59    /// # Returns
60    /// - A `Result` containing the `DataArray` object or an error if the data length is invalid.
61    pub fn from_string(data: String) -> Result<Self, crate::error::Error> {
62        let mut obj = DataArray {
63            data: [0; N], // Initialize with an array of zeros
64            path: None,   // No file path initially
65        };
66
67        // Decode the hexadecimal string into a byte array
68        let decoded = hex::decode(data)?;
69
70        // Ensure the decoded data matches the expected length
71        if decoded.len() != N {
72            return Err(crate::error::Error::InvalidState(format!(
73                "Expected {} bytes in hex string, got {}",
74                N,
75                decoded.len()
76            )));
77        }
78
79        // Copy the decoded bytes into the `data` field
80        obj.data.copy_from_slice(&decoded);
81        Ok(obj)
82    }
83
84    /// Loads the data from a file at the given path.
85    ///
86    /// # Parameters
87    /// - `path`: The file path to load the data from.
88    ///
89    /// # Returns
90    /// - A `Result` containing the `DataArray` object or an error if the data length is invalid.
91    pub fn load(path: String) -> Result<Self, crate::error::Error> {
92        // Read the file content into a buffer
93        let buffer = fs::read(&path)?;
94        let mut obj = DataArray {
95            data: [0; N],     // Initialize with an array of zeros
96            path: Some(path), // Store the file path
97        };
98
99        // Ensure the file contains the expected number of bytes
100        if buffer.len() != N {
101            return Err(crate::error::Error::InvalidState(format!(
102                "Expected {} bytes in file, got {}",
103                N,
104                buffer.len()
105            )));
106        }
107
108        // Copy the file data into the `data` field
109        obj.data.copy_from_slice(&buffer);
110        Ok(obj)
111    }
112}
113
114impl<'de, const N: usize> Deserialize<'de> for DataArray<N> {
115    /// Custom deserialization logic for `DataArray`. It reads the input as a string, which can either be a file path or a hex string.
116    ///
117    /// # Parameters
118    /// - `deserializer`: The deserializer used to read the input.
119    ///
120    /// # Returns
121    /// - A `Result` containing the `DataArray` object or an error.
122    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
123    where
124        D: serde::Deserializer<'de>,
125    {
126        // Deserialize the input string (either a path or hex string)
127        let s = String::deserialize(deserializer)?;
128        // Use `DataArray::new` to create the object from the string
129        DataArray::new(s).map_err(serde::de::Error::custom)
130    }
131}
132
133impl<const N: usize> Serialize for DataArray<N> {
134    /// Custom serialization logic for `DataArray`. If the data was loaded from a file, it writes the data to the file and serializes the path.
135    /// If the data was provided as a hex string, it serializes the hex string.
136    ///
137    /// # Parameters
138    /// - `serializer`: The serializer used to write the output.
139    ///
140    /// # Returns
141    /// - A `Result` containing the serialized object or an error.
142    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
143    where
144        S: serde::Serializer,
145    {
146        match &self.path {
147            Some(path) => {
148                // If the data has a path, write the data to the file and serialize the path
149                fs::write(path, &self.data).map_err(serde::ser::Error::custom)?;
150                serializer.serialize_str(path)
151            }
152            None => {
153                // If there's no path, serialize the data as a hex string
154                serializer.serialize_str(&hex::encode(&self.data))
155            }
156        }
157    }
158}