mindustry logic execution, map- and schematic- parsing and rendering
Make all error types implement Error
| -rw-r--r-- | src/block/logic.rs | 4 | ||||
| -rw-r--r-- | src/block/mod.rs | 30 | ||||
| -rw-r--r-- | src/data/base64.rs | 5 | ||||
| -rw-r--r-- | src/data/dynamic.rs | 62 | ||||
| -rw-r--r-- | src/data/mod.rs | 40 | ||||
| -rw-r--r-- | src/data/schematic.rs | 61 | ||||
| -rw-r--r-- | src/exe/args.rs | 44 |
7 files changed, 232 insertions, 14 deletions
diff --git a/src/block/logic.rs b/src/block/logic.rs index e6338a6..aea9d47 100644 --- a/src/block/logic.rs +++ b/src/block/logic.rs @@ -319,7 +319,7 @@ impl fmt::Display for ProcessorDeserializeError { match self { - Self::Read(..) => write!(f, "Failed to read data from buffer"), + Self::Read(e) => e.fmt(f), Self::Decompress(e) => e.fmt(f), Self::DecompressStall => write!(f, "Decompressor stalled before completion"), Self::FromUtf8(e) => e.fmt(f), @@ -386,7 +386,7 @@ impl fmt::Display for ProcessorSerializeError { match self { - Self::Write(..) => write!(f, "Failed to write data to buffer"), + Self::Write(e) => e.fmt(f), Self::Compress(e) => e.fmt(f), Self::CompressEof(remain) => write!(f, "Compression overflow with {remain} bytes of input remaining"), Self::CompressStall => write!(f, "Compressor stalled before completion"), diff --git a/src/block/mod.rs b/src/block/mod.rs index 5b9643c..3699c41 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -46,7 +46,7 @@ pub enum DeserializeError impl DeserializeError { - pub fn filter<T, E: Error + 'static>(result: Result<T, E>) -> Result<T, Self> + pub fn forward<T, E: Error + 'static>(result: Result<T, E>) -> Result<T, Self> { match result { @@ -88,7 +88,7 @@ pub enum SerializeError impl SerializeError { - pub fn filter<T, E: Error + 'static>(result: Result<T, E>) -> Result<T, Self> + pub fn forward<T, E: Error + 'static>(result: Result<T, E>) -> Result<T, Self> { match result { @@ -169,6 +169,15 @@ impl Block } } +impl fmt::Debug for Block +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + let name: &str = &self.name; + write!(f, "Block {{ name: {:?} }}", name) + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Rotation { @@ -266,11 +275,11 @@ impl<'l> BlockRegistry<'l> Self{blocks: HashMap::new()} } - pub fn register(&mut self, block: &'l Block) -> Result<&'l Block, &'l Block> + pub fn register(&mut self, block: &'l Block) -> Result<&'l Block, RegisterError<'l>> { match self.blocks.entry(&block.name) { - Entry::Occupied(e) => Err(e.get()), + Entry::Occupied(e) => Err(RegisterError(e.get())), Entry::Vacant(e) => Ok(*e.insert(block)), } } @@ -281,6 +290,9 @@ impl<'l> BlockRegistry<'l> } } +#[derive(Clone, Copy, Debug)] +pub struct RegisterError<'l>(pub &'l Block); + impl<'l> AsRef<HashMap<&'l str, &'l Block>> for BlockRegistry<'l> { fn as_ref(&self) -> &HashMap<&'l str, &'l Block> @@ -289,6 +301,16 @@ impl<'l> AsRef<HashMap<&'l str, &'l Block>> for BlockRegistry<'l> } } +impl<'l> fmt::Display for RegisterError<'l> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Block {:?} already exists", self.0.get_name()) + } +} + +impl<'l> Error for RegisterError<'l> {} + macro_rules!make_register { ($($field:ident: $name:literal => $logic:expr;)+) => diff --git a/src/data/base64.rs b/src/data/base64.rs index 457d773..a0eb3dc 100644 --- a/src/data/base64.rs +++ b/src/data/base64.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::fmt; const CHARS: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -185,6 +186,8 @@ impl fmt::Display for DecodeError } } +impl Error for DecodeError {} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum EncodeError { @@ -202,6 +205,8 @@ impl fmt::Display for EncodeError } } +impl Error for EncodeError {} + #[cfg(test)] mod test { diff --git a/src/data/dynamic.rs b/src/data/dynamic.rs index 64616c3..7de97ff 100644 --- a/src/data/dynamic.rs +++ b/src/data/dynamic.rs @@ -1,3 +1,6 @@ +use std::error::Error; +use std::fmt; + use crate::data::{self, DataRead, DataWrite, GridPos, Serializer}; use crate::logic::LogicField; use crate::team::Team; @@ -439,6 +442,37 @@ impl From<data::ReadError> for ReadError } } +impl fmt::Display for ReadError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + ReadError::Underlying(e) => e.fmt(f), + ReadError::Type(id) => write!(f, "Invalid dynamic data type ({id})"), + ReadError::IntArrayLen(len) => write!(f, "Integer array too long ({len})"), + ReadError::Point2ArrayLen(len) => write!(f, "Point2 array too long ({len})"), + ReadError::LogicField(id) => write!(f, "Invalid logic field ({id})"), + ReadError::ByteArrayLen(len) => write!(f, "Byte array too long ({len})"), + ReadError::UnitCommand(id) => write!(f, "Invalid unit command ({id})"), + ReadError::BoolArrayLen(len) => write!(f, "Boolean array too long ({len})"), + ReadError::Vec2ArrayLen(len) => write!(f, "Vec2 array too long ({len})"), + } + } +} + +impl Error for ReadError +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + ReadError::Underlying(e) => Some(e), + _ => None, + } + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum WriteError { @@ -458,6 +492,34 @@ impl From<data::WriteError> for WriteError } } +impl fmt::Display for WriteError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + WriteError::Underlying(e) => e.fmt(f), + WriteError::IntArrayLen(len) => write!(f, "Integer array too long ({len})"), + WriteError::Point2ArrayLen(len) => write!(f, "Point2 array too long ({len})"), + WriteError::ByteArrayLen(len) => write!(f, "Byte array too long ({len})"), + WriteError::BoolArrayLen(len) => write!(f, "Boolean array too long ({len})"), + WriteError::Vec2ArrayLen(len) => write!(f, "Vec2 array too long ({len})"), + } + } +} + +impl Error for WriteError +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + WriteError::Underlying(e) => Some(e), + _ => None, + } + } +} + #[cfg(test)] mod test { diff --git a/src/data/mod.rs b/src/data/mod.rs index 6117cf8..e68200b 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,3 +1,5 @@ +use std::error::Error; +use std::fmt; use std::str::Utf8Error; pub mod base64; @@ -106,6 +108,30 @@ impl From<Utf8Error> for ReadError } } +impl fmt::Display for ReadError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + ReadError::Underflow{need, have} => write!(f, "Buffer underflow (expected {need} but got {have})"), + ReadError::Utf8(e) => e.fmt(f), + } + } +} + +impl Error for ReadError +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + ReadError::Utf8(e) => Some(e), + _ => None, + } + } +} + enum WriteBuff<'d> { // unlike the DataRead want to access the written region after @@ -229,6 +255,20 @@ pub enum WriteError TooLong{len: usize}, } +impl fmt::Display for WriteError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + WriteError::Overflow{need, have} => write!(f, "Buffer overflow (expected {need} but got {have})"), + WriteError::TooLong{len} => write!(f, "String too long ({len} bytes of {})", u16::MAX), + } + } +} + +impl Error for WriteError {} + impl<'d> From<&'d mut [u8]> for DataWrite<'d> { fn from(value: &'d mut [u8]) -> Self diff --git a/src/data/schematic.rs b/src/data/schematic.rs index 57173e9..d0928f1 100644 --- a/src/data/schematic.rs +++ b/src/data/schematic.rs @@ -454,6 +454,8 @@ impl fmt::Display for NewError } } +impl Error for NewError {} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct PosError { @@ -471,6 +473,8 @@ impl fmt::Display for PosError } } +impl Error for PosError {} + #[derive(Debug)] pub enum PlaceError { @@ -975,7 +979,7 @@ impl fmt::Display for ReadError { match self { - ReadError::Read(..) => write!(f, "Failed to read data from buffer"), + ReadError::Read(e) => e.fmt(f), ReadError::Header(hdr) => write!(f, "Incorrect header ({hdr:08X})"), ReadError::Version(ver) => write!(f, "Unsupported version ({ver})"), ReadError::Decompress(e) => e.fmt(f), @@ -985,12 +989,27 @@ impl fmt::Display for ReadError ReadError::NoSuchBlock(name) => write!(f, "Unknown block {name:?}"), ReadError::BlockCount(cnt) => write!(f, "Invalid total block count ({cnt})"), ReadError::BlockIndex(idx, cnt) => write!(f, "Invalid block index ({idx} / {cnt})"), - ReadError::BlockState(..) => write!(f, "Failed to read block state"), + ReadError::BlockState(e) => e.fmt(f), ReadError::Placement(e) => e.fmt(f), } } } +impl Error for ReadError +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + ReadError::Read(e) => Some(e), + ReadError::Decompress(e) => Some(e), + ReadError::BlockState(e) => Some(e), + ReadError::Placement(e) => Some(e), + _ => None, + } + } +} + #[derive(Debug)] pub enum WriteError { @@ -1054,6 +1073,20 @@ impl fmt::Display for WriteError } } +impl Error for WriteError +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + WriteError::Write(e) => Some(e), + WriteError::StateSerialize(e) => Some(e), + WriteError::Compress(e) => Some(e), + _ => None, + } + } +} + impl<'l> SchematicSerializer<'l> { pub fn deserialize_base64(&mut self, data: &str) -> Result<Schematic<'l>, R64Error> @@ -1116,6 +1149,18 @@ impl fmt::Display for R64Error } } +impl Error for R64Error +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + R64Error::Base64(e) => Some(e), + R64Error::Content(e) => Some(e), + } + } +} + #[derive(Debug)] pub enum W64Error { @@ -1151,6 +1196,18 @@ impl fmt::Display for W64Error } } +impl Error for W64Error +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + W64Error::Base64(e) => Some(e), + W64Error::Content(e) => Some(e), + } + } +} + pub struct PosIter { x: u16, diff --git a/src/exe/args.rs b/src/exe/args.rs index afd9e72..6e0742c 100644 --- a/src/exe/args.rs +++ b/src/exe/args.rs @@ -1,11 +1,12 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::error; use std::fmt; use std::slice::from_ref; pub trait ArgHandler { - type Error; + type Error: error::Error + 'static; fn on_literal(&mut self, name: &str) -> Result<(), Self::Error>; @@ -15,13 +16,13 @@ pub trait ArgHandler } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Error<E> +pub enum Error<E: error::Error + 'static> { Handler{pos: usize, val: E}, EmptyName{pos: usize}, } -impl<E: fmt::Display> fmt::Display for Error<E> +impl<E: error::Error + 'static> fmt::Display for Error<E> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -33,6 +34,18 @@ impl<E: fmt::Display> fmt::Display for Error<E> } } +impl<E: error::Error + 'static> error::Error for Error<E> +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> + { + match self + { + Error::Handler{pos: _, val} => Some(val), + _ => None, + } + } +} + pub fn parse<I: Iterator, H: ArgHandler>(args: &mut I, handler: &mut H, arg_off: usize) -> Result<bool, Error<H::Error>> where I::Item: AsRef<str> { @@ -269,13 +282,13 @@ impl OptionHandler Self{options: Vec::new(), short_map: HashMap::new(), long_map: HashMap::new(), literals: Vec::new()} } - pub fn add(&mut self, opt: ArgOption) -> Result<OptionRef, (ArgOption, &ArgOption)> + pub fn add(&mut self, opt: ArgOption) -> Result<OptionRef, AddArgError> { match opt.short { Some(c) => match self.short_map.get(&c) { - Some(&i) => return Err((opt, &self.options[i].0)), + Some(&i) => return Err(AddArgError{to_add: opt, existing: &self.options[i].0}), _ => (), }, _ => (), @@ -284,7 +297,7 @@ impl OptionHandler { Some(ref s) => match self.long_map.get(&**s) { - Some(&i) => return Err((opt, &self.options[i].0)), + Some(&i) => return Err(AddArgError{to_add: opt, existing: &self.options[i].0}), _ => (), }, _ => (), @@ -423,6 +436,23 @@ impl OptionHandler #[derive(Clone, Copy, Debug)] pub struct OptionRef(usize); +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AddArgError<'l> +{ + pub to_add: ArgOption, + pub existing: &'l ArgOption, +} + +impl<'l> fmt::Display for AddArgError<'l> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Duplicate argument {} (already have {})", self.to_add, self.existing) + } +} + +impl<'l> error::Error for AddArgError<'l> {} + impl ArgHandler for OptionHandler { type Error = OptionError; @@ -480,3 +510,5 @@ impl fmt::Display for OptionError } } } + +impl error::Error for OptionError {} |