2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
4
use core:: slice;
5
+ use ddcommon:: error:: FfiSafeErrorMessage ;
5
6
use serde:: ser:: Error ;
6
7
use serde:: Serializer ;
7
8
use std:: borrow:: Cow ;
@@ -11,6 +12,14 @@ use std::marker::PhantomData;
11
12
use std:: os:: raw:: c_char;
12
13
use std:: str:: Utf8Error ;
13
14
15
+ #[ repr( C ) ]
16
+ #[ derive( Clone , Copy , Debug ) ]
17
+ pub enum SliceConversionError {
18
+ LargeLength ,
19
+ NullPointer ,
20
+ MisalignedPointer ,
21
+ }
22
+
14
23
#[ repr( C ) ]
15
24
#[ derive( Copy , Clone ) ]
16
25
pub struct Slice < ' a , T : ' a > {
@@ -25,6 +34,25 @@ pub struct Slice<'a, T: 'a> {
25
34
_marker : PhantomData < & ' a [ T ] > ,
26
35
}
27
36
37
+ /// # Safety
38
+ /// All strings are valid UTF-8 (enforced by using c-str literals in Rust).
39
+ unsafe impl FfiSafeErrorMessage for SliceConversionError {
40
+ fn as_ffi_str ( & self ) -> & ' static std:: ffi:: CStr {
41
+ match self {
42
+ SliceConversionError :: LargeLength => c"length was too large" ,
43
+ SliceConversionError :: NullPointer => c"null pointer with non-zero length" ,
44
+ SliceConversionError :: MisalignedPointer => c"pointer was not aligned for the type" ,
45
+ }
46
+ }
47
+ }
48
+ impl Display for SliceConversionError {
49
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
50
+ Display :: fmt ( self . as_rust_str ( ) , f)
51
+ }
52
+ }
53
+
54
+ impl core:: error:: Error for SliceConversionError { }
55
+
28
56
impl < ' a , T : ' a > core:: ops:: Deref for Slice < ' a , T > {
29
57
type Target = [ T ] ;
30
58
@@ -55,51 +83,25 @@ pub type ByteSlice<'a> = Slice<'a, u8>;
55
83
56
84
/// This exists as an intrinsic, but it is private.
57
85
pub fn is_aligned_and_not_null < T > ( ptr : * const T ) -> bool {
58
- !ptr. is_null ( ) && is_aligned ( ptr)
59
- }
60
-
61
- #[ inline]
62
- fn is_aligned < T > ( ptr : * const T ) -> bool {
63
- debug_assert ! ( !ptr. is_null( ) ) ;
64
- ptr as usize % std:: mem:: align_of :: < T > ( ) == 0
65
- }
66
-
67
- #[ repr( C ) ]
68
- #[ derive( Clone , Copy , Debug ) ]
69
- pub enum SliceConversionError {
70
- LargeLength ,
71
- NullPointer ,
72
- MisalignedPointer ,
86
+ !ptr. is_null ( ) && ptr. is_aligned ( )
73
87
}
74
88
75
- /// # Safety
76
- /// All strings are valid UTF-8 (enforced by using c-str literals in Rust)
77
- unsafe impl ddcommon:: ffi:: ThinError for SliceConversionError {
78
- fn as_ffi_str ( & self ) -> & ' static std:: ffi:: CStr {
79
- match self {
80
- SliceConversionError :: LargeLength => c"length was too large" ,
81
- SliceConversionError :: NullPointer => c"null pointer with non-zero length" ,
82
- SliceConversionError :: MisalignedPointer => c"pointer was not aligned for the type" ,
83
- }
84
- }
85
- }
86
-
87
- impl Display for SliceConversionError {
88
- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
89
- Display :: fmt ( ddcommon:: ffi:: error_as_rust_str ( self ) , f)
90
- }
91
- }
92
-
93
- impl core:: error:: Error for SliceConversionError { }
94
-
95
89
pub trait AsBytes < ' a > {
96
- fn as_bytes ( & self ) -> & ' a [ u8 ] {
97
- {
98
- #[ allow( clippy:: expect_used) ]
99
- self . try_as_bytes ( ) . expect ( "failed to interpret as bytes" )
100
- }
101
- }
90
+ fn as_bytes ( & self ) -> & ' a [ u8 ] ;
102
91
92
+ /// Tries to interpret the structure as a slice of bytes.
93
+ ///
94
+ /// # Errors
95
+ ///
96
+ /// - Returns [`SliceConversionError::NullPointer`] if the slice has a null pointer and a
97
+ /// length other than zero. If pointer is null and length is zero, then return `Ok(&[])`
98
+ /// instead.
99
+ /// - Returns [`SliceConversionError::MisalignedPointer`] if the pointer is non-null and is not
100
+ /// aligned correctly for the type (not generally possible with types which are inherently
101
+ /// byte oriented, but is if the slice is of some other type which is being safely
102
+ /// reinterpreted as bytes).
103
+ /// - Returns [`SliceConversionError::LargeLength`] if the length of the slice exceeds
104
+ /// [`isize::MAX`].
103
105
fn try_as_bytes ( & self ) -> Result < & ' a [ u8 ] , SliceConversionError > ;
104
106
105
107
#[ inline]
@@ -130,20 +132,30 @@ pub trait AsBytes<'a> {
130
132
}
131
133
132
134
impl < ' a > AsBytes < ' a > for Slice < ' a , u8 > {
135
+ fn as_bytes ( & self ) -> & ' a [ u8 ] {
136
+ self . as_slice ( )
137
+ }
138
+
133
139
fn try_as_bytes ( & self ) -> Result < & ' a [ u8 ] , SliceConversionError > {
134
140
self . try_as_slice ( )
135
141
}
136
142
}
137
143
138
144
impl < ' a > AsBytes < ' a > for Slice < ' a , i8 > {
145
+ fn as_bytes ( & self ) -> & ' a [ u8 ] {
146
+ #[ allow( clippy:: expect_used) ]
147
+ self . try_as_bytes ( )
148
+ . expect ( "AsBytes::as_bytes failed to convert to a Rust slice" )
149
+ }
150
+
139
151
fn try_as_bytes ( & self ) -> Result < & ' a [ u8 ] , SliceConversionError > {
140
- self . try_as_slice ( ) . map ( |i8_slice | {
152
+ self . try_as_slice ( ) . map ( |slice | {
141
153
// SAFETY: we've gone through a successful try_as_slice, so the
142
154
// enforceable characteristics such as fitting in isize::MAX are
143
155
// all good. The rest is safe only if the consumer respects the
144
156
// inherent safety requirements--doesn't give invalid length,
145
157
// pointer to invalid memory, etc.
146
- unsafe { slice:: from_raw_parts ( i8_slice . as_ptr ( ) . cast ( ) , self . len ) }
158
+ unsafe { slice:: from_raw_parts ( slice . as_ptr ( ) . cast ( ) , self . len ) }
147
159
} )
148
160
}
149
161
}
@@ -160,7 +172,7 @@ impl<'a> AsBytes<'a> for &'a [c_char] {
160
172
}
161
173
}
162
174
163
- impl < ' a , T > Slice < ' a , T > {
175
+ impl < ' a , T : ' a > Slice < ' a , T > {
164
176
/// Creates a valid empty slice (len=0, ptr is non-null).
165
177
#[ must_use]
166
178
pub const fn empty ( ) -> Self {
@@ -198,10 +210,10 @@ impl<'a, T> Slice<'a, T> {
198
210
}
199
211
}
200
212
201
- #[ inline]
202
213
pub fn as_slice ( & self ) -> & ' a [ T ] {
203
214
#[ allow( clippy:: expect_used) ]
204
- self . try_as_slice ( ) . expect ( "ffi Slice wasn't a valid slice" )
215
+ self . try_as_slice ( )
216
+ . expect ( "ffi Slice failed to convert to a Rust slice" )
205
217
}
206
218
207
219
/// Tries to convert the FFI slice into a standard slice.
@@ -212,15 +224,16 @@ impl<'a, T> Slice<'a, T> {
212
224
/// 2. Fails if `self.ptr` is not null and is unaligned.
213
225
/// 3. Fails if `self.len` is larger than [`isize::MAX`].
214
226
pub fn try_as_slice ( & self ) -> Result < & ' a [ T ] , SliceConversionError > {
215
- if !self . ptr . is_null ( ) {
216
- if self . len ( ) > isize:: MAX as usize {
227
+ let ( ptr, len) = self . as_raw_parts ( ) ;
228
+ if !ptr. is_null ( ) {
229
+ if len > isize:: MAX as usize {
217
230
Err ( SliceConversionError :: LargeLength )
218
- } else if self . ptr . is_aligned ( ) {
231
+ } else if ! ptr. is_aligned ( ) {
219
232
Err ( SliceConversionError :: MisalignedPointer )
220
233
} else {
221
- Ok ( unsafe { slice:: from_raw_parts ( self . ptr , self . len ) } )
234
+ Ok ( unsafe { slice:: from_raw_parts ( ptr, len) } )
222
235
}
223
- } else if self . len != 0 {
236
+ } else if len != 0 {
224
237
Err ( SliceConversionError :: NullPointer )
225
238
} else {
226
239
Ok ( & [ ] )
0 commit comments