diff --git a/apis/leds/src/lib.rs b/apis/leds/src/lib.rs index 41e6d310..bfcd51f1 100644 --- a/apis/leds/src/lib.rs +++ b/apis/leds/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use libtock_platform::Syscalls; +use libtock_platform::{ErrorCode, Syscalls}; /// The LEDs driver /// @@ -9,30 +9,30 @@ use libtock_platform::Syscalls; /// use libtock2::Leds; /// /// // Turn on led 0 -/// Leds::on(0); +/// let _ = Leds::on(0); /// ``` pub struct Leds(S); impl Leds { /// Run a check against the leds capsule to ensure it is present. /// - /// Returns `Some(number_of_leds)` if the driver was present. This does not necessarily mean + /// Returns `Ok(number_of_leds)` if the driver was present. This does not necessarily mean /// that the driver is working, as it may still fail to allocate grant /// memory. - pub fn count() -> Option { - S::command(DRIVER_ID, LEDS_COUNT, 0, 0).get_success_u32() + pub fn count() -> Result { + S::command(DRIVER_ID, LEDS_COUNT, 0, 0).to_result() } - pub fn on(led: u32) { - S::command(DRIVER_ID, LED_ON, led, 0); + pub fn on(led: u32) -> Result<(), ErrorCode> { + S::command(DRIVER_ID, LED_ON, led, 0).to_result() } - pub fn off(led: u32) { - S::command(DRIVER_ID, LED_OFF, led, 0); + pub fn off(led: u32) -> Result<(), ErrorCode> { + S::command(DRIVER_ID, LED_OFF, led, 0).to_result() } - pub fn toggle(led: u32) { - S::command(DRIVER_ID, LED_TOGGLE, led, 0); + pub fn toggle(led: u32) -> Result<(), ErrorCode> { + S::command(DRIVER_ID, LED_TOGGLE, led, 0).to_result() } } diff --git a/apis/leds/src/tests.rs b/apis/leds/src/tests.rs index 44f28194..ea94005c 100644 --- a/apis/leds/src/tests.rs +++ b/apis/leds/src/tests.rs @@ -1,3 +1,4 @@ +use libtock_platform::ErrorCode; use libtock_unittest::fake; type Leds = super::Leds; @@ -5,7 +6,7 @@ type Leds = super::Leds; #[test] fn no_driver() { let _kernel = fake::Kernel::new(); - assert_eq!(Leds::count(), None); + assert_eq!(Leds::count(), Err(ErrorCode::NoDevice)); } #[test] @@ -14,7 +15,7 @@ fn driver_check() { let driver = fake::Leds::<10>::new(); kernel.add_driver(&driver); - assert!(Leds::count().is_some()); + assert_eq!(Leds::count(), Ok(10)); for led in 0..10 { assert_eq!(driver.get_led(led), Some(false)); } @@ -34,7 +35,7 @@ fn on() { let driver = fake::Leds::<10>::new(); kernel.add_driver(&driver); - Leds::on(0); + assert_eq!(Leds::on(0), Ok(())); assert_eq!(driver.get_led(0), Some(true)); } @@ -44,7 +45,7 @@ fn off() { let driver = fake::Leds::<10>::new(); kernel.add_driver(&driver); - Leds::off(0); + assert_eq!(Leds::off(0), Ok(())); assert_eq!(driver.get_led(0), Some(false)); } @@ -54,9 +55,9 @@ fn toggle() { let driver = fake::Leds::<10>::new(); kernel.add_driver(&driver); - Leds::toggle(0); + assert_eq!(Leds::toggle(0), Ok(())); assert_eq!(driver.get_led(0), Some(true)); - Leds::toggle(0); + assert_eq!(Leds::toggle(0), Ok(())); assert_eq!(driver.get_led(0), Some(false)); } @@ -66,9 +67,9 @@ fn on_off() { let driver = fake::Leds::<10>::new(); kernel.add_driver(&driver); - Leds::on(0); + assert_eq!(Leds::on(0), Ok(())); assert_eq!(driver.get_led(0), Some(true)); - Leds::off(0); + assert_eq!(Leds::off(0), Ok(())); assert_eq!(driver.get_led(0), Some(false)); } @@ -78,7 +79,7 @@ fn no_led() { let driver = fake::Leds::<10>::new(); kernel.add_driver(&driver); - Leds::on(11); + assert_eq!(Leds::on(11), Err(ErrorCode::Invalid)); for led in 0..Leds::count().unwrap_or_default() { assert_eq!(driver.get_led(led), Some(false)); } diff --git a/libtock2/examples/leds.rs b/libtock2/examples/leds.rs index 6f4a4748..5e67d352 100644 --- a/libtock2/examples/leds.rs +++ b/libtock2/examples/leds.rs @@ -10,9 +10,9 @@ set_main! {main} stack_size! {0x100} fn main() { - if let Some(leds_count) = Leds::count() { + if let Ok(leds_count) = Leds::count() { for led_index in 0..leds_count { - Leds::on(led_index as u32); + let _ = Leds::on(led_index as u32); } } } diff --git a/platform/src/command_return.rs b/platform/src/command_return.rs index df637eb6..e8284b10 100644 --- a/platform/src/command_return.rs +++ b/platform/src/command_return.rs @@ -2,8 +2,63 @@ use crate::{return_variant, ErrorCode, ReturnVariant}; use core::mem::transmute; -/// The response type from `command`. Can represent a successful value or a -/// failure. +/// The response type from the [`command`](crate::Syscalls::command) syscall. +/// Can represent a success or a failure with or without associated data. +/// +/// After a syscall is made, registers `r1`-`r3` contain the output as +/// described by [TRD 104][trd-104]. Some syscalls only return success/failure, +/// while others provide associated data. This is done by placing the _return +/// variant_ in `r0`, which specifies how the output registers should be +/// interpreted. For syscalls other than `command`, the possible output +/// variants are fixed; you always know which variants are expected given the +/// syscall class. +/// +/// However, the `command` syscall is flexible - there must be one success +/// variant and one failure variant for a given driver/command ID, but +/// which variants those are, and what data is expected, cannot be checked +/// statically. Capsules and userspace APIs must agree on the expected +/// variants for success and failure. +/// +/// # Example +/// +/// This uses the [`to_result`] method to implicitly check variants and convert +/// to a `Result`. +/// +/// ```ignore +/// let res: Result<(u32, u32), ErrorCode> = Syscalls::command(314, 1, 1, 2).to_result(); +/// match res { +/// Ok((val1, val2)) => { +/// // Success with associated data in val1, val2. +/// } +/// Err(ErrorCode::BadRVal) => { +/// // Incorrect return variant! We may choose to handle this +/// // explicitly or propagate upwards without branching. +/// } +/// Err(ec) => { +/// // The driver returned an error (or it doesn't exist). +/// } +/// } +/// ``` +/// +/// This uses the `get_*` methods to check the variants explicitly and extract +/// the associated data. +/// +/// ```ignore +/// let command_return = Syscalls::command(314, 1, 1, 2); +/// if let Some((val1, val2)) = command_return.get_success_2_u32() { +/// // If there was a success, there is an associated data (u32, u32). +/// } else if let Some(error_code) = command_return.get_failure() { +/// // If there was a failure, there's no associated data and we only +/// // have an error code. +/// } else { +/// // Incorrect return variant! If this occurs, your capsule and userspace +/// // API do not agree on what the return variants should be. +/// // An application may want to panic in this case to catch this early. +/// } +/// ``` +/// +/// [trd-104]: https://github.com/tock/tock/blob/master/doc/reference/trd104-syscalls.md#32-return-values +#[must_use = "this `CommandReturn` may represent an error, which should be handled"] #[derive(Clone, Copy, Debug)] pub struct CommandReturn { return_variant: ReturnVariant, @@ -26,16 +81,6 @@ impl CommandReturn { r3, } } - // I generally expect CommandReturn to be used with pattern matching, e.g.: - // - // let command_return = Syscalls::command(314, 1, 1, 2); - // if let Some((val1, val2)) = command_return.get_success_2_u32() { - // // ... - // } else if let Some(error_code) = command_return.get_failure() { - // // ... - // } else { - // // Incorrect return variant - // } /// Returns true if this CommandReturn is of type Failure. Note that this /// does not return true for other failure types, such as Failure with u32. @@ -177,4 +222,152 @@ impl CommandReturn { pub fn return_variant(&self) -> ReturnVariant { self.return_variant } + + /// Interprets this `CommandReturn` as a `Result`, checking the success and + /// failure variants, as well as extracting the relevant data. + /// + /// If neither the success or failure variants match what is required by + /// `T` and `E`, this function will return `Err(ErrorCode::BadRVal)`. + /// If `E` contains non-`ErrorCode` data in this case, the data will be 0. + /// + /// It is recommended to use type ascription or `::<>` to make the types + /// for `T` and `E` explicit at call-site. + pub fn to_result(self) -> Result + where + T: SuccessData, + E: FailureData, + { + let (return_variant, r1, mut r2, mut r3) = self.raw_values(); + if return_variant == T::RETURN_VARIANT { + return Ok(T::from_raw_values(r1, r2, r3)); + } + let ec: ErrorCode = if return_variant == E::RETURN_VARIANT { + // Safety: E::RETURN_VARIANT must be a failure variant, and + // failure variants must contain a valid ErrorCode in r1. + unsafe { core::mem::transmute(r1 as u16) } + } else { + r2 = 0; + r3 = 0; + ErrorCode::BadRVal + }; + Err(E::from_raw_values(ec, r2, r3)) + } +} + +mod sealed { + pub trait Sealed {} +} + +/// Output from a successful `command` syscall. +/// +/// This trait is [sealed], meaning foreign implementations cannot be defined, +/// even though it can be referenced by foreign crates. +/// +/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed +pub trait SuccessData: sealed::Sealed { + /// The return variant for this success type, stored in `r0` after + /// performing a `command` syscall. + const RETURN_VARIANT: ReturnVariant; + + /// Constructs the success data given the raw register values. + fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self; +} + +impl sealed::Sealed for () {} +impl SuccessData for () { + const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS; + + fn from_raw_values(_r1: u32, _r2: u32, _r3: u32) -> Self {} +} +impl sealed::Sealed for u32 {} +impl SuccessData for u32 { + const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U32; + + fn from_raw_values(r1: u32, _r2: u32, _r3: u32) -> Self { + r1 + } +} +impl sealed::Sealed for u64 {} +impl SuccessData for u64 { + const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U64; + + fn from_raw_values(r1: u32, r2: u32, _r3: u32) -> Self { + r1 as u64 | ((r2 as u64) << 32) + } +} +impl sealed::Sealed for (u32, u32) {} +impl SuccessData for (u32, u32) { + const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_2_U32; + + fn from_raw_values(r1: u32, r2: u32, _r3: u32) -> Self { + (r1, r2) + } +} +impl sealed::Sealed for (u32, u64) {} +impl SuccessData for (u32, u64) { + const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_U32_U64; + + fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self { + (r1, r2 as u64 | ((r3 as u64) << 32)) + } +} +impl sealed::Sealed for (u32, u32, u32) {} +impl SuccessData for (u32, u32, u32) { + const RETURN_VARIANT: ReturnVariant = return_variant::SUCCESS_3_U32; + + fn from_raw_values(r1: u32, r2: u32, r3: u32) -> Self { + (r1, r2, r3) + } +} + +/// Output from a failed `command` syscall. +/// +/// This trait is [sealed], meaning foreign implementations cannot be defined, +/// even though it can be referenced by foreign crates. +/// +/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed +pub unsafe trait FailureData: sealed::Sealed { + /// The return variant for this failure type, stored in `r0` after + /// performing a `command` syscall. + /// + /// # Safety + /// This must represent a failure variant, such that `r1` will always be + /// a valid [`ErrorCode`]. + const RETURN_VARIANT: ReturnVariant; + + /// Constructs the error data given the raw register values. + fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self; +} + +impl sealed::Sealed for ErrorCode {} +unsafe impl FailureData for ErrorCode { + const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE; + + fn from_raw_values(r1: ErrorCode, _r2: u32, _r3: u32) -> Self { + r1 + } +} +impl sealed::Sealed for (ErrorCode, u32) {} +unsafe impl FailureData for (ErrorCode, u32) { + const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_U32; + + fn from_raw_values(r1: ErrorCode, r2: u32, _r3: u32) -> Self { + (r1, r2) + } +} +impl sealed::Sealed for (ErrorCode, u32, u32) {} +unsafe impl FailureData for (ErrorCode, u32, u32) { + const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_2_U32; + + fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self { + (r1, r2, r3) + } +} +impl sealed::Sealed for (ErrorCode, u64) {} +unsafe impl FailureData for (ErrorCode, u64) { + const RETURN_VARIANT: ReturnVariant = return_variant::FAILURE_U64; + + fn from_raw_values(r1: ErrorCode, r2: u32, r3: u32) -> Self { + (r1, r2 as u64 | ((r3 as u64) << 32)) + } } diff --git a/platform/src/command_return_tests.rs b/platform/src/command_return_tests.rs index 80a563a1..6e719546 100644 --- a/platform/src/command_return_tests.rs +++ b/platform/src/command_return_tests.rs @@ -34,6 +34,22 @@ fn failure() { (return_variant::FAILURE, 5, 1002, 1003) ); assert_eq!(command_return.return_variant(), return_variant::FAILURE); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::Reserve) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32)>(), + Err((ErrorCode::BadRVal, 0)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32, u32)>(), + Err((ErrorCode::BadRVal, 0, 0)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u64)>(), + Err((ErrorCode::BadRVal, 0)) + ); } #[test] @@ -73,6 +89,22 @@ fn failure_u32() { (return_variant::FAILURE_U32, 4, 1002, 1003) ); assert_eq!(command_return.return_variant(), return_variant::FAILURE_U32); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32)>(), + Err((ErrorCode::Off, 1002)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32, u32)>(), + Err((ErrorCode::BadRVal, 0, 0)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u64)>(), + Err((ErrorCode::BadRVal, 0)) + ); } #[test] @@ -115,6 +147,22 @@ fn failure_2_u32() { command_return.return_variant(), return_variant::FAILURE_2_U32 ); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32)>(), + Err((ErrorCode::BadRVal, 0)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32, u32)>(), + Err((ErrorCode::Already, 1002, 1003)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u64)>(), + Err((ErrorCode::BadRVal, 0)) + ); } #[test] @@ -154,6 +202,22 @@ fn failure_u64() { (return_variant::FAILURE_U64, 2, 0x1002, 0x1003) ); assert_eq!(command_return.return_variant(), return_variant::FAILURE_U64); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32)>(), + Err((ErrorCode::BadRVal, 0)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u32, u32)>(), + Err((ErrorCode::BadRVal, 0, 0)) + ); + assert_eq!( + command_return.to_result::<(), (ErrorCode, u64)>(), + Err((ErrorCode::Busy, 0x0000_1003_0000_1002)) + ); } #[test] @@ -183,6 +247,27 @@ fn success() { (return_variant::SUCCESS, 1001, 1002, 1003) ); assert_eq!(command_return.return_variant(), return_variant::SUCCESS); + assert_eq!(command_return.to_result::<(), ErrorCode>(), Ok(())); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u64), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); } #[test] @@ -213,6 +298,27 @@ fn success_u32() { (return_variant::SUCCESS_U32, 1001, 1002, 1003) ); assert_eq!(command_return.return_variant(), return_variant::SUCCESS_U32); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!(command_return.to_result::(), Ok(1001)); + assert_eq!( + command_return.to_result::<(u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u64), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); } #[test] @@ -246,6 +352,30 @@ fn success_2_u32() { command_return.return_variant(), return_variant::SUCCESS_2_U32 ); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32), ErrorCode>(), + Ok((1001, 1002)) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u64), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); } #[test] @@ -279,6 +409,30 @@ fn success_u64() { (return_variant::SUCCESS_U64, 0x1001, 0x1002, 1003) ); assert_eq!(command_return.return_variant(), return_variant::SUCCESS_U64); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Ok(0x0000_1002_0000_1001) + ); + assert_eq!( + command_return.to_result::<(u32, u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u64), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); } #[test] @@ -312,6 +466,30 @@ fn success_3_u32() { command_return.return_variant(), return_variant::SUCCESS_3_U32 ); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32, u32), ErrorCode>(), + Ok((1001, 1002, 1003)) + ); + assert_eq!( + command_return.to_result::<(u32, u64), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); } #[test] @@ -348,4 +526,28 @@ fn success_u32_u64() { command_return.return_variant(), return_variant::SUCCESS_U32_U64 ); + assert_eq!( + command_return.to_result::<(), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u32, u32), ErrorCode>(), + Err(ErrorCode::BadRVal) + ); + assert_eq!( + command_return.to_result::<(u32, u64), ErrorCode>(), + Ok((1001, 0x0000_1003_0000_1002)) + ); } diff --git a/platform/src/error_code.rs b/platform/src/error_code.rs index d0b9e909..a9212ed6 100644 --- a/platform/src/error_code.rs +++ b/platform/src/error_code.rs @@ -1,9 +1,9 @@ use core::{convert::TryFrom, mem::transmute}; // TODO: Add a ufmt debug implementation for process binaries to use. -/// An error code the Tock kernel may return, as specified in -/// [TRD 104][error-codes]. Note that `BADRVAL` is not included, as it cannot be -/// produced by the Tock kernel. +/// An error code that libtock-rs APIs may return, as specified in +/// [TRD 104][error-codes]. Note that while `BADRVAL` can never be produced by +/// the kernel, it can be produced by userspace APIs. /// /// [error-codes]: https://github.com/tock/tock/blob/master/doc/reference/trd104-syscalls.md#33-error-codes #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -23,6 +23,7 @@ pub enum ErrorCode { NoDevice = 11, Uninstalled = 12, NoAck = 13, + BadRVal = 1024, // Error codes reserved for future use. We have to include these for future // compatibility -- this allows process binaries compiled with this version @@ -241,7 +242,7 @@ impl TryFrom for ErrorCode { type Error = NotAnErrorCode; fn try_from(value: u32) -> Result { - if (1..=1023).contains(&value) { + if (1..=1024).contains(&value) { Ok(unsafe { transmute(value as u16) }) } else { Err(NotAnErrorCode) diff --git a/platform/src/error_code_tests.rs b/platform/src/error_code_tests.rs index 870a8903..685cdae6 100644 --- a/platform/src/error_code_tests.rs +++ b/platform/src/error_code_tests.rs @@ -3,11 +3,11 @@ use core::convert::TryInto; use crate::{error_code::NotAnErrorCode, ErrorCode}; // Verifies that `ErrorCode` represents every valid value in the range -// [1, 1023]. +// [1, 1024]. #[cfg(miri)] #[test] fn error_code_range() { - for value in 1..=1023u16 { + for value in 1..=1024u16 { unsafe { *(&value as *const u16 as *const ErrorCode) }; } } @@ -15,8 +15,8 @@ fn error_code_range() { #[test] fn error_code_try_into() { assert_eq!(TryInto::::try_into(0u32), Err(NotAnErrorCode)); - for value in 1..=1023u32 { + for value in 1..=1024u32 { assert_eq!(value.try_into().map(|e: ErrorCode| e as u32), Ok(value)); } - assert_eq!(TryInto::::try_into(1024u32), Err(NotAnErrorCode)); + assert_eq!(TryInto::::try_into(1025u32), Err(NotAnErrorCode)); } diff --git a/platform/src/lib.rs b/platform/src/lib.rs index efa30abe..5c5de345 100644 --- a/platform/src/lib.rs +++ b/platform/src/lib.rs @@ -3,7 +3,7 @@ pub mod allow_ro; pub mod allow_rw; -mod command_return; +pub mod command_return; mod constants; mod default_config; mod error_code;