vex_rt/
error.rs

1//! Common error model.
2
3use alloc::{format, string::*};
4use core::{
5    fmt::{self, Debug, Display, Formatter},
6    num::TryFromIntError,
7};
8use cstring_interop::from_cstring_raw;
9
10use crate::bindings;
11
12/// Represents a runtime error.
13pub enum Error {
14    /// Represents a runtime error which comes from the underlying platform
15    /// (PROS, FreeRTOS, newlib, etc.). It wraps an `errno` value (i.e., system
16    /// error code).
17    System(i32),
18    /// Represents a runtime error which comes from within Rust. It wraps an
19    /// error string.
20    Custom(String),
21}
22
23impl From<rcstring::Error> for Error {
24    fn from(err: rcstring::Error) -> Self {
25        Error::Custom(format!("{:?}", err))
26    }
27}
28
29impl From<TryFromIntError> for Error {
30    fn from(err: TryFromIntError) -> Self {
31        Error::Custom(format!("{:?}", err))
32    }
33}
34
35impl<T> From<Error> for Result<T, Error> {
36    #[inline]
37    fn from(err: Error) -> Self {
38        Err(err)
39    }
40}
41
42impl Debug for Error {
43    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44        match self {
45            Error::System(n) => write!(f, "System({}) [{}]", n, unsafe {
46                from_cstring_raw(libc::strerror(*n))
47            }),
48            Error::Custom(s) => write!(f, "Custom({:?})", s),
49        }
50    }
51}
52
53impl Display for Error {
54    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
55        match self {
56            Error::System(n) => Display::fmt(unsafe { &from_cstring_raw(libc::strerror(*n)) }, f),
57            Error::Custom(s) => Display::fmt(s, f),
58        }
59    }
60}
61
62/// Represents a type which has some sentinel values which represent errors.
63///
64/// Implementations are provided for `i32` and `f64` based on PROS's sentinel
65/// error values, represented by `PROS_ERR` and `PROS_ERR_F` in C/C++.
66pub trait SentinelError: Sized {
67    /// Checks if the type is a valid (success value), giving an appropriate
68    /// error otherwise.
69    fn check(self) -> Result<Self, Error>;
70}
71
72impl SentinelError for i32 {
73    fn check(self) -> Result<Self, Error> {
74        if self == bindings::PROS_ERR_ {
75            Err(from_errno())
76        } else {
77            Ok(self)
78        }
79    }
80}
81
82impl SentinelError for f64 {
83    fn check(self) -> Result<Self, Error> {
84        if self == bindings::PROS_ERR_F_ {
85            Err(from_errno())
86        } else {
87            Ok(self)
88        }
89    }
90}
91
92impl<T> SentinelError for *mut T {
93    fn check(self) -> Result<Self, Error> {
94        if self.is_null() {
95            Err(from_errno())
96        } else {
97            Ok(self)
98        }
99    }
100}
101
102// Need to manually declare until https://github.com/rust-lang/libc/issues/1995 is resolved.
103extern "C" {
104    fn __errno() -> *mut i32;
105}
106
107/// Gets the value of `errno` for the current task.
108#[inline]
109pub fn get_errno() -> libc::c_int {
110    unsafe { *__errno() }
111}
112
113/// Generates an [`Error`] object from the value of `errno` for the current
114/// task.
115#[inline]
116pub fn from_errno() -> Error {
117    Error::System(get_errno())
118}