split_array/
lib.rs

1//! Split array references in two with compile-time size validation.
2//!
3//! # Examples
4//!
5//! The sizes of the two halves can usually be inferred:
6//! ```rust
7//! use split_array::SplitArray;
8//!
9//! let mut array: [usize; 5] = [0, 1, 2, 3, 4];
10//! let (left, right) = array.split_arr_mut();
11//! *left = [10, 11, 12];
12//! *right = [23, 24];
13//! assert_eq!([10, 11, 12, 23, 24], array);
14//! ```
15//!
16//! They can be annotated explicitly as well:
17//! ```rust
18//! use split_array::SplitArray;
19//!
20//! let array: [usize; 5] = [0, 1, 2, 3, 4];
21//! let (left, right) = array.split_arr::<2>();
22//! assert_eq!([0, 1, 2], *left);
23//! assert_eq!([3, 4], *right);
24//! ```
25//!
26//! The annotated size is validated at compile-time. This won't compile:
27//! ```rust
28//! use split_array::SplitArray;
29//!
30//! let array: [usize; 5] = [0, 1, 2, 3, 4];
31//! let (left, right) = array.split_arr::<6>();
32//! ```
33
34#![no_std]
35#![allow(incomplete_features)]
36#![feature(generic_const_exprs)]
37
38/// Split array references in two with compile-time size validation.
39pub trait SplitArray<const LEN: usize> {
40    /// The result of a split.
41    type Output<const OUT_SIZE: usize>: SplitArray<OUT_SIZE>;
42
43    /// Split an array reference
44    /// into a reference to the left half and a reference to the right half.
45    /// The sizes of the halves are validated at compile time.
46    fn split_arr<const LEFT: usize>(&self) -> (&Self::Output<LEFT>, &Self::Output<{ LEN - LEFT }>)
47    where
48        [(); LEN - LEFT]:;
49
50    /// Mutable version of [`Self::split_arr`]
51    fn split_arr_mut<const LEFT: usize>(
52        &mut self,
53    ) -> (&mut Self::Output<LEFT>, &mut Self::Output<{ LEN - LEFT }>)
54    where
55        [(); LEN - LEFT]:;
56}
57
58/// Raw version of [`SplitArray`].
59pub trait SplitArrayRaw<const LEN: usize> {
60    /// The result of a split.
61    type Output<const OUT_SIZE: usize>: SplitArrayRaw<OUT_SIZE>;
62
63    /// Split an array pointer
64    /// into a pointer to the left half and a pointer to the right half.
65    /// The sizes of the halves are validated at compile time.
66    ///
67    /// # Safety
68    /// `self` must be valid.
69    unsafe fn split_arr_raw<const LEFT: usize>(
70        self,
71    ) -> (Self::Output<LEFT>, Self::Output<{ LEN - LEFT }>)
72    where
73        [(); LEN - LEFT]:;
74}
75
76/// Raw mutable version of [`SplitArray`].
77pub trait SplitArrayRawMut<const LEN: usize> {
78    type Output<const OUT_SIZE: usize>: SplitArrayRawMut<OUT_SIZE>;
79
80    /// Split an array pointer
81    /// into a pointer to the left half and a pointer to the right half.
82    /// The sizes of the halves are validated at compile time.
83    ///
84    /// # Safety
85    /// `self` must be valid.
86    unsafe fn split_arr_raw_mut<const LEFT: usize>(
87        self,
88    ) -> (Self::Output<LEFT>, Self::Output<{ LEN - LEFT }>)
89    where
90        [(); LEN - LEFT]:;
91}
92
93impl<T, const LEN: usize> SplitArray<LEN> for [T; LEN] {
94    type Output<const OUT_SIZE: usize> = [T; OUT_SIZE];
95
96    #[inline]
97    fn split_arr<const LEFT: usize>(&self) -> (&[T; LEFT], &[T; LEN - LEFT])
98    where
99        [(); LEN - LEFT]:,
100    {
101        split_arr(self)
102    }
103
104    #[inline]
105    fn split_arr_mut<const LEFT: usize>(&mut self) -> (&mut [T; LEFT], &mut [T; LEN - LEFT])
106    where
107        [(); LEN - LEFT]:,
108    {
109        split_arr_mut(self)
110    }
111}
112
113impl<T, const LEN: usize> SplitArrayRaw<LEN> for *const [T; LEN] {
114    type Output<const OUT_SIZE: usize> = *const [T; OUT_SIZE];
115
116    unsafe fn split_arr_raw<const LEFT: usize>(self) -> (*const [T; LEFT], *const [T; LEN - LEFT])
117    where
118        [(); LEN - LEFT]:,
119    {
120        unsafe { split_arr_raw(self) }
121    }
122}
123
124impl<T, const LEN: usize> SplitArrayRawMut<LEN> for *mut [T; LEN] {
125    type Output<const OUT_SIZE: usize> = *mut [T; OUT_SIZE];
126
127    unsafe fn split_arr_raw_mut<const LEFT: usize>(self) -> (*mut [T; LEFT], *mut [T; LEN - LEFT])
128    where
129        [(); LEN - LEFT]:,
130    {
131        unsafe { split_arr_raw_mut(self) }
132    }
133}
134
135/// Split an array reference
136/// into a reference to the left half and a reference to the right half.
137/// The sizes of the halves are validated at compile time.
138#[inline]
139pub const fn split_arr<const LEFT: usize, const N: usize, T>(
140    arr: &[T; N],
141) -> (&[T; LEFT], &[T; N - LEFT])
142where
143    [(); N - LEFT]:,
144{
145    unsafe {
146        let (left, right) = split_arr_raw(arr);
147        (&*left, &*right)
148    }
149}
150
151/// Mutable version of [`split_arr`].
152#[inline]
153pub fn split_arr_mut<const LEFT: usize, const N: usize, T>(
154    arr: &mut [T; N],
155) -> (&mut [T; LEFT], &mut [T; N - LEFT])
156where
157    [(); N - LEFT]:,
158{
159    unsafe {
160        let (left, right) = split_arr_raw_mut(arr);
161        (&mut *left, &mut *right)
162    }
163}
164
165/// Raw version of [`split_arr`].
166///
167/// # Safety
168/// `arr` must be valid.
169#[inline]
170pub const unsafe fn split_arr_raw<const LEFT: usize, const N: usize, T>(
171    arr: *const [T; N],
172) -> (*const [T; LEFT], *const [T; N - LEFT])
173where
174    [(); N - LEFT]:,
175{
176    let left = arr.cast::<T>();
177    let right = unsafe { left.add(LEFT) };
178
179    (left.cast(), right.cast())
180}
181
182/// Raw version of [`split_arr_mut`].
183///
184/// # Safety
185/// `arr` must be valid.
186#[inline]
187pub const unsafe fn split_arr_raw_mut<const LEFT: usize, const N: usize, T>(
188    arr: *mut [T; N],
189) -> (*mut [T; LEFT], *mut [T; N - LEFT])
190where
191    [(); N - LEFT]:,
192{
193    let left = arr as *mut T;
194    let right = unsafe { left.add(LEFT) };
195
196    (left.cast(), right.cast())
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202    use core::ptr::{addr_of, addr_of_mut};
203
204    #[test]
205    fn split_arr() {
206        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
207        let (left, right) = arr.split_arr::<5>();
208
209        assert_eq!(&[0, 1, 2, 3, 4], left);
210        assert_eq!(&[5, 6, 7], right);
211    }
212
213    #[test]
214    fn split_arr_infer_size() {
215        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
216        let (left, right) = arr.split_arr();
217
218        assert_eq!(&[0, 1, 2, 3, 4], left);
219        assert_eq!(&[5, 6, 7], right);
220    }
221
222    #[test]
223    fn split_arr_left_zero() {
224        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
225        let (left, right) = arr.split_arr::<0>();
226
227        assert_eq!(&[0; 0], left);
228        assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7], right);
229    }
230
231    #[test]
232    fn split_arr_right_zero() {
233        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
234        let (left, right) = arr.split_arr::<8>();
235
236        assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7], left);
237        assert_eq!(&[0; 0], right);
238    }
239
240    #[test]
241    fn split_arr_mut() {
242        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
243        let (left, right) = arr.split_arr_mut::<5>();
244        left.clone_from(&[10, 11, 12, 13, 14]);
245        right.clone_from(&[25, 26, 27]);
246
247        assert_eq!(&[10, 11, 12, 13, 14], left);
248        assert_eq!(&[25, 26, 27], right);
249        assert_eq!([10, 11, 12, 13, 14, 25, 26, 27], arr);
250    }
251
252    #[test]
253    fn split_arr_mut_infer_size() {
254        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
255        let (left, right) = arr.split_arr_mut();
256        left.clone_from(&[10, 11, 12, 13, 14]);
257        right.clone_from(&[25, 26, 27]);
258
259        assert_eq!(&[10, 11, 12, 13, 14], left);
260        assert_eq!(&[25, 26, 27], right);
261        assert_eq!([10, 11, 12, 13, 14, 25, 26, 27], arr);
262    }
263
264    #[test]
265    fn split_arr_mut_left_zero() {
266        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
267        let (left, right) = arr.split_arr_mut::<0>();
268        left.clone_from(&[]);
269        right.clone_from(&[20, 21, 22, 23, 24, 25, 26, 27]);
270
271        assert_eq!(&[0; 0], left);
272        assert_eq!(&[20, 21, 22, 23, 24, 25, 26, 27], right);
273        assert_eq!([20, 21, 22, 23, 24, 25, 26, 27], arr);
274    }
275
276    #[test]
277    fn split_arr_mut_right_zero() {
278        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
279        let (left, right) = arr.split_arr_mut::<8>();
280        left.clone_from(&[10, 11, 12, 13, 14, 15, 16, 17]);
281        right.clone_from(&[]);
282
283        assert_eq!(&[10, 11, 12, 13, 14, 15, 16, 17], left);
284        assert_eq!(&[0; 0], right);
285        assert_eq!([10, 11, 12, 13, 14, 15, 16, 17], arr);
286    }
287
288    #[test]
289    fn split_arr_raw() {
290        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
291
292        unsafe {
293            let (left, right) = addr_of!(arr).split_arr_raw::<5>();
294
295            assert_eq!([0, 1, 2, 3, 4], *left);
296            assert_eq!([5, 6, 7], *right);
297        }
298    }
299
300    #[test]
301    fn split_arr_raw_infer_size() {
302        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
303
304        unsafe {
305            let (left, right) = addr_of!(arr).split_arr_raw();
306
307            assert_eq!([0, 1, 2, 3, 4], *left);
308            assert_eq!([5, 6, 7], *right);
309        }
310    }
311
312    #[test]
313    fn split_arr_raw_left_zero() {
314        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
315
316        unsafe {
317            let (left, right) = addr_of!(arr).split_arr_raw::<0>();
318
319            assert_eq!([0; 0], *left);
320            assert_eq!([0, 1, 2, 3, 4, 5, 6, 7], *right);
321        }
322    }
323
324    #[test]
325    fn split_arr_raw_right_zero() {
326        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
327
328        unsafe {
329            let (left, right) = addr_of!(arr).split_arr_raw::<8>();
330
331            assert_eq!([0, 1, 2, 3, 4, 5, 6, 7], *left);
332            assert_eq!([0; 0], *right);
333        }
334    }
335
336    #[test]
337    fn split_arr_raw_mut() {
338        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
339
340        unsafe {
341            let (left, right) = addr_of_mut!(arr).split_arr_raw_mut::<5>();
342            *left = [10, 11, 12, 13, 14];
343            *right = [25, 26, 27];
344
345            assert_eq!([10, 11, 12, 13, 14], *left);
346            assert_eq!([25, 26, 27], *right);
347        }
348
349        assert_eq!([10, 11, 12, 13, 14, 25, 26, 27], arr);
350    }
351
352    #[test]
353    fn split_arr_raw_mut_infer_size() {
354        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
355
356        unsafe {
357            let (left, right) = addr_of_mut!(arr).split_arr_raw_mut();
358            *left = [10, 11, 12, 13, 14];
359            *right = [25, 26, 27];
360
361            assert_eq!([10, 11, 12, 13, 14], *left);
362            assert_eq!([25, 26, 27], *right);
363        }
364
365        assert_eq!([10, 11, 12, 13, 14, 25, 26, 27], arr);
366    }
367
368    #[test]
369    fn split_arr_raw_mut_left_zero() {
370        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
371
372        unsafe {
373            let (left, right) = addr_of_mut!(arr).split_arr_raw_mut::<0>();
374            *left = [];
375            *right = [20, 21, 22, 23, 24, 25, 26, 27];
376
377            assert_eq!([0; 0], *left);
378            assert_eq!([20, 21, 22, 23, 24, 25, 26, 27], *right);
379        }
380
381        assert_eq!([20, 21, 22, 23, 24, 25, 26, 27], arr);
382    }
383
384    #[test]
385    fn split_arr_raw_mut_right_zero() {
386        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
387
388        unsafe {
389            let (left, right) = addr_of_mut!(arr).split_arr_raw_mut::<8>();
390            *left = [10, 11, 12, 13, 14, 15, 16, 17];
391            *right = [];
392
393            assert_eq!([10, 11, 12, 13, 14, 15, 16, 17], *left);
394            assert_eq!([0; 0], *right);
395        }
396
397        assert_eq!([10, 11, 12, 13, 14, 15, 16, 17], arr);
398    }
399
400    #[test]
401    fn array_impl_defers() {
402        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
403        assert_eq!(crate::split_arr(&arr), arr.split_arr::<5>());
404    }
405
406    #[test]
407    fn array_impl_defers_mut() {
408        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
409        let (crate_level_left, crate_level_right) = crate::split_arr_mut(&mut arr);
410        let crate_level_result = (crate_level_left as *mut _, crate_level_right as *mut _);
411        let (trait_left, trait_right) = arr.split_arr_mut::<5>();
412        let trait_result = (trait_left as *mut _, trait_right as *mut _);
413        assert_eq!(crate_level_result, trait_result);
414    }
415
416    #[test]
417    fn array_impl_defers_raw() {
418        let arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
419        unsafe {
420            assert_eq!(
421                crate::split_arr_raw(addr_of!(arr)),
422                addr_of!(arr).split_arr_raw::<5>()
423            );
424        }
425    }
426
427    #[test]
428    fn array_impl_defers_raw_mut() {
429        let mut arr: [usize; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
430        unsafe {
431            assert_eq!(
432                crate::split_arr_raw_mut(addr_of_mut!(arr)),
433                addr_of_mut!(arr).split_arr_raw_mut::<5>()
434            );
435        }
436    }
437}