|
6 | 6 |
|
7 | 7 | use crate::{bindings, c_types};
|
8 | 8 | use alloc::{alloc::AllocError, collections::TryReserveError};
|
| 9 | +use core::convert::From; |
9 | 10 | use core::{num::TryFromIntError, str::Utf8Error};
|
10 | 11 |
|
11 | 12 | /// Generic integer kernel error.
|
@@ -104,3 +105,50 @@ impl From<AllocError> for Error {
|
104 | 105 | Error::ENOMEM
|
105 | 106 | }
|
106 | 107 | }
|
| 108 | + |
| 109 | +// # Invariant: `-bindings::MAX_ERRNO` fits in an `i16`. |
| 110 | +crate::static_assert!(bindings::MAX_ERRNO <= -(i16::MIN as i32) as u32); |
| 111 | + |
| 112 | +#[doc(hidden)] |
| 113 | +pub fn from_kernel_result_helper<T>(r: Result<T>) -> T |
| 114 | +where |
| 115 | + T: From<i16>, |
| 116 | +{ |
| 117 | + match r { |
| 118 | + Ok(v) => v, |
| 119 | + // NO-OVERFLOW: negative `errno`s are no smaller than `-bindings::MAX_ERRNO`, |
| 120 | + // `-bindings::MAX_ERRNO` fits in an `i16` as per invariant above, |
| 121 | + // therefore a negative `errno` always fits in an `i16` and will not overflow. |
| 122 | + Err(e) => T::from(e.to_kernel_errno() as i16), |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +/// Transforms a [`crate::error::Result<T>`] to a kernel C integer result. |
| 127 | +/// |
| 128 | +/// This is useful when calling Rust functions that return [`crate::error::Result<T>`] |
| 129 | +/// from inside `extern "C"` functions that need to return an integer |
| 130 | +/// error result. |
| 131 | +/// |
| 132 | +/// `T` should be convertible to an `i16` via `From<i16>`. |
| 133 | +/// |
| 134 | +/// # Examples |
| 135 | +/// |
| 136 | +/// ```rust,no_run |
| 137 | +/// unsafe extern "C" fn probe_callback( |
| 138 | +/// pdev: *mut bindings::platform_device, |
| 139 | +/// ) -> c_types::c_int { |
| 140 | +/// from_kernel_result! { |
| 141 | +/// let ptr = devm_alloc(pdev)?; |
| 142 | +/// rust_helper_platform_set_drvdata(pdev, ptr); |
| 143 | +/// Ok(0) |
| 144 | +/// } |
| 145 | +/// } |
| 146 | +/// ``` |
| 147 | +#[macro_export] |
| 148 | +macro_rules! from_kernel_result { |
| 149 | + ($($tt:tt)*) => {{ |
| 150 | + $crate::error::from_kernel_result_helper((|| { |
| 151 | + $($tt)* |
| 152 | + })()) |
| 153 | + }}; |
| 154 | +} |
0 commit comments