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}