From ce084c6be26fa31923d91d29a040b69fe831703d Mon Sep 17 00:00:00 2001 From: Kor Nielsen Date: Wed, 22 Feb 2023 14:48:12 -0800 Subject: [PATCH] Support indexing with most core::ops::Range* types. These will panic if the result is not aligned correctly. --- src/lib.rs | 509 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 500 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 802366d..0caeabc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,21 +34,38 @@ use core::{ cmp::Ordering, fmt::{Debug, Display}, hash::{Hash, Hasher}, - ops, + ops::{self}, }; use as_slice::{AsMutSlice, AsSlice}; /// A marker trait for an alignment value. -pub trait Alignment: Copy + sealed::Sealed {} +pub trait Alignment: Copy + sealed::Sealed { + /// The alignment in bytes. + const ALIGN: usize; +} -impl Alignment for A1 {} -impl Alignment for A2 {} -impl Alignment for A4 {} -impl Alignment for A8 {} -impl Alignment for A16 {} -impl Alignment for A32 {} -impl Alignment for A64 {} +impl Alignment for A1 { + const ALIGN: usize = 1; +} +impl Alignment for A2 { + const ALIGN: usize = 2; +} +impl Alignment for A4 { + const ALIGN: usize = 4; +} +impl Alignment for A8 { + const ALIGN: usize = 8; +} +impl Alignment for A16 { + const ALIGN: usize = 16; +} +impl Alignment for A32 { + const ALIGN: usize = 32; +} +impl Alignment for A64 { + const ALIGN: usize = 64; +} mod sealed { pub trait Sealed {} @@ -138,6 +155,34 @@ where } } +impl Aligned +where + A: Alignment, +{ + fn is_index_aligned(index: usize) -> bool { + use core::mem::size_of; + + (index * size_of::()) % A::ALIGN == 0 + } + fn check_start_index(index: usize) { + if !Self::is_index_aligned(index) { + panic!("Unaligned start index"); + } + } +} + +impl ops::Index> for Aligned +where + A: Alignment, +{ + type Output = Aligned; + + fn index(&self, range: ops::RangeFrom) -> &Aligned { + Self::check_start_index(range.start); + unsafe { &*(&self.value[range] as *const [T] as *const Aligned) } + } +} + impl ops::Index> for Aligned where A: Alignment, @@ -149,6 +194,109 @@ where } } +impl ops::Index> for Aligned +where + A: Alignment, +{ + type Output = Aligned; + + fn index(&self, range: ops::RangeToInclusive) -> &Aligned { + unsafe { &*(&self.value[range] as *const [T] as *const Aligned) } + } +} + +impl ops::Index> for Aligned +where + A: Alignment, +{ + type Output = Aligned; + + fn index(&self, range: ops::RangeInclusive) -> &Aligned { + Self::check_start_index(*range.start()); + unsafe { &*(&self.value[range] as *const [T] as *const Aligned) } + } +} + +impl ops::Index> for Aligned +where + A: Alignment, +{ + type Output = Aligned; + + fn index(&self, range: ops::Range) -> &Aligned { + Self::check_start_index(range.start); + unsafe { &*(&self.value[range] as *const [T] as *const Aligned) } + } +} + +impl ops::Index for Aligned +where + A: Alignment, +{ + type Output = Aligned; + + fn index(&self, range: ops::RangeFull) -> &Aligned { + unsafe { &*(&self.value[range] as *const [T] as *const Aligned) } + } +} + +impl ops::IndexMut> for Aligned +where + A: Alignment, +{ + fn index_mut(&mut self, range: ops::RangeFrom) -> &mut Aligned { + Self::check_start_index(range.start); + unsafe { &mut *(&mut self.value[range] as *mut [T] as *mut Aligned) } + } +} + +impl ops::IndexMut> for Aligned +where + A: Alignment, +{ + fn index_mut(&mut self, range: ops::RangeTo) -> &mut Aligned { + unsafe { &mut *(&mut self.value[range] as *mut [T] as *mut Aligned) } + } +} + +impl ops::IndexMut> for Aligned +where + A: Alignment, +{ + fn index_mut(&mut self, range: ops::RangeToInclusive) -> &mut Aligned { + unsafe { &mut *(&mut self.value[range] as *mut [T] as *mut Aligned) } + } +} + +impl ops::IndexMut> for Aligned +where + A: Alignment, +{ + fn index_mut(&mut self, range: ops::RangeInclusive) -> &mut Aligned { + Self::check_start_index(*range.start()); + unsafe { &mut *(&mut self.value[range] as *mut [T] as *mut Aligned) } + } +} + +impl ops::IndexMut> for Aligned +where + A: Alignment, +{ + fn index_mut(&mut self, range: ops::Range) -> &mut Aligned { + Self::check_start_index(range.start); + unsafe { &mut *(&mut self.value[range] as *mut [T] as *mut Aligned) } + } +} + +impl ops::IndexMut for Aligned +where + A: Alignment, +{ + fn index_mut(&mut self, range: ops::RangeFull) -> &mut Aligned { + unsafe { &mut *(&mut self.value[range] as *mut [T] as *mut Aligned) } + } +} + impl AsSlice for Aligned where A: Alignment, @@ -376,3 +524,346 @@ fn sanity() { let y: &Aligned = &x; let _: &[u8] = y; } + +#[test] +fn test_range_to() { + let a: &Aligned = &Aligned::([0, 1, 2, 3]); + assert_eq!((&a[..0]).as_slice(), &[],); + assert_eq!((&a[..1]).as_slice(), &[0],); + assert_eq!((&a[..2]).as_slice(), &[0, 1],); + assert_eq!((&a[..3]).as_slice(), &[0, 1, 2],); + assert_eq!((&a[..4]).as_slice(), &[0, 1, 2, 3],); +} + +#[test] +fn test_range_to_mut() { + let a: &mut Aligned = &mut Aligned::([0, 1, 2, 3]); + assert_eq!((&mut a[..0]).as_slice(), &[],); + assert_eq!((&mut a[..1]).as_slice(), &[0],); + assert_eq!((&mut a[..2]).as_slice(), &[0, 1],); + assert_eq!((&mut a[..3]).as_slice(), &[0, 1, 2],); + assert_eq!((&mut a[..4]).as_slice(), &[0, 1, 2, 3],); +} + +#[test] +fn test_range_to_inclusive() { + let a: &Aligned = &Aligned::([0, 1, 2, 3]); + assert_eq!((&a[..=0]).as_slice(), &[0],); + assert_eq!((&a[..=1]).as_slice(), &[0, 1],); + assert_eq!((&a[..=2]).as_slice(), &[0, 1, 2],); + assert_eq!((&a[..=3]).as_slice(), &[0, 1, 2, 3],); +} + +#[test] +fn test_range_to_inclusive_mut() { + let a: &mut Aligned = &mut Aligned::([0, 1, 2, 3]); + assert_eq!((&mut a[..=0]).as_slice(), &[0],); + assert_eq!((&mut a[..=1]).as_slice(), &[0, 1],); + assert_eq!((&mut a[..=2]).as_slice(), &[0, 1, 2],); + assert_eq!((&mut a[..=3]).as_slice(), &[0, 1, 2, 3],); +} + +#[test] +fn test_range_full() { + let a: &Aligned = &Aligned::([0, 1, 2, 3]); + assert_eq!((&a[..]).as_slice(), &[0, 1, 2, 3],); +} + +#[test] +fn test_range_full_mut() { + let a: &Aligned = &Aligned::([0, 1, 2, 3]); + assert_eq!((&a[..]).as_slice(), &[0, 1, 2, 3],); +} + +#[test] +fn test_range_from() { + let a: &Aligned = &Aligned::([0, 1, 2, 3]); + assert_eq!((&a[0..]).as_slice(), &[0, 1, 2, 3],); + assert_eq!((&a[2..]).as_slice(), &[2, 3],); + assert_eq!((&a[4..]).as_slice(), &[],); + + let a: &Aligned = &Aligned::([0, 1, 2]); + assert_eq!((&a[0..]).as_slice(), &[0, 1, 2],); + assert_eq!((&a[2..]).as_slice(), &[2],); + + let a: &Aligned = &Aligned::([0, 1, 2, 3, 4, 5, 6, 7]); + assert_eq!((&a[0..]).as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7],); + assert_eq!((&a[4..]).as_slice(), &[4, 5, 6, 7],); + assert_eq!((&a[8..]).as_slice(), &[],); + + let a: &Aligned = &Aligned::([0, 1, 2, 3, 4, 5, 6]); + assert_eq!((&a[0..]).as_slice(), &[0, 1, 2, 3, 4, 5, 6],); + assert_eq!((&a[4..]).as_slice(), &[4, 5, 6],); + + let a: &Aligned = + &Aligned::([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + assert_eq!( + (&a[0..]).as_slice(), + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + ); + assert_eq!((&a[8..]).as_slice(), &[8, 9, 10, 11, 12, 13, 14, 15],); + assert_eq!((&a[16..]).as_slice(), &[],); + + let a: &Aligned = + &Aligned::([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]); + assert_eq!( + (&a[0..]).as_slice(), + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], + ); + assert_eq!((&a[8..]).as_slice(), &[8, 9, 10, 11, 12, 13, 14],); + + let a: &Aligned = &Aligned::([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, + ]); + assert_eq!( + (&a[0..]).as_slice(), + &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31 + ], + ); + assert_eq!( + (&a[16..]).as_slice(), + &[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], + ); + assert_eq!((&a[32..]).as_slice(), &[],); + + let a: &Aligned = &Aligned::([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, + ]); + assert_eq!( + (&a[0..]).as_slice(), + &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30 + ], + ); + assert_eq!( + (&a[16..]).as_slice(), + &[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], + ); + + let a: &Aligned = &Aligned::([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + ]); + assert_eq!( + (&a[0..]).as_slice(), + &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 + ] + ); + assert_eq!( + (&a[32..]).as_slice(), + &[ + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 + ] + ); + assert_eq!((&a[64..]).as_slice(), &[],); + + let a: &Aligned = &Aligned::([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + ]); + assert_eq!( + (&a[0..]).as_slice(), + &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62 + ] + ); + assert_eq!( + (&a[32..]).as_slice(), + &[ + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62 + ] + ); + + let a: &Aligned = &Aligned::([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + ]); + assert_eq!( + (&a[0..]).as_slice(), + &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127 + ] + ); + assert_eq!( + (&a[64..]).as_slice(), + &[ + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127 + ] + ); + assert_eq!((&a[128..]).as_slice(), &[]); + + let a: &Aligned = &Aligned::([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + ]); + assert_eq!( + (&a[0..]).as_slice(), + &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126 + ] + ); + assert_eq!( + (&a[64..]).as_slice(), + &[ + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126 + ] + ); +} + +#[test] +#[should_panic(expected = "Unaligned start index")] +fn test_range_from_a2_invalid_alignment() { + let a: &Aligned = &Aligned::([0u8; 4]); + let _ = &a[1..]; +} + +#[test] +#[should_panic(expected = "Unaligned start index")] +fn test_range_from_a4_invalid_alignment() { + let a: &Aligned = &Aligned::([0u8; 8]); + let _ = &a[6..]; +} + +#[test] +fn test_range_from_mut() { + let a: &mut Aligned = &mut Aligned::([0, 1, 2, 3]); + assert_eq!((&mut a[0..]).as_slice(), &[0, 1, 2, 3],); + assert_eq!((&mut a[2..]).as_slice(), &[2, 3],); + assert_eq!((&mut a[4..]).as_slice(), &[],); + + let a: &mut Aligned = &mut Aligned::([0, 1, 2]); + assert_eq!((&mut a[0..]).as_slice(), &[0, 1, 2],); + assert_eq!((&mut a[2..]).as_slice(), &[2],); +} + +#[test] +#[should_panic(expected = "Unaligned start index")] +fn test_range_from_mut_invalid_argument() { + let a: &mut Aligned = &mut Aligned::([0u8; 4]); + let _ = &mut a[1..]; +} + +#[test] +fn test_range() { + let a: &Aligned = &Aligned::([0, 1, 2, 3]); + assert_eq!((&a[0..0]).as_slice(), &[],); + assert_eq!((&a[0..1]).as_slice(), &[0],); + assert_eq!((&a[0..2]).as_slice(), &[0, 1],); + assert_eq!((&a[0..3]).as_slice(), &[0, 1, 2],); + assert_eq!((&a[0..4]).as_slice(), &[0, 1, 2, 3],); + assert_eq!((&a[2..2]).as_slice(), &[],); + assert_eq!((&a[2..3]).as_slice(), &[2],); + assert_eq!((&a[2..4]).as_slice(), &[2, 3],); + assert_eq!((&a[4..4]).as_slice(), &[],); +} + +#[test] +#[should_panic(expected = "Unaligned start index")] +fn test_range_invalid_alignment() { + let a: &Aligned = &Aligned::([0u8; 4]); + let _ = &a[1..2]; +} + +#[test] +fn test_range_mut() { + let a: &mut Aligned = &mut Aligned::([0, 1, 2, 3]); + assert_eq!((&mut a[0..0]).as_slice(), &[],); + assert_eq!((&mut a[0..1]).as_slice(), &[0],); + assert_eq!((&mut a[0..2]).as_slice(), &[0, 1],); + assert_eq!((&mut a[0..3]).as_slice(), &[0, 1, 2],); + assert_eq!((&mut a[0..4]).as_slice(), &[0, 1, 2, 3],); + assert_eq!((&mut a[2..2]).as_slice(), &[],); + assert_eq!((&mut a[2..3]).as_slice(), &[2],); + assert_eq!((&mut a[2..4]).as_slice(), &[2, 3],); + assert_eq!((&mut a[4..4]).as_slice(), &[],); +} + +#[test] +#[should_panic(expected = "Unaligned start index")] +fn test_range_mut_invalid_alignment() { + let a: &mut Aligned = &mut Aligned::([0u8; 4]); + let _ = &mut a[1..2]; +} + +#[test] +fn test_range_inclusive() { + let a: &Aligned = &Aligned::([0, 1, 2, 3]); + assert_eq!((&a[0..=0]).as_slice(), &[0],); + assert_eq!((&a[0..=1]).as_slice(), &[0, 1],); + assert_eq!((&a[0..=2]).as_slice(), &[0, 1, 2],); + assert_eq!((&a[0..=3]).as_slice(), &[0, 1, 2, 3],); + assert_eq!((&a[2..=2]).as_slice(), &[2],); + assert_eq!((&a[2..=3]).as_slice(), &[2, 3],); +} + +#[test] +#[should_panic(expected = "Unaligned start index")] +fn test_range_inclusive_invalid_alignment() { + let a: &Aligned = &Aligned::([0u8; 4]); + let _ = &a[1..=2]; +} + +#[test] +fn test_range_inclusive_mut() { + let a: &mut Aligned = &mut Aligned::([0, 1, 2, 3]); + assert_eq!((&mut a[0..=0]).as_slice(), &[0],); + assert_eq!((&mut a[0..=1]).as_slice(), &[0, 1],); + assert_eq!((&mut a[0..=2]).as_slice(), &[0, 1, 2],); + assert_eq!((&mut a[0..=3]).as_slice(), &[0, 1, 2, 3],); + assert_eq!((&mut a[2..=2]).as_slice(), &[2],); + assert_eq!((&mut a[2..=3]).as_slice(), &[2, 3],); +} + +#[test] +#[should_panic(expected = "Unaligned start index")] +fn test_range_inclusive_mut_invalid_alignment() { + let a: &mut Aligned = &mut Aligned::([0u8; 4]); + let _ = &mut a[1..=2]; +} + +#[test] +#[should_panic(expected = "out of range")] +fn test_range_from_out_of_bounds() { + let a: &Aligned = &Aligned::([0u8; 4]); + let _ = &a[6..]; +}