mindustry logic execution, map- and schematic- parsing and rendering
Make all error types implement Error
KosmosPrime 2023-01-20
parent e6d70e7 · commit d078cf6
-rw-r--r--src/block/logic.rs4
-rw-r--r--src/block/mod.rs30
-rw-r--r--src/data/base64.rs5
-rw-r--r--src/data/dynamic.rs62
-rw-r--r--src/data/mod.rs40
-rw-r--r--src/data/schematic.rs61
-rw-r--r--src/exe/args.rs44
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 {}