1use crate::Dodecet;
6use std::ops::{Deref, DerefMut};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct DodecetArray<const N: usize> {
20 data: [Dodecet; N],
21}
22
23impl<const N: usize> DodecetArray<N> {
24 pub fn new() -> Self
35 where
36 [Dodecet; N]: Sized,
37 {
38 DodecetArray {
39 data: [Dodecet::from_hex(0); N],
40 }
41 }
42
43 pub fn from_slice(values: &[u16]) -> Self
56 where
57 [Dodecet; N]: Sized,
58 {
59 assert_eq!(values.len(), N, "Slice length must match array size");
60
61 let data: [Dodecet; N] = values
62 .iter()
63 .map(|&v| Dodecet::from_hex(v))
64 .collect::<Vec<_>>()
65 .try_into()
66 .unwrap();
67
68 DodecetArray { data }
69 }
70
71 pub fn from_dodecets(data: [Dodecet; N]) -> Self {
85 DodecetArray { data }
86 }
87
88 pub fn as_inner(&self) -> &[Dodecet; N] {
90 &self.data
91 }
92
93 pub fn as_inner_mut(&mut self) -> &mut [Dodecet; N] {
95 &mut self.data
96 }
97
98 pub fn to_hex_string(&self) -> String {
109 self.data
110 .iter()
111 .map(|d| d.to_hex_string())
112 .collect::<Vec<_>>()
113 .join("")
114 }
115
116 pub fn from_hex_str(s: &str) -> crate::Result<Self>
128 where
129 [Dodecet; N]: Sized,
130 {
131 let expected_len = N * 3;
132 if s.len() != expected_len {
133 return Err(crate::DodecetError::InvalidHex);
134 }
135
136 let mut data = [Dodecet::from_hex(0); N];
137
138 for (i, chunk) in s.as_bytes().chunks(3).enumerate() {
139 let chunk_str = std::str::from_utf8(chunk).unwrap();
140 data[i] = Dodecet::from_hex_str(chunk_str)?;
141 }
142
143 Ok(DodecetArray { data })
144 }
145
146 pub fn map<F>(self, f: F) -> Self
158 where
159 F: FnMut(Dodecet) -> Dodecet,
160 {
161 DodecetArray {
162 data: self.data.map(f),
163 }
164 }
165
166 pub fn zip_map<F>(self, other: Self, mut f: F) -> Self
179 where
180 F: FnMut(Dodecet, Dodecet) -> Dodecet,
181 {
182 DodecetArray {
183 data: self
184 .data
185 .into_iter()
186 .zip(other.data)
187 .map(|(a, b)| f(a, b))
188 .collect::<Vec<_>>()
189 .try_into()
190 .unwrap(),
191 }
192 }
193
194 pub fn sum(self) -> Dodecet {
205 self.data.into_iter().fold(Dodecet::from_hex(0), |acc, d| acc + d)
206 }
207
208 pub fn average(&self) -> Dodecet {
220 let sum: u32 = self.data.iter().map(|d| d.value() as u32).sum();
221 Dodecet::from_hex((sum / N as u32) as u16)
222 }
223}
224
225impl<const N: usize> Default for DodecetArray<N>
226where
227 [Dodecet; N]: Sized,
228{
229 fn default() -> Self {
230 Self::new()
231 }
232}
233
234impl<const N: usize> Deref for DodecetArray<N> {
235 type Target = [Dodecet; N];
236
237 fn deref(&self) -> &Self::Target {
238 &self.data
239 }
240}
241
242impl<const N: usize> DerefMut for DodecetArray<N> {
243 fn deref_mut(&mut self) -> &mut Self::Target {
244 &mut self.data
245 }
246}
247
248impl<const N: usize> From<[u16; N]> for DodecetArray<N> {
249 fn from(values: [u16; N]) -> Self {
250 DodecetArray::from_slice(&values)
251 }
252}
253
254impl<const N: usize> From<[Dodecet; N]> for DodecetArray<N> {
255 fn from(data: [Dodecet; N]) -> Self {
256 DodecetArray { data }
257 }
258}
259
260impl<const N: usize> std::fmt::Display for DodecetArray<N> {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262 write!(f, "[")?;
263 for (i, d) in self.data.iter().enumerate() {
264 if i > 0 {
265 write!(f, ", ")?;
266 }
267 write!(f, "{}", d)?;
268 }
269 write!(f, "]")
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn test_creation() {
279 let arr: DodecetArray<3> = DodecetArray::new();
280 assert_eq!(arr.len(), 3);
281 assert!(arr.iter().all(|d| d.is_zero()));
282 }
283
284 #[test]
285 fn test_from_slice() {
286 let arr = DodecetArray::<3>::from_slice(&[0x123, 0x456, 0x789]);
287 assert_eq!(arr[0].value(), 0x123);
288 assert_eq!(arr[1].value(), 0x456);
289 assert_eq!(arr[2].value(), 0x789);
290 }
291
292 #[test]
293 fn test_indexing() {
294 let mut arr = DodecetArray::<3>::from_slice(&[0x123, 0x456, 0x789]);
295 assert_eq!(arr[0].value(), 0x123);
296
297 arr[1] = Dodecet::from_hex(0xABC);
298 assert_eq!(arr[1].value(), 0xABC);
299 }
300
301 #[test]
302 fn test_hex_string() {
303 let arr = DodecetArray::<2>::from_slice(&[0x123, 0x456]);
304 assert_eq!(arr.to_hex_string(), "123456");
305
306 let arr2 = DodecetArray::<2>::from_hex_str("123456").unwrap();
307 assert_eq!(arr2[0].value(), 0x123);
308 assert_eq!(arr2[1].value(), 0x456);
309 }
310
311 #[test]
312 fn test_map() {
313 let arr = DodecetArray::<3>::from_slice(&[0x100, 0x200, 0x300]);
314 let doubled = arr.map(|d| Dodecet::from_hex(d.value() * 2));
315 assert_eq!(doubled[0].value(), 0x200);
316 assert_eq!(doubled[1].value(), 0x400);
317 assert_eq!(doubled[2].value(), 0x600);
318 }
319
320 #[test]
321 fn test_zip_map() {
322 let a = DodecetArray::<3>::from_slice(&[0x100, 0x200, 0x300]);
323 let b = DodecetArray::<3>::from_slice(&[0x001, 0x002, 0x003]);
324 let sum = a.zip_map(b, |x, y| x + y);
325 assert_eq!(sum[0].value(), 0x101);
326 assert_eq!(sum[1].value(), 0x202);
327 assert_eq!(sum[2].value(), 0x303);
328 }
329
330 #[test]
331 fn test_sum() {
332 let arr = DodecetArray::<3>::from_slice(&[0x100, 0x200, 0x300]);
333 assert_eq!(arr.sum().value(), 0x600);
334 }
335
336 #[test]
337 fn test_average() {
338 let arr = DodecetArray::<3>::from_slice(&[0x000, 0x003, 0x006]);
339 assert_eq!(arr.average().value(), 0x003);
340 }
341
342 #[test]
343 fn test_display() {
344 let arr = DodecetArray::<3>::from_slice(&[0x123, 0x456, 0x789]);
345 assert_eq!(format!("{}", arr), "[0x123, 0x456, 0x789]");
346 }
347}