sub_array/
lib.rs

1#![no_std]
2//
3// This crate is entirely safe (tho that's not a guarantee for the future)
4#![forbid(unsafe_code)]
5
6//! Allows to extract a sub-array out of an array
7//!
8//! # Example
9//!
10//! Getting a sub array:
11//!
12//! ```
13//! use sub_array::SubArray;
14//!
15//! let arr: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
16//!
17//! // Get a sub-array starting at offset 1
18//! let sub: &[u8; 3] = arr.sub_array_ref(1);
19//! assert_eq!(sub, &[2, 3, 4]);
20//! ```
21//!
22//! Initializing an `[u8;10]` array with `(u16, u32, u32)`:
23//!
24//! ```
25//! use sub_array::SubArray;
26//!
27//! let foo: u16 = 42;
28//! let bar: u32 = 0x1234;
29//! let baz: u32 = 0x5678;
30//!
31//! let mut arr = [0_u8; 10];
32//! *arr.sub_array_mut::<2>(0) = foo.to_be_bytes();
33//! *arr.sub_array_mut::<4>(2) = bar.to_be_bytes();
34//! *arr.sub_array_mut::<4>(6) = baz.to_be_bytes();
35//!
36//! assert_eq!(
37//!     arr,
38//!     [
39//!         0, 42, // foo
40//!         0x0, 0x0, 0x12, 0x34, // bar
41//!         0x0, 0x0, 0x56, 0x78, // baz
42//!     ]
43//! );
44//! ```
45
46
47/// Array that can be slice into a smaller sub-array
48///
49/// Also see the [crate] level reference.
50pub trait SubArray {
51	/// The value type of this array.
52	///
53	/// This is the `T` in `[T; N]` on regular arrays.
54	type Item;
55
56	/// Get a reference to a sub-array of length `N` starting at `offset`.
57	///
58	/// # Panics
59	/// Panics if `offset + N` exceeds the length of this array.
60	///
61	/// # Example
62	/// ```
63	/// use sub_array::SubArray;
64	///
65	/// let arr: [u8; 5] = [9, 8, 7, 6, 5];
66	///
67	/// // Get a sub-array starting at offset 3
68	/// let sub: &[u8; 2] = arr.sub_array_ref(3);
69	/// assert_eq!(sub, &[6, 5]);
70	/// ```
71	fn sub_array_ref<const N: usize>(&self, offset: usize) -> &[Self::Item; N];
72
73	/// Get a mutable reference to a sub-array of length `N` starting at
74	/// `offset`.
75	///
76	/// # Panics
77	/// Panics if `offset + N` exceeds the length of this array.
78	///
79	/// # Example
80	/// ```
81	/// use sub_array::SubArray;
82	///
83	/// let mut arr: [u8; 5] = [9, 8, 7, 6, 5];
84	///
85	/// // Get a mutable sub-array starting at offset 0
86	/// let sub: &mut [u8; 2] = arr.sub_array_mut(0);
87	/// assert_eq!(sub, &mut [9, 8]);
88	/// ```
89	fn sub_array_mut<const N: usize>(&mut self, offset: usize) -> &mut [Self::Item; N];
90}
91
92/// Implementation on regular arrays
93impl<T, const M: usize> SubArray for [T; M] {
94	type Item = T;
95
96	fn sub_array_ref<const N: usize>(&self, offset: usize) -> &[Self::Item; N] {
97		self[offset..(offset + N)].try_into().unwrap()
98	}
99
100	fn sub_array_mut<const N: usize>(&mut self, offset: usize) -> &mut [Self::Item; N] {
101		(&mut self[offset..(offset + N)]).try_into().unwrap()
102	}
103}
104
105/// Implementation on slices
106impl<T> SubArray for [T] {
107	type Item = T;
108
109	fn sub_array_ref<const N: usize>(&self, offset: usize) -> &[Self::Item; N] {
110		self[offset..(offset + N)].try_into().unwrap()
111	}
112
113	fn sub_array_mut<const N: usize>(&mut self, offset: usize) -> &mut [Self::Item; N] {
114		(&mut self[offset..(offset + N)]).try_into().unwrap()
115	}
116}
117
118/// Implementation on mutable references
119impl<T> SubArray for &mut T
120where
121	T: SubArray,
122{
123	type Item = T::Item;
124
125	fn sub_array_ref<const N: usize>(&self, offset: usize) -> &[Self::Item; N] {
126		(**self).sub_array_ref(offset)
127	}
128
129	fn sub_array_mut<const N: usize>(&mut self, offset: usize) -> &mut [Self::Item; N] {
130		(**self).sub_array_mut(offset)
131	}
132}
133
134
135
136#[cfg(test)]
137mod tests {
138	extern crate alloc;
139
140	use alloc::string::String;
141	use alloc::string::ToString;
142
143	use super::*;
144
145
146	#[test]
147	fn empty_ref() {
148		let arr = [0_u8; 0];
149		assert_eq!(arr.sub_array_ref::<0>(0), &[]);
150	}
151
152	#[test]
153	fn empty_mut() {
154		let mut arr = [0_u8; 0];
155		assert_eq!(arr.sub_array_mut::<0>(0), &mut []);
156	}
157
158	#[test]
159	fn full_ref() {
160		let arr = [1, 2, 3_i8];
161		assert_eq!(arr.sub_array_ref::<3>(0), &[1, 2, 3]);
162	}
163
164	#[test]
165	fn full_mut() {
166		let mut arr = [1, 2, 3_i8];
167		assert_eq!(arr.sub_array_mut::<3>(0), &mut [1, 2, 3]);
168	}
169
170	#[test]
171	fn first_ref() {
172		let arr = [1, 2, 3_u16];
173		assert_eq!(arr.sub_array_ref::<1>(0), &[1]);
174	}
175
176	#[test]
177	fn first_mut() {
178		let mut arr = [1, 2, 3_u16];
179		assert_eq!(arr.sub_array_mut::<1>(0), &mut [1]);
180	}
181
182	#[test]
183	fn middle_ref() {
184		let arr = [1, 2, 3_i16];
185		assert_eq!(arr.sub_array_ref::<1>(1), &[2]);
186	}
187
188	#[test]
189	fn middle_mut() {
190		let mut arr = [1, 2, 3_i16];
191		assert_eq!(arr.sub_array_mut::<1>(1), &mut [2]);
192	}
193
194	#[test]
195	fn last_ref() {
196		let arr = [1, 2, 3_i16];
197		assert_eq!(arr.sub_array_ref::<1>(2), &[3]);
198	}
199
200	#[test]
201	fn last_mut() {
202		let mut arr = [1, 2, 3_i16];
203		assert_eq!(arr.sub_array_mut::<1>(2), &mut [3]);
204	}
205
206	#[derive(Debug, PartialEq, Eq)]
207	struct NotClone(&'static str);
208
209	const NOT_CLONE_ARRAY: [NotClone; 5] = [
210		NotClone("abc"),
211		NotClone("foo"),
212		NotClone("bar"),
213		NotClone("qux"),
214		NotClone("fox"),
215	];
216
217	#[test]
218	fn not_clone_ref() {
219		let exp_arr = [NotClone("foo"), NotClone("bar"), NotClone("qux")];
220		let arr = NOT_CLONE_ARRAY;
221		assert_eq!(arr.sub_array_ref::<3>(1), &exp_arr);
222	}
223
224	#[test]
225	fn not_clone_mut() {
226		let mut exp_arr = [NotClone("foo"), NotClone("bar"), NotClone("qux")];
227		let mut arr = NOT_CLONE_ARRAY;
228		assert_eq!(arr.sub_array_mut::<3>(1), &mut exp_arr);
229	}
230
231	#[test]
232	fn some_strings() {
233		let arr: [String; 5] = NOT_CLONE_ARRAY.map(|s| s.0.to_string());
234		assert_eq!(
235			arr.sub_array_ref::<2>(2),
236			&[String::from("bar"), String::from("qux")]
237		);
238	}
239
240	fn test_by_slice(s: &[u8]) -> &[u8; 3] {
241		s.sub_array_ref(4)
242	}
243
244	#[test]
245	fn slices() {
246		let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9_u8];
247
248		let slice: &[u8] = &arr;
249
250		let arr_ref = test_by_slice(slice);
251
252		assert_eq!(arr_ref, &[5, 6, 7]);
253		assert_eq!(arr_ref, arr.sub_array_ref(4));
254		assert_eq!(arr_ref, &slice[4..7]);
255	}
256}