@@ -42,7 +42,11 @@ fn array_from_slice<const N: usize>(bs: &[u8]) -> Result<[u8; N]> {
42
42
}
43
43
}
44
44
45
- pub trait FromBytes : Sized {
45
+ /// # Safety
46
+ /// All bit patterns 00000xxxx, where there are `BIT_CAPACITY` `x`s,
47
+ /// must be valid, unless BIT_CAPACITY is 0.
48
+ pub unsafe trait FromBytes : Sized {
49
+ const BIT_CAPACITY : usize ;
46
50
type Buffer : AsMut < [ u8 ] > + Default ;
47
51
fn try_from_le_slice ( b : & [ u8 ] ) -> Result < Self > ;
48
52
fn from_le_bytes ( bs : Self :: Buffer ) -> Self ;
@@ -51,7 +55,9 @@ pub trait FromBytes: Sized {
51
55
macro_rules! from_le_bytes {
52
56
( $( $ty: ty) ,* ) => {
53
57
$(
54
- impl FromBytes for $ty {
58
+ // SAFETY: this macro is used for types for which all bit patterns are valid.
59
+ unsafe impl FromBytes for $ty {
60
+ const BIT_CAPACITY : usize = std:: mem:: size_of:: <$ty>( ) * 8 ;
55
61
type Buffer = [ u8 ; size_of:: <Self >( ) ] ;
56
62
fn try_from_le_slice( b: & [ u8 ] ) -> Result <Self > {
57
63
Ok ( Self :: from_le_bytes( array_from_slice( b) ?) )
@@ -66,7 +72,9 @@ macro_rules! from_le_bytes {
66
72
67
73
from_le_bytes ! { u8 , u16 , u32 , u64 , i8 , i16 , i32 , i64 , f32 , f64 }
68
74
69
- impl FromBytes for bool {
75
+ // SAFETY: the 0000000x bit pattern is always valid for `bool`.
76
+ unsafe impl FromBytes for bool {
77
+ const BIT_CAPACITY : usize = 1 ;
70
78
type Buffer = [ u8 ; 1 ] ;
71
79
72
80
fn try_from_le_slice ( b : & [ u8 ] ) -> Result < Self > {
@@ -77,7 +85,9 @@ impl FromBytes for bool {
77
85
}
78
86
}
79
87
80
- impl FromBytes for Int96 {
88
+ // SAFETY: BIT_CAPACITY is 0.
89
+ unsafe impl FromBytes for Int96 {
90
+ const BIT_CAPACITY : usize = 0 ;
81
91
type Buffer = [ u8 ; 12 ] ;
82
92
83
93
fn try_from_le_slice ( b : & [ u8 ] ) -> Result < Self > {
@@ -95,7 +105,9 @@ impl FromBytes for Int96 {
95
105
}
96
106
}
97
107
98
- impl FromBytes for ByteArray {
108
+ // SAFETY: BIT_CAPACITY is 0.
109
+ unsafe impl FromBytes for ByteArray {
110
+ const BIT_CAPACITY : usize = 0 ;
99
111
type Buffer = Vec < u8 > ;
100
112
101
113
fn try_from_le_slice ( b : & [ u8 ] ) -> Result < Self > {
@@ -106,7 +118,9 @@ impl FromBytes for ByteArray {
106
118
}
107
119
}
108
120
109
- impl FromBytes for FixedLenByteArray {
121
+ // SAFETY: BIT_CAPACITY is 0.
122
+ unsafe impl FromBytes for FixedLenByteArray {
123
+ const BIT_CAPACITY : usize = 0 ;
110
124
type Buffer = Vec < u8 > ;
111
125
112
126
fn try_from_le_slice ( b : & [ u8 ] ) -> Result < Self > {
@@ -457,10 +471,17 @@ impl BitReader {
457
471
}
458
472
}
459
473
474
+ assert_ne ! ( T :: BIT_CAPACITY , 0 ) ;
475
+ assert ! ( num_bits <= T :: BIT_CAPACITY ) ;
476
+
460
477
// Read directly into output buffer
461
478
match size_of :: < T > ( ) {
462
479
1 => {
463
480
let ptr = batch. as_mut_ptr ( ) as * mut u8 ;
481
+ // SAFETY: batch is properly aligned and sized. Caller guarantees that all bit patterns
482
+ // in which only the lowest T::BIT_CAPACITY bits of T are set are valid,
483
+ // unpack{8,16,32,64} only set to non0 the lowest num_bits bits, and we
484
+ // checked that num_bits <= T::BIT_CAPACITY.
464
485
let out = unsafe { std:: slice:: from_raw_parts_mut ( ptr, batch. len ( ) ) } ;
465
486
while values_to_read - i >= 8 {
466
487
let out_slice = ( & mut out[ i..i + 8 ] ) . try_into ( ) . unwrap ( ) ;
@@ -471,6 +492,10 @@ impl BitReader {
471
492
}
472
493
2 => {
473
494
let ptr = batch. as_mut_ptr ( ) as * mut u16 ;
495
+ // SAFETY: batch is properly aligned and sized. Caller guarantees that all bit patterns
496
+ // in which only the lowest T::BIT_CAPACITY bits of T are set are valid,
497
+ // unpack{8,16,32,64} only set to non0 the lowest num_bits bits, and we
498
+ // checked that num_bits <= T::BIT_CAPACITY.
474
499
let out = unsafe { std:: slice:: from_raw_parts_mut ( ptr, batch. len ( ) ) } ;
475
500
while values_to_read - i >= 16 {
476
501
let out_slice = ( & mut out[ i..i + 16 ] ) . try_into ( ) . unwrap ( ) ;
@@ -481,6 +506,10 @@ impl BitReader {
481
506
}
482
507
4 => {
483
508
let ptr = batch. as_mut_ptr ( ) as * mut u32 ;
509
+ // SAFETY: batch is properly aligned and sized. Caller guarantees that all bit patterns
510
+ // in which only the lowest T::BIT_CAPACITY bits of T are set are valid,
511
+ // unpack{8,16,32,64} only set to non0 the lowest num_bits bits, and we
512
+ // checked that num_bits <= T::BIT_CAPACITY.
484
513
let out = unsafe { std:: slice:: from_raw_parts_mut ( ptr, batch. len ( ) ) } ;
485
514
while values_to_read - i >= 32 {
486
515
let out_slice = ( & mut out[ i..i + 32 ] ) . try_into ( ) . unwrap ( ) ;
@@ -491,6 +520,10 @@ impl BitReader {
491
520
}
492
521
8 => {
493
522
let ptr = batch. as_mut_ptr ( ) as * mut u64 ;
523
+ // SAFETY: batch is properly aligned and sized. Caller guarantees that all bit patterns
524
+ // in which only the lowest T::BIT_CAPACITY bits of T are set are valid,
525
+ // unpack{8,16,32,64} only set to non0 the lowest num_bits bits, and we
526
+ // checked that num_bits <= T::BIT_CAPACITY.
494
527
let out = unsafe { std:: slice:: from_raw_parts_mut ( ptr, batch. len ( ) ) } ;
495
528
while values_to_read - i >= 64 {
496
529
let out_slice = ( & mut out[ i..i + 64 ] ) . try_into ( ) . unwrap ( ) ;
0 commit comments