1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
//! An [`Error`] trait based on [`std::error::Error`].
//!
//! This is a modified version of [`std::error::Error`] that doesn't require the
//! Rust standard library.
use core::{any::TypeId, fmt};
/// `Error` is a trait representing the basic expectations for error values,
/// i.e., values of type `E` in `Result<T, E>`.
///
/// This is essentially a re-implementation of the Rust standard library's
/// `std::error::Error` trait. Because we cannot use `std` in the kernel, we
/// must reimplement that trait in `mycelium_util`.
///
/// Errors must describe themselves through the `Display` and `Debug` traits,
/// and may provide cause chain information:
///
/// The [`source`] method is generally used when errors cross "abstraction
/// boundaries". If one module must report an error that is caused by an error
/// from a lower-level module, it can allow access to that error via the
/// [`source`] method. This makes it possible for the high-level module to
/// provide its own errors while also revealing some of the implementation for
/// debugging via [`source`] chains.
///
/// [`source`]: trait.Error.html#method.source
pub trait Error: fmt::Debug + fmt::Display {
/// The lower-level source of this error, if any.
///
/// This is equivalent to `std::error::Error`'s `source` method.
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
/// Gets the `TypeId` of `self`.
fn type_id(&self, _: private::Internal) -> TypeId
where
Self: 'static,
{
TypeId::of::<Self>()
}
}
impl dyn Error + 'static + Send {
/// Forwards to the method defined on the type `dyn Error`.
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
<dyn Error + 'static>::is::<T>(self)
}
/// Forwards to the method defined on the type `dyn Error`.
#[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
<dyn Error + 'static>::downcast_ref::<T>(self)
}
/// Forwards to the method defined on the type `dyn Error`.
#[inline]
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
<dyn Error + 'static>::downcast_mut::<T>(self)
}
}
impl dyn Error + 'static + Send + Sync {
/// Forwards to the method defined on the type `dyn Error`.
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
<dyn Error + 'static>::is::<T>(self)
}
/// Forwards to the method defined on the type `dyn Error`.
#[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
<dyn Error + 'static>::downcast_ref::<T>(self)
}
/// Forwards to the method defined on the type `dyn Error`.
#[inline]
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
<dyn Error + 'static>::downcast_mut::<T>(self)
}
}
impl dyn Error {
/// Returns an iterator starting with the current error and continuing with
/// recursively calling [`source`].
///
/// [`source`]: trait.Error.html#method.source
#[inline]
pub fn iter_chain(&self) -> ErrorIter<'_> {
ErrorIter {
current: Some(self),
}
}
/// Returns an iterator starting with the [`source`] of this error
/// and continuing with recursively calling [`source`].
///
/// [`source`]: trait.Error.html#method.source
#[inline]
pub fn iter_sources(&self) -> ErrorIter<'_> {
ErrorIter {
current: self.source(),
}
}
}
impl dyn Error + 'static {
/// Returns `true` if the boxed type is the same as `T`
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
// Get `TypeId` of the type this function is instantiated with.
let t = TypeId::of::<T>();
// Get `TypeId` of the type in the trait object.
let obj = self.type_id(private::Internal);
// Compare both `TypeId`s on equality.
t == obj
}
/// Returns some reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
#[inline]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe { Some(&*(self as *const dyn Error as *const T)) }
} else {
None
}
}
/// Returns some mutable reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
#[inline]
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) }
} else {
None
}
}
}
/// An iterator over [`Error`]
///
/// [`Error`]: trait.Error.html
#[derive(Copy, Clone, Debug)]
pub struct ErrorIter<'a> {
current: Option<&'a (dyn Error + 'static)>,
}
impl<'a> Iterator for ErrorIter<'a> {
type Item = &'a (dyn Error + 'static);
fn next(&mut self) -> Option<Self::Item> {
let current = self.current;
self.current = self.current.and_then(Error::source);
current
}
}
impl Error for &'static str {}
mod private {
// This is a hack to prevent `type_id` from being overridden by `Error`
// implementations, since that can enable unsound downcasting.
#[derive(Debug)]
pub struct Internal;
}