Something went wrong. Try again.
A fork of pulp-os for the xteink4 adding custom apps
Something went wrong. Try again.
8.2 kB · 286 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287// unified error type for pulp-os//// single Copy type carrying ErrorKind (what) and a &'static str// source tag (where); smol-epub boundary converts via From impls
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]#[non_exhaustive]pub enum ErrorKind { // storage / sd card NoCard, OpenVolume, OpenDir, OpenFile, ReadFailed, WriteFailed, SeekFailed, DeleteFailed, DirFull, NotFound,
// data / parsing ParseFailed, InvalidData, BadEncoding,
// resources OutOfMemory, BufferTooSmall,
// network (upload) NetworkIo, Protocol,
// catch-all Other,}
impl ErrorKind { pub const fn as_str(self) -> &'static str { match self { Self::NoCard => "no sd card", Self::OpenVolume => "open volume failed", Self::OpenDir => "open dir failed", Self::OpenFile => "open file failed", Self::ReadFailed => "read failed", Self::WriteFailed => "write failed", Self::SeekFailed => "seek failed", Self::DeleteFailed => "delete failed", Self::DirFull => "directory full", Self::NotFound => "not found", Self::ParseFailed => "parse failed", Self::InvalidData => "invalid data", Self::BadEncoding => "bad encoding", Self::OutOfMemory => "out of memory", Self::BufferTooSmall => "buffer too small", Self::NetworkIo => "network error", Self::Protocol => "protocol error", Self::Other => "error", } }
pub const fn is_storage(self) -> bool { matches!( self, Self::NoCard | Self::OpenVolume | Self::OpenDir | Self::OpenFile | Self::ReadFailed | Self::WriteFailed | Self::SeekFailed | Self::DeleteFailed | Self::DirFull | Self::NotFound ) }}
impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) }}
// one discriminant byte + one &'static str pointer; cheap to copy// source is module_path!() or a short caller-supplied tag#[derive(Clone, Copy)]pub struct Error { kind: ErrorKind, source: &'static str,}
impl Error { #[inline] pub const fn new(kind: ErrorKind, source: &'static str) -> Self { Self { kind, source } }
#[inline] pub const fn from_kind(kind: ErrorKind) -> Self { Self { kind, source: "" } }
pub const NO_CARD: Self = Self::from_kind(ErrorKind::NoCard); pub const OPEN_VOLUME: Self = Self::from_kind(ErrorKind::OpenVolume); pub const OPEN_DIR: Self = Self::from_kind(ErrorKind::OpenDir); pub const OPEN_FILE: Self = Self::from_kind(ErrorKind::OpenFile); pub const READ_FAILED: Self = Self::from_kind(ErrorKind::ReadFailed); pub const WRITE_FAILED: Self = Self::from_kind(ErrorKind::WriteFailed); pub const SEEK_FAILED: Self = Self::from_kind(ErrorKind::SeekFailed); pub const DELETE_FAILED: Self = Self::from_kind(ErrorKind::DeleteFailed); pub const DIR_FULL: Self = Self::from_kind(ErrorKind::DirFull); pub const NOT_FOUND: Self = Self::from_kind(ErrorKind::NotFound);}
impl Error { #[inline] pub const fn kind(&self) -> ErrorKind { self.kind }
#[inline] pub const fn source_tag(&self) -> &'static str { self.source }
#[inline] pub const fn with_source(self, source: &'static str) -> Self { Self { kind: self.kind, source, } }
#[inline] pub const fn with_kind(self, kind: ErrorKind) -> Self { Self { kind, source: self.source, } }
#[inline] pub const fn has_source(&self) -> bool { !self.source.is_empty() }
#[inline] pub const fn is_storage(&self) -> bool { self.kind.is_storage() }
#[inline] pub const fn as_str(&self) -> &'static str { self.kind.as_str() }}
impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.source.is_empty() { write!(f, "Error({:?})", self.kind) } else { write!(f, "Error({:?} @ {:?})", self.kind, self.source) } }}
impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.source.is_empty() { f.write_str(self.kind.as_str()) } else { write!(f, "{} [{}]", self.kind.as_str(), self.source) } }}
// equality is semantic: kind only, source is diagnosticimpl PartialEq for Error { #[inline] fn eq(&self, other: &Self) -> bool { self.kind == other.kind }}
impl Eq for Error {}
// wrap &'static str (smol-epub returns) into Error; well-known// strings map to the appropriate kind, rest becomes Otherimpl From<&'static str> for Error { #[inline] fn from(msg: &'static str) -> Self { let kind = match msg { "read failed" | "read local header failed" => ErrorKind::ReadFailed, "write failed" => ErrorKind::WriteFailed, "read error" | "read error during upload" => ErrorKind::NetworkIo, "no sd card" => ErrorKind::NoCard, "not found" | "OPF not found" | "no filename in upload" => ErrorKind::NotFound, "too small" | "CD truncated" | "cache file too small" => ErrorKind::InvalidData, "CD too large" | "OOM for cached image" => ErrorKind::OutOfMemory, "bad OPF path" | "bad encoding" | "filename encoding error" => ErrorKind::BadEncoding, "parse failed" | "no title in OPF" => ErrorKind::ParseFailed, "boundary too long" | "part headers too large" | "invalid filename" | "upload incomplete" | "connection closed during headers" => ErrorKind::Protocol, _ => ErrorKind::Other, }; Self { kind, source: msg } }}
// project back to &'static str for the smol-epub trait boundaryimpl From<Error> for &'static str { #[inline] fn from(e: Error) -> &'static str { if e.source.is_empty() { e.kind.as_str() } else { e.source } }}
// ergonomic source tagging on Result<T, Error> and// Result<T, &'static str> (smol-epub returns)pub trait ResultExt<T> { fn source(self, src: &'static str) -> Result<T>; fn map_kind(self, kind: ErrorKind, src: &'static str) -> Result<T>;}
impl<T> ResultExt<T> for Result<T> { #[inline] fn source(self, src: &'static str) -> Result<T> { self.map_err(|e| e.with_source(src)) }
#[inline] fn map_kind(self, kind: ErrorKind, src: &'static str) -> Result<T> { self.map_err(|_| Error::new(kind, src)) }}
impl<T> ResultExt<T> for core::result::Result<T, &'static str> { #[inline] fn source(self, src: &'static str) -> Result<T> { self.map_err(|msg| Error::from(msg).with_source(src)) }
#[inline] fn map_kind(self, kind: ErrorKind, src: &'static str) -> Result<T> { self.map_err(|_| Error::new(kind, src)) }}
// create an Error with module_path!() as source// err!(ReadFailed)// err!(OpenFile, "epub_init_zip")#[macro_export]macro_rules! err { ($kind:ident) => { $crate::error::Error::new($crate::error::ErrorKind::$kind, module_path!()) }; ($kind:ident, $src:expr) => { $crate::error::Error::new($crate::error::ErrorKind::$kind, $src) };}
// map any Result<T, _> into an Error of the given kind// or_err!(mgr.read(file, buf).await, ReadFailed)#[macro_export]macro_rules! or_err { ($result:expr, $kind:ident) => { ($result) .map_err(|_| $crate::error::Error::new($crate::error::ErrorKind::$kind, module_path!())) }; ($result:expr, $kind:ident, $src:expr) => { ($result).map_err(|_| $crate::error::Error::new($crate::error::ErrorKind::$kind, $src)) };}
pub type Result<T> = core::result::Result<T, Error>;