1#![no_std]
2#![doc = include_str!("../README.md")]
3
4use core::ops::Deref;
5use core::ops::DerefMut;
6
7#[cfg(feature = "serde")]
9mod serde_impl;
10
11#[cfg(feature = "defmt")]
13mod defmt_impl;
14
15#[repr(C)]
17#[derive(Debug, Clone, Copy)]
18#[cfg_attr(
19 feature = "postcard_max_size",
20 derive(postcard::experimental::max_size::MaxSize)
21)]
22pub struct ArrayPlusExtra<T, const N: usize, const EXTRA: usize> {
23 data: [T; N],
24 extra: [T; EXTRA],
25}
26
27impl<T, const N: usize, const EXTRA: usize> ArrayPlusExtra<T, N, EXTRA>
28where
29 T: Copy,
30{
31 #[inline]
33 pub const fn new(value: T) -> Self {
34 Self {
35 data: [value; N],
36 extra: [value; EXTRA],
37 }
38 }
39}
40
41impl<T, const N: usize, const EXTRA: usize> ArrayPlusExtra<T, N, EXTRA> {
42 #[inline]
44 pub const fn as_array<const M: usize>(&self) -> &[T; M] {
45 const { assert!(M == N + EXTRA) }
46 unsafe { core::mem::transmute(self) }
49 }
50
51 #[inline]
53 pub const fn into_array<const M: usize>(self) -> [T; M] {
54 const { assert!(M == N + EXTRA) }
55 let this = unsafe { core::ptr::read(&self as *const Self as *const [T; M]) };
58 core::mem::forget(self);
59 this
60 }
61
62 #[inline]
65 pub const fn as_slice(&self) -> &[T] {
66 unsafe { core::slice::from_raw_parts(self as *const _ as *const T, N + EXTRA) }
69 }
70
71 #[inline]
74 pub const fn as_mut_slice(&mut self) -> &mut [T] {
75 unsafe { core::slice::from_raw_parts_mut(self as *mut _ as *mut T, N + EXTRA) }
78 }
79}
80
81impl<T, const N: usize, const EXTRA: usize> Deref for ArrayPlusExtra<T, N, EXTRA> {
82 type Target = [T];
83
84 #[inline(always)]
85 fn deref(&self) -> &Self::Target {
86 self.as_slice()
87 }
88}
89
90impl<T, const N: usize, const EXTRA: usize> DerefMut for ArrayPlusExtra<T, N, EXTRA> {
91 #[inline(always)]
92 fn deref_mut(&mut self) -> &mut Self::Target {
93 self.as_mut_slice()
94 }
95}
96
97impl<T, const N: usize, const EXTRA: usize> PartialEq for ArrayPlusExtra<T, N, EXTRA>
99where
100 T: PartialEq,
101{
102 #[inline]
103 fn eq(&self, other: &Self) -> bool {
104 self[..] == other[..]
105 }
106}
107
108impl<T, const N: usize, const EXTRA: usize> Eq for ArrayPlusExtra<T, N, EXTRA> where T: Eq {}
110
111impl<T, const N: usize, const EXTRA: usize> core::hash::Hash for ArrayPlusExtra<T, N, EXTRA>
113where
114 T: core::hash::Hash,
115{
116 #[inline]
117 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
118 self[..].hash(state);
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 extern crate std;
128 use std::format;
129
130 #[test]
132 fn test_extra_zero_with_n_zero() {
133 let arr: ArrayPlusExtra<i32, 0, 0> = ArrayPlusExtra::new(42);
134 assert_eq!(arr.len(), 0);
136 }
137
138 #[test]
139 fn test_extra_zero_with_n_five() {
140 let mut arr: ArrayPlusExtra<i32, 5, 0> = ArrayPlusExtra::new(42);
141 assert_eq!(arr.len(), 5);
143 for i in 0..5 {
145 assert_eq!(arr[i], 42);
146 }
147 arr[4] = 100;
149 assert_eq!(arr[4], 100);
150 }
151
152 #[test]
154 fn test_extra_one_with_n_zero() {
155 let mut arr: ArrayPlusExtra<i32, 0, 1> = ArrayPlusExtra::new(99);
156 assert_eq!(arr.len(), 1);
158 assert_eq!(arr[0], 99);
159 arr[0] = 100;
160 assert_eq!(arr[0], 100);
161 }
162
163 #[test]
164 fn test_extra_one_with_n_five() {
165 let arr: ArrayPlusExtra<i32, 5, 1> = ArrayPlusExtra::new(42);
166 assert_eq!(arr.len(), 6);
168 for i in 0..6 {
170 assert_eq!(arr[i], 42);
171 }
172 }
173
174 #[test]
175 fn test_extra_one_deref_mut() {
176 let mut arr: ArrayPlusExtra<i32, 4, 1> = ArrayPlusExtra::new(0);
177 assert_eq!(arr.len(), 5);
179 for i in 0..5 {
181 arr[i] = i as i32;
182 }
183 for i in 0..5 {
185 assert_eq!(arr[i], i as i32);
186 }
187 }
188
189 #[test]
191 fn test_extra_three_with_n_two() {
192 let mut arr: ArrayPlusExtra<u32, 2, 3> = ArrayPlusExtra::new(7);
193 assert_eq!(arr.len(), 5);
195 for i in 0..5 {
197 assert_eq!(arr[i], 7);
198 }
199 arr[0] = 10; arr[1] = 20; arr[2] = 30; arr[3] = 40; arr[4] = 50; assert_eq!(arr[0], 10);
207 assert_eq!(arr[1], 20);
208 assert_eq!(arr[2], 30);
209 assert_eq!(arr[3], 40);
210 assert_eq!(arr[4], 50);
211 }
212
213 #[test]
214 fn test_extra_ten_with_n_ten() {
215 let mut arr: ArrayPlusExtra<u64, 10, 10> = ArrayPlusExtra::new(0);
216 assert_eq!(arr.len(), 20);
218 arr[0] = 1;
220 arr[9] = 9; arr[10] = 10; arr[19] = 19; assert_eq!(arr[0], 1);
225 assert_eq!(arr[9], 9);
226 assert_eq!(arr[10], 10);
227 assert_eq!(arr[19], 19);
228 }
229
230 #[test]
231 fn test_extra_fifty_large() {
232 let mut arr: ArrayPlusExtra<u8, 50, 50> = ArrayPlusExtra::new(1);
233 assert_eq!(arr.len(), 100);
235 assert_eq!(arr[0], 1);
237 assert_eq!(arr[25], 1); assert_eq!(arr[49], 1); assert_eq!(arr[50], 1); assert_eq!(arr[75], 1); assert_eq!(arr[99], 1); arr[99] = 255;
244 assert_eq!(arr[99], 255);
245 }
246
247 #[test]
249 fn test_different_types_various_extra() {
250 let arr_u8: ArrayPlusExtra<u8, 2, 2> = ArrayPlusExtra::new(255);
252 assert_eq!(arr_u8.len(), 4);
253 assert_eq!(arr_u8[3], 255);
254
255 let arr_u64: ArrayPlusExtra<u64, 2, 3> = ArrayPlusExtra::new(u64::MAX);
257 assert_eq!(arr_u64.len(), 5);
258 assert_eq!(arr_u64[4], u64::MAX);
259
260 let mut arr_f64: ArrayPlusExtra<f64, 1, 5> = ArrayPlusExtra::new(1.5);
262 assert_eq!(arr_f64.len(), 6);
263 arr_f64[5] = 2.5;
264 assert_eq!(arr_f64[5], 2.5);
265 }
266
267 #[test]
268 fn test_slice_iteration_various_extra() {
269 let mut arr: ArrayPlusExtra<i32, 3, 1> = ArrayPlusExtra::new(0);
271 assert_eq!(arr.len(), 4);
272 arr[0] = 10;
273 arr[1] = 20;
274 arr[2] = 30;
275 arr[3] = 40;
276
277 let sum: i32 = arr.iter().sum();
279 assert_eq!(sum, 100);
280
281 for elem in arr.iter_mut() {
283 *elem += 1;
284 }
285 assert_eq!(arr[0], 11);
286 assert_eq!(arr[3], 41);
287
288 let mut arr2: ArrayPlusExtra<i32, 2, 5> = ArrayPlusExtra::new(1);
290 assert_eq!(arr2.len(), 7);
291 let sum2: i32 = arr2.iter().sum();
292 assert_eq!(sum2, 7);
293
294 for elem in arr2.iter_mut() {
295 *elem *= 2;
296 }
297 for i in 0..7 {
298 assert_eq!(arr2[i], 2);
299 }
300 }
301
302 #[test]
304 fn test_debug() {
305 let arr: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
306 let debug_str = format!("{:?}", arr);
307 assert!(debug_str.contains("42"));
309 }
310
311 #[test]
312 #[allow(clippy::clone_on_copy)]
313 fn test_clone() {
314 let arr: ArrayPlusExtra<i32, 2, 2> = ArrayPlusExtra::new(5);
315 let cloned = arr.clone();
316 assert_eq!(arr[0], cloned[0]);
317 assert_eq!(arr.len(), cloned.len());
318 for i in 0..4 {
319 assert_eq!(arr[i], cloned[i]);
320 }
321 }
322
323 #[test]
324 fn test_partial_eq() {
325 let arr1: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
326 let arr2: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
327 let arr3: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(99);
328
329 assert_eq!(arr1, arr2);
331 assert_ne!(arr1, arr3);
333 }
334
335 #[test]
336 fn test_eq_reflexive() {
337 let arr: ArrayPlusExtra<i32, 3, 2> = ArrayPlusExtra::new(7);
338 assert_eq!(arr, arr);
339 }
340
341 #[test]
342 fn test_hash() {
343 use core::hash::{Hash, Hasher};
344 use std::collections::hash_map::DefaultHasher;
345
346 let arr1: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
347 let arr2: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
348 let arr3: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(99);
349
350 let mut hasher1 = DefaultHasher::new();
351 let mut hasher2 = DefaultHasher::new();
352 let mut hasher3 = DefaultHasher::new();
353
354 arr1.hash(&mut hasher1);
355 arr2.hash(&mut hasher2);
356 arr3.hash(&mut hasher3);
357
358 assert_eq!(hasher1.finish(), hasher2.finish());
360 assert_ne!(hasher1.finish(), hasher3.finish());
362 }
363
364 #[test]
365 fn test_copy() {
366 let arr: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(10);
367 let copied = arr; assert_eq!(arr[0], 10);
370 assert_eq!(copied[0], 10);
371 }
372
373 #[test]
375 fn test_as_slice_const_fn() {
376 const ARR: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
377 const SLICE: &[i32] = ARR.as_slice();
378 const LEN: usize = SLICE.len();
379
380 assert_eq!(LEN, 3);
381 assert_eq!(SLICE[0], 42);
382 assert_eq!(SLICE[1], 42);
383 assert_eq!(SLICE[2], 42);
384 }
385
386 #[test]
387 fn test_const_creation_and_slicing() {
388 const ARR: ArrayPlusExtra<u8, 5, 3> = ArrayPlusExtra::new(255);
389 const SLICE: &[u8] = ARR.as_slice();
390 const FIRST: u8 = SLICE[0];
391 const LAST_INDEX: usize = SLICE.len() - 1;
392
393 assert_eq!(FIRST, 255);
394 assert_eq!(SLICE.len(), 8);
395 assert_eq!(SLICE[LAST_INDEX], 255);
396 }
397
398 #[test]
399 fn test_as_slice_method() {
400 let arr: ArrayPlusExtra<i32, 3, 2> = ArrayPlusExtra::new(7);
401 let slice = arr.as_slice();
402
403 assert_eq!(slice.len(), 5);
404 for &val in slice {
405 assert_eq!(val, 7);
406 }
407 }
408
409 #[test]
410 fn test_as_mut_slice_method() {
411 let mut arr: ArrayPlusExtra<i32, 2, 2> = ArrayPlusExtra::new(0);
412 let slice = arr.as_mut_slice();
413
414 slice[0] = 10;
415 slice[1] = 20;
416 slice[2] = 30;
417 slice[3] = 40;
418
419 assert_eq!(arr[0], 10);
420 assert_eq!(arr[1], 20);
421 assert_eq!(arr[2], 30);
422 assert_eq!(arr[3], 40);
423 }
424
425 #[test]
426 fn test_const_zero_sized() {
427 const ARR: ArrayPlusExtra<i32, 0, 0> = ArrayPlusExtra::new(42);
428 const SLICE: &[i32] = ARR.as_slice();
429 const LEN: usize = SLICE.len();
430
431 assert_eq!(LEN, 0);
432 }
433
434 #[test]
435 fn test_as_array() {
436 let mut arr: ArrayPlusExtra<i32, 2, 3> = ArrayPlusExtra::new(0);
437 arr[0] = 10;
438 arr[4] = 50;
439
440 let array_ref: &[i32; 5] = arr.as_array();
441 assert_eq!(array_ref[0], 10);
442 assert_eq!(array_ref[4], 50);
443 }
444
445 #[test]
446 fn test_into_array() {
447 let mut arr: ArrayPlusExtra<i32, 2, 3> = ArrayPlusExtra::new(0);
448 arr[0] = 10;
449 arr[4] = 50;
450
451 let array: [i32; 5] = arr.into_array();
452 assert_eq!(array[0], 10);
453 assert_eq!(array[4], 50);
454 }
455}