@@ -9,6 +9,7 @@ use crate::{alloc::AllocError, str::CStr};
9
9
use alloc:: alloc:: LayoutError ;
10
10
11
11
use core:: fmt;
12
+ use core:: num:: NonZeroI32 ;
12
13
use core:: num:: TryFromIntError ;
13
14
use core:: str:: Utf8Error ;
14
15
@@ -20,7 +21,12 @@ pub mod code {
20
21
$(
21
22
#[ doc = $doc]
22
23
) *
23
- pub const $err: super :: Error = super :: Error ( -( crate :: bindings:: $err as i32 ) ) ;
24
+ pub const $err: super :: Error =
25
+ match super :: Error :: try_from_errno( -( crate :: bindings:: $err as i32 ) ) {
26
+ Some ( err) => err,
27
+ None => panic!( "Invalid errno in `declare_err!`" ) ,
28
+ }
29
+ ;
24
30
} ;
25
31
}
26
32
@@ -88,7 +94,7 @@ pub mod code {
88
94
///
89
95
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
90
96
#[ derive( Clone , Copy , PartialEq , Eq ) ]
91
- pub struct Error ( core :: ffi :: c_int ) ;
97
+ pub struct Error ( NonZeroI32 ) ;
92
98
93
99
impl Error {
94
100
/// Creates an [`Error`] from a kernel error code.
@@ -107,45 +113,59 @@ impl Error {
107
113
108
114
// INVARIANT: The check above ensures the type invariant
109
115
// will hold.
110
- Error ( errno)
116
+ // SAFETY: `errno` is checked above to be in a valid range.
117
+ unsafe { Error :: from_errno_unchecked ( errno) }
118
+ }
119
+
120
+ /// Creates an [`Error`] from a kernel error code.
121
+ ///
122
+ /// Returns [`None`] if `errno` is out-of-range.
123
+ const fn try_from_errno ( errno : core:: ffi:: c_int ) -> Option < Error > {
124
+ if errno < -( bindings:: MAX_ERRNO as i32 ) || errno >= 0 {
125
+ return None ;
126
+ }
127
+
128
+ // SAFETY: `errno` is checked above to be in a valid range.
129
+ Some ( unsafe { Error :: from_errno_unchecked ( errno) } )
111
130
}
112
131
113
132
/// Creates an [`Error`] from a kernel error code.
114
133
///
115
134
/// # Safety
116
135
///
117
136
/// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
118
- unsafe fn from_errno_unchecked ( errno : core:: ffi:: c_int ) -> Error {
137
+ const unsafe fn from_errno_unchecked ( errno : core:: ffi:: c_int ) -> Error {
119
138
// INVARIANT: The contract ensures the type invariant
120
139
// will hold.
121
- Error ( errno)
140
+ // SAFETY: The caller guarantees `errno` is non-zero.
141
+ Error ( unsafe { NonZeroI32 :: new_unchecked ( errno) } )
122
142
}
123
143
124
144
/// Returns the kernel error code.
125
145
pub fn to_errno ( self ) -> core:: ffi:: c_int {
126
- self . 0
146
+ self . 0 . get ( )
127
147
}
128
148
129
149
#[ cfg( CONFIG_BLOCK ) ]
130
150
pub ( crate ) fn to_blk_status ( self ) -> bindings:: blk_status_t {
131
151
// SAFETY: `self.0` is a valid error due to its invariant.
132
- unsafe { bindings:: errno_to_blk_status ( self . 0 ) }
152
+ unsafe { bindings:: errno_to_blk_status ( self . 0 . get ( ) ) }
133
153
}
134
154
135
155
/// Returns the error encoded as a pointer.
136
156
pub fn to_ptr < T > ( self ) -> * mut T {
137
157
#[ cfg_attr( target_pointer_width = "32" , allow( clippy:: useless_conversion) ) ]
138
158
// SAFETY: `self.0` is a valid error due to its invariant.
139
159
unsafe {
140
- bindings:: ERR_PTR ( self . 0 . into ( ) ) as * mut _
160
+ bindings:: ERR_PTR ( self . 0 . get ( ) . into ( ) ) as * mut _
141
161
}
142
162
}
143
163
144
164
/// Returns a string representing the error, if one exists.
145
165
#[ cfg( not( testlib) ) ]
146
166
pub fn name ( & self ) -> Option < & ' static CStr > {
147
167
// SAFETY: Just an FFI call, there are no extra safety requirements.
148
- let ptr = unsafe { bindings:: errname ( -self . 0 ) } ;
168
+ let ptr = unsafe { bindings:: errname ( -self . 0 . get ( ) ) } ;
149
169
if ptr. is_null ( ) {
150
170
None
151
171
} else {
0 commit comments