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 as_array_mut<const M: usize>(&mut self) -> &mut [T; M] {
54 const { assert!(M == N + EXTRA) }
55 unsafe { core::mem::transmute(self) }
58 }
59
60 #[inline]
62 pub const fn into_array<const M: usize>(self) -> [T; M] {
63 const { assert!(M == N + EXTRA) }
64 let this = unsafe { core::ptr::read(&self as *const Self as *const [T; M]) };
67 core::mem::forget(self);
68 this
69 }
70
71 #[inline]
74 pub const fn as_slice(&self) -> &[T] {
75 unsafe { core::slice::from_raw_parts(self as *const _ as *const T, N + EXTRA) }
78 }
79
80 #[inline]
83 pub const fn as_mut_slice(&mut self) -> &mut [T] {
84 unsafe { core::slice::from_raw_parts_mut(self as *mut _ as *mut T, N + EXTRA) }
87 }
88}
89
90impl<T, const N: usize, const EXTRA: usize> Deref for ArrayPlusExtra<T, N, EXTRA> {
91 type Target = [T];
92
93 #[inline(always)]
94 fn deref(&self) -> &Self::Target {
95 self.as_slice()
96 }
97}
98
99impl<T, const N: usize, const EXTRA: usize> DerefMut for ArrayPlusExtra<T, N, EXTRA> {
100 #[inline(always)]
101 fn deref_mut(&mut self) -> &mut Self::Target {
102 self.as_mut_slice()
103 }
104}
105
106impl<T, const N: usize, const EXTRA: usize> PartialEq for ArrayPlusExtra<T, N, EXTRA>
108where
109 T: PartialEq,
110{
111 #[inline]
112 fn eq(&self, other: &Self) -> bool {
113 self[..] == other[..]
114 }
115}
116
117impl<T, const N: usize, const EXTRA: usize> Eq for ArrayPlusExtra<T, N, EXTRA> where T: Eq {}
119
120impl<T, const N: usize, const EXTRA: usize> core::hash::Hash for ArrayPlusExtra<T, N, EXTRA>
122where
123 T: core::hash::Hash,
124{
125 #[inline]
126 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
127 self[..].hash(state);
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 extern crate std;
137 use std::format;
138
139 #[test]
141 fn test_extra_zero_with_n_zero() {
142 let arr: ArrayPlusExtra<i32, 0, 0> = ArrayPlusExtra::new(42);
143 assert_eq!(arr.len(), 0);
145 }
146
147 #[test]
148 fn test_extra_zero_with_n_five() {
149 let mut arr: ArrayPlusExtra<i32, 5, 0> = ArrayPlusExtra::new(42);
150 assert_eq!(arr.len(), 5);
152 for i in 0..5 {
154 assert_eq!(arr[i], 42);
155 }
156 arr[4] = 100;
158 assert_eq!(arr[4], 100);
159 }
160
161 #[test]
163 fn test_extra_one_with_n_zero() {
164 let mut arr: ArrayPlusExtra<i32, 0, 1> = ArrayPlusExtra::new(99);
165 assert_eq!(arr.len(), 1);
167 assert_eq!(arr[0], 99);
168 arr[0] = 100;
169 assert_eq!(arr[0], 100);
170 }
171
172 #[test]
173 fn test_extra_one_with_n_five() {
174 let arr: ArrayPlusExtra<i32, 5, 1> = ArrayPlusExtra::new(42);
175 assert_eq!(arr.len(), 6);
177 for i in 0..6 {
179 assert_eq!(arr[i], 42);
180 }
181 }
182
183 #[test]
184 fn test_extra_one_deref_mut() {
185 let mut arr: ArrayPlusExtra<i32, 4, 1> = ArrayPlusExtra::new(0);
186 assert_eq!(arr.len(), 5);
188 for i in 0..5 {
190 arr[i] = i as i32;
191 }
192 for i in 0..5 {
194 assert_eq!(arr[i], i as i32);
195 }
196 }
197
198 #[test]
200 fn test_extra_three_with_n_two() {
201 let mut arr: ArrayPlusExtra<u32, 2, 3> = ArrayPlusExtra::new(7);
202 assert_eq!(arr.len(), 5);
204 for i in 0..5 {
206 assert_eq!(arr[i], 7);
207 }
208 arr[0] = 10; arr[1] = 20; arr[2] = 30; arr[3] = 40; arr[4] = 50; assert_eq!(arr[0], 10);
216 assert_eq!(arr[1], 20);
217 assert_eq!(arr[2], 30);
218 assert_eq!(arr[3], 40);
219 assert_eq!(arr[4], 50);
220 }
221
222 #[test]
223 fn test_extra_ten_with_n_ten() {
224 let mut arr: ArrayPlusExtra<u64, 10, 10> = ArrayPlusExtra::new(0);
225 assert_eq!(arr.len(), 20);
227 arr[0] = 1;
229 arr[9] = 9; arr[10] = 10; arr[19] = 19; assert_eq!(arr[0], 1);
234 assert_eq!(arr[9], 9);
235 assert_eq!(arr[10], 10);
236 assert_eq!(arr[19], 19);
237 }
238
239 #[test]
240 fn test_extra_fifty_large() {
241 let mut arr: ArrayPlusExtra<u8, 50, 50> = ArrayPlusExtra::new(1);
242 assert_eq!(arr.len(), 100);
244 assert_eq!(arr[0], 1);
246 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;
253 assert_eq!(arr[99], 255);
254 }
255
256 #[test]
258 fn test_different_types_various_extra() {
259 let arr_u8: ArrayPlusExtra<u8, 2, 2> = ArrayPlusExtra::new(255);
261 assert_eq!(arr_u8.len(), 4);
262 assert_eq!(arr_u8[3], 255);
263
264 let arr_u64: ArrayPlusExtra<u64, 2, 3> = ArrayPlusExtra::new(u64::MAX);
266 assert_eq!(arr_u64.len(), 5);
267 assert_eq!(arr_u64[4], u64::MAX);
268
269 let mut arr_f64: ArrayPlusExtra<f64, 1, 5> = ArrayPlusExtra::new(1.5);
271 assert_eq!(arr_f64.len(), 6);
272 arr_f64[5] = 2.5;
273 assert_eq!(arr_f64[5], 2.5);
274 }
275
276 #[test]
277 fn test_slice_iteration_various_extra() {
278 let mut arr: ArrayPlusExtra<i32, 3, 1> = ArrayPlusExtra::new(0);
280 assert_eq!(arr.len(), 4);
281 arr[0] = 10;
282 arr[1] = 20;
283 arr[2] = 30;
284 arr[3] = 40;
285
286 let sum: i32 = arr.iter().sum();
288 assert_eq!(sum, 100);
289
290 for elem in arr.iter_mut() {
292 *elem += 1;
293 }
294 assert_eq!(arr[0], 11);
295 assert_eq!(arr[3], 41);
296
297 let mut arr2: ArrayPlusExtra<i32, 2, 5> = ArrayPlusExtra::new(1);
299 assert_eq!(arr2.len(), 7);
300 let sum2: i32 = arr2.iter().sum();
301 assert_eq!(sum2, 7);
302
303 for elem in arr2.iter_mut() {
304 *elem *= 2;
305 }
306 for i in 0..7 {
307 assert_eq!(arr2[i], 2);
308 }
309 }
310
311 #[test]
313 fn test_debug() {
314 let arr: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
315 let debug_str = format!("{:?}", arr);
316 assert!(debug_str.contains("42"));
318 }
319
320 #[test]
321 #[allow(clippy::clone_on_copy)]
322 fn test_clone() {
323 let arr: ArrayPlusExtra<i32, 2, 2> = ArrayPlusExtra::new(5);
324 let cloned = arr.clone();
325 assert_eq!(arr[0], cloned[0]);
326 assert_eq!(arr.len(), cloned.len());
327 for i in 0..4 {
328 assert_eq!(arr[i], cloned[i]);
329 }
330 }
331
332 #[test]
333 fn test_partial_eq() {
334 let arr1: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
335 let arr2: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
336 let arr3: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(99);
337
338 assert_eq!(arr1, arr2);
340 assert_ne!(arr1, arr3);
342 }
343
344 #[test]
345 fn test_eq_reflexive() {
346 let arr: ArrayPlusExtra<i32, 3, 2> = ArrayPlusExtra::new(7);
347 assert_eq!(arr, arr);
348 }
349
350 #[test]
351 fn test_hash() {
352 use core::hash::{Hash, Hasher};
353 use std::collections::hash_map::DefaultHasher;
354
355 let arr1: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
356 let arr2: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
357 let arr3: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(99);
358
359 let mut hasher1 = DefaultHasher::new();
360 let mut hasher2 = DefaultHasher::new();
361 let mut hasher3 = DefaultHasher::new();
362
363 arr1.hash(&mut hasher1);
364 arr2.hash(&mut hasher2);
365 arr3.hash(&mut hasher3);
366
367 assert_eq!(hasher1.finish(), hasher2.finish());
369 assert_ne!(hasher1.finish(), hasher3.finish());
371 }
372
373 #[test]
374 fn test_copy() {
375 let arr: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(10);
376 let copied = arr; assert_eq!(arr[0], 10);
379 assert_eq!(copied[0], 10);
380 }
381
382 #[test]
384 fn test_as_slice_const_fn() {
385 const ARR: ArrayPlusExtra<i32, 2, 1> = ArrayPlusExtra::new(42);
386 const SLICE: &[i32] = ARR.as_slice();
387 const LEN: usize = SLICE.len();
388
389 assert_eq!(LEN, 3);
390 assert_eq!(SLICE[0], 42);
391 assert_eq!(SLICE[1], 42);
392 assert_eq!(SLICE[2], 42);
393 }
394
395 #[test]
396 fn test_const_creation_and_slicing() {
397 const ARR: ArrayPlusExtra<u8, 5, 3> = ArrayPlusExtra::new(255);
398 const SLICE: &[u8] = ARR.as_slice();
399 const FIRST: u8 = SLICE[0];
400 const LAST_INDEX: usize = SLICE.len() - 1;
401
402 assert_eq!(FIRST, 255);
403 assert_eq!(SLICE.len(), 8);
404 assert_eq!(SLICE[LAST_INDEX], 255);
405 }
406
407 #[test]
408 fn test_as_slice_method() {
409 let arr: ArrayPlusExtra<i32, 3, 2> = ArrayPlusExtra::new(7);
410 let slice = arr.as_slice();
411
412 assert_eq!(slice.len(), 5);
413 for &val in slice {
414 assert_eq!(val, 7);
415 }
416 }
417
418 #[test]
419 fn test_as_mut_slice_method() {
420 let mut arr: ArrayPlusExtra<i32, 2, 2> = ArrayPlusExtra::new(0);
421 let slice = arr.as_mut_slice();
422
423 slice[0] = 10;
424 slice[1] = 20;
425 slice[2] = 30;
426 slice[3] = 40;
427
428 assert_eq!(arr[0], 10);
429 assert_eq!(arr[1], 20);
430 assert_eq!(arr[2], 30);
431 assert_eq!(arr[3], 40);
432 }
433
434 #[test]
435 fn test_const_zero_sized() {
436 const ARR: ArrayPlusExtra<i32, 0, 0> = ArrayPlusExtra::new(42);
437 const SLICE: &[i32] = ARR.as_slice();
438 const LEN: usize = SLICE.len();
439
440 assert_eq!(LEN, 0);
441 }
442
443 #[test]
444 fn test_as_array() {
445 let mut arr: ArrayPlusExtra<i32, 2, 3> = ArrayPlusExtra::new(0);
446 arr[0] = 10;
447 arr[4] = 50;
448
449 let array_ref: &[i32; 5] = arr.as_array();
450 assert_eq!(array_ref[0], 10);
451 assert_eq!(array_ref[4], 50);
452 }
453
454 #[test]
455 fn test_as_array_mut() {
456 let mut arr: ArrayPlusExtra<i32, 2, 3> = ArrayPlusExtra::new(0);
457 arr[0] = 20;
458 arr[4] = 50;
459
460 let array_ref: &mut [i32; 5] = arr.as_array_mut();
461 assert_eq!(array_ref[0], 20);
462 assert_eq!(array_ref[4], 50);
463 array_ref[0] = 30;
464 array_ref[4] = 10;
465 assert_eq!(array_ref[0], 30);
466 assert_eq!(array_ref[4], 10);
467 }
468
469 #[test]
470 fn test_into_array() {
471 let mut arr: ArrayPlusExtra<i32, 2, 3> = ArrayPlusExtra::new(0);
472 arr[0] = 10;
473 arr[4] = 50;
474
475 let array: [i32; 5] = arr.into_array();
476 assert_eq!(array[0], 10);
477 assert_eq!(array[4], 50);
478 }
479}