mindustry logic execution, map- and schematic- parsing and rendering
Print errors with more information
| -rw-r--r-- | src/block/fluid.rs | 4 | ||||
| -rw-r--r-- | src/block/logic.rs | 14 | ||||
| -rw-r--r-- | src/block/mod.rs | 21 | ||||
| -rw-r--r-- | src/block/payload.rs | 4 | ||||
| -rw-r--r-- | src/block/transport.rs | 6 | ||||
| -rw-r--r-- | src/data/base64.rs | 2 | ||||
| -rw-r--r-- | src/data/dynamic.rs | 8 | ||||
| -rw-r--r-- | src/data/mod.rs | 2 | ||||
| -rw-r--r-- | src/data/schematic.rs | 48 | ||||
| -rw-r--r-- | src/exe/args.rs | 3 | ||||
| -rw-r--r-- | src/exe/mod.rs | 25 | ||||
| -rw-r--r-- | src/exe/print.rs | 13 |
12 files changed, 93 insertions, 57 deletions
diff --git a/src/block/fluid.rs b/src/block/fluid.rs index a9f1349..9f57ff0 100644 --- a/src/block/fluid.rs +++ b/src/block/fluid.rs @@ -81,7 +81,7 @@ impl BlockLogic for FluidBlock { if config < 0 || config > u16::MAX as i32 { - return Err(DataConvertError(Box::new(FluidConvertError(config)))); + return Err(DataConvertError::Custom(Box::new(FluidConvertError(config)))); } Ok(DynData::Content(content::Type::Fluid, config as u16)) } @@ -160,7 +160,7 @@ impl fmt::Display for FluidDeserializeError match self { Self::ContentType(have) => write!(f, "expected content {:?} but got {have:?}", content::Type::Fluid), - Self::NotFound(e) => e.fmt(f), + Self::NotFound(..) => f.write_str("fluid not found"), } } } diff --git a/src/block/logic.rs b/src/block/logic.rs index 9e13e5c..4946bdb 100644 --- a/src/block/logic.rs +++ b/src/block/logic.rs @@ -401,10 +401,10 @@ impl fmt::Display for ProcessorDeserializeError { match self { - 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), + Self::Read(..) => f.write_str("failed to read state data"), + Self::Decompress(..) => f.write_str("zlib decompression failed"), + Self::DecompressStall => f.write_str("decompressor stalled before completion"), + Self::FromUtf8(..) => f.write_str("malformed utf-8 in processor code"), Self::Version(ver) => write!(f, "unsupported version ({ver})"), Self::CodeLength(len) => write!(f, "invalid code length ({len})"), Self::LinkCount(cnt) => write!(f, "invalid link count ({cnt})"), @@ -468,10 +468,10 @@ impl fmt::Display for ProcessorSerializeError { match self { - Self::Write(e) => e.fmt(f), - Self::Compress(e) => e.fmt(f), + Self::Write(..) => f.write_str("failed to write state data"), + Self::Compress(..) => f.write_str("zlib compression failed"), Self::CompressEof(remain) => write!(f, "compression overflow with {remain} bytes of input remaining"), - Self::CompressStall => write!(f, "compressor stalled before completion"), + Self::CompressStall => f.write_str("compressor stalled before completion"), } } } diff --git a/src/block/mod.rs b/src/block/mod.rs index 9bed114..5efb269 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -41,7 +41,10 @@ pub trait BlockLogic } #[derive(Debug)] -pub struct DataConvertError(pub Box<dyn Error>); +pub enum DataConvertError +{ + Custom(Box<dyn Error>), +} impl DataConvertError { @@ -50,7 +53,7 @@ impl DataConvertError match result { Ok(v) => Ok(v), - Err(e) => Err(Self(Box::new(e))), + Err(e) => Err(Self::Custom(Box::new(e))), } } } @@ -59,7 +62,10 @@ impl fmt::Display for DataConvertError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + match self + { + Self::Custom(e) => e.fmt(f), + } } } @@ -67,7 +73,10 @@ impl Error for DataConvertError { fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(self.0.as_ref()) + match self + { + Self::Custom(e) => e.source(), + } } } @@ -108,7 +117,7 @@ impl Error for DeserializeError { match self { - Self::Custom(e) => Some(e.as_ref()), + Self::Custom(e) => e.source(), _ => None, } } @@ -149,7 +158,7 @@ impl Error for SerializeError { match self { - Self::Custom(e) => Some(e.as_ref()), + Self::Custom(e) => e.source(), } } } diff --git a/src/block/payload.rs b/src/block/payload.rs index e302770..164c0bb 100644 --- a/src/block/payload.rs +++ b/src/block/payload.rs @@ -315,8 +315,8 @@ impl fmt::Display for PayloadDeserializeError match self { Self::ContentType(have) => write!(f, "expected content {:?} or {:?} but got {have:?}", content::Type::Block, content::Type::Unit), - Self::BlockNotFound(e) => e.fmt(f), - Self::UnitNotFound(e) => e.fmt(f), + Self::BlockNotFound(..) => f.write_str("payload block not found"), + Self::UnitNotFound(..) => f.write_str("payload unit not found"), } } } diff --git a/src/block/transport.rs b/src/block/transport.rs index e2b4384..f1e8dae 100644 --- a/src/block/transport.rs +++ b/src/block/transport.rs @@ -82,7 +82,7 @@ impl BlockLogic for ItemBlock { if config < 0 || config > u16::MAX as i32 { - return Err(DataConvertError(Box::new(ItemConvertError(config)))); + return Err(DataConvertError::Custom(Box::new(ItemConvertError(config)))); } Ok(DynData::Content(content::Type::Item, config as u16)) } @@ -161,7 +161,7 @@ impl fmt::Display for ItemDeserializeError match self { Self::ContentType(have) => write!(f, "expected content {:?} but got {have:?}", content::Type::Item), - Self::NotFound(e) => e.fmt(f), + Self::NotFound(..) => f.write_str("target item not found"), } } } @@ -238,7 +238,7 @@ impl BlockLogic for BridgeBlock let (x, y) = ((config >> 16) as i16, config as i16); if x < 0 || y < 0 { - return Err(DataConvertError(Box::new(BridgeConvertError{x, y}))); + return Err(DataConvertError::Custom(Box::new(BridgeConvertError{x, y}))); } let dx = x as i32 - pos.0 as i32; let dy = y as i32 - pos.1 as i32; diff --git a/src/data/base64.rs b/src/data/base64.rs index b1c14e7..ccd27ff 100644 --- a/src/data/base64.rs +++ b/src/data/base64.rs @@ -180,7 +180,7 @@ impl fmt::Display for DecodeError { Self::Malformed{at, value} => write!(f, "malformed base64 character {value:?} (at {at})"), Self::Overflow{need, have} => write!(f, "decoder overflow (need {need}, but only have {have})"), - Self::Truncated => write!(f, "truncated base64 input stream"), + Self::Truncated => f.write_str("truncated base64 input stream"), Self::TrailingData{at} => write!(f, "trailing data in base64 stream (at {at})"), } } diff --git a/src/data/dynamic.rs b/src/data/dynamic.rs index 7f89f1d..874dc6b 100644 --- a/src/data/dynamic.rs +++ b/src/data/dynamic.rs @@ -425,14 +425,14 @@ impl fmt::Display for ReadError { match self { - Self::Underlying(e) => e.fmt(f), + Self::Underlying(..) => f.write_str("failed to read from buffer"), Self::Type(id) => write!(f, "invalid dynamic data type ({id})"), - Self::ContentType(e) => e.fmt(f), + Self::ContentType(..) => f.write_str("content type not found"), Self::IntArrayLen(len) => write!(f, "integer array too long ({len})"), Self::Point2ArrayLen(len) => write!(f, "point2 array too long ({len})"), Self::LogicField(id) => write!(f, "invalid logic field ({id})"), Self::ByteArrayLen(len) => write!(f, "byte array too long ({len})"), - Self::UnitCommand(e) => e.fmt(f), + Self::UnitCommand(..) => f.write_str("unit command not found"), Self::BoolArrayLen(len) => write!(f, "boolean array too long ({len})"), Self::Vec2ArrayLen(len) => write!(f, "vec2 array too long ({len})"), } @@ -476,7 +476,7 @@ impl fmt::Display for WriteError { match self { - Self::Underlying(e) => e.fmt(f), + Self::Underlying(..) => f.write_str("failed to write to buffer"), Self::IntArrayLen(len) => write!(f, "integer array too long ({len})"), Self::Point2ArrayLen(len) => write!(f, "point2 array too long ({len})"), Self::ByteArrayLen(len) => write!(f, "byte array too long ({len})"), diff --git a/src/data/mod.rs b/src/data/mod.rs index 0cc2104..b8ab386 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -116,7 +116,7 @@ impl fmt::Display for ReadError match self { Self::Underflow{need, have} => write!(f, "buffer underflow (expected {need} but got {have})"), - Self::Utf8(e) => e.fmt(f), + Self::Utf8(..) => f.write_str("malformed utf-8 in string"), } } } diff --git a/src/data/schematic.rs b/src/data/schematic.rs index 0b9f9a0..65f5575 100644 --- a/src/data/schematic.rs +++ b/src/data/schematic.rs @@ -514,9 +514,9 @@ impl fmt::Display for PlaceError { match self { - Self::Bounds{x, y, sz, w, h} => write!(f, "block placement {x} / {y} (size {sz}) within {w} / {h}"), + Self::Bounds{x, y, sz, w, h} => write!(f, "invalid block placement {x} / {y} (size {sz}) within {w} / {h}"), Self::Overlap{x, y} => write!(f, "overlapping an existing block at {x} / {y}"), - Self::Deserialize(e) => e.fmt(f), + Self::Deserialize(..) => f.write_str("block state deserialization failed"), } } } @@ -955,7 +955,7 @@ pub enum ReadError BlockCount(i32), BlockIndex(i8, usize), BlockConfig(block::DataConvertError), - BlockState(dynamic::ReadError), + ReadState(dynamic::ReadError), Placement(PlaceError), } @@ -979,7 +979,7 @@ impl From<dynamic::ReadError> for ReadError { fn from(value: dynamic::ReadError) -> Self { - Self::BlockState(value) + Self::ReadState(value) } } @@ -1005,19 +1005,19 @@ impl fmt::Display for ReadError { match self { - Self::Read(e) => e.fmt(f), + Self::Read(..) => f.write_str("failed to read from buffer"), Self::Header(hdr) => write!(f, "incorrect header ({hdr:08X})"), Self::Version(ver) => write!(f, "unsupported version ({ver})"), - Self::Decompress(e) => e.fmt(f), - Self::DecompressStall => write!(f, "decompressor stalled before completion"), + Self::Decompress(..) => f.write_str("zlib decompression failed"), + Self::DecompressStall => f.write_str("decompressor stalled before completion"), Self::Dimensions(w, h) => write!(f, "invalid schematic dimensions ({w} * {h})"), Self::TableSize(cnt) => write!(f, "invalid block table size ({cnt})"), Self::NoSuchBlock(name) => write!(f, "unknown block {name:?}"), Self::BlockCount(cnt) => write!(f, "invalid total block count ({cnt})"), Self::BlockIndex(idx, cnt) => write!(f, "invalid block index ({idx} / {cnt})"), - Self::BlockConfig(e) => e.fmt(f), - Self::BlockState(e) => e.fmt(f), - Self::Placement(e) => e.fmt(f), + Self::BlockConfig(..) => f.write_str("block config conversion failed"), + Self::ReadState(..) => f.write_str("failed to read block data"), + Self::Placement(..) => f.write_str("deserialized block could not be placed"), } } } @@ -1031,7 +1031,7 @@ impl Error for ReadError Self::Read(e) => Some(e), Self::Decompress(e) => Some(e), Self::BlockConfig(e) => Some(e), - Self::BlockState(e) => Some(e), + Self::ReadState(e) => Some(e), Self::Placement(e) => Some(e), _ => None, } @@ -1045,7 +1045,7 @@ pub enum WriteError TagCount(usize), TableSize(usize), StateSerialize(block::SerializeError), - BlockState(dynamic::WriteError), + WriteState(dynamic::WriteError), Compress(CompressError), CompressEof(usize), CompressStall, @@ -1079,7 +1079,7 @@ impl From<dynamic::WriteError> for WriteError { fn from(value: dynamic::WriteError) -> Self { - Self::BlockState(value) + Self::WriteState(value) } } @@ -1089,14 +1089,14 @@ impl fmt::Display for WriteError { match self { - Self::Write(..) => write!(f, "failed to write data to buffer"), - Self::TagCount(cnt) => write!(f, "invalid tag count ({cnt})"), - Self::TableSize(cnt) => write!(f, "invalid block table size ({cnt})"), + Self::Write(..) => f.write_str("failed to write data to buffer"), + Self::TagCount(len) => write!(f, "tag list too long ({len})"), + Self::TableSize(len) => write!(f, "block table too long ({len})"), Self::StateSerialize(e) => e.fmt(f), - Self::BlockState(..) => write!(f, "failed to write block state"), - Self::Compress(e) => e.fmt(f), + Self::WriteState(..) => f.write_str("failed to write block data"), + Self::Compress(..) => f.write_str("zlib compression failed"), Self::CompressEof(remain) => write!(f, "compression overflow with {remain} bytes of input remaining"), - Self::CompressStall => write!(f, "compressor stalled before completion"), + Self::CompressStall => f.write_str("compressor stalled before completion"), } } } @@ -1108,7 +1108,7 @@ impl Error for WriteError match self { Self::Write(e) => Some(e), - Self::StateSerialize(e) => Some(e), + Self::StateSerialize(e) => e.source(), Self::Compress(e) => Some(e), _ => None, } @@ -1171,7 +1171,7 @@ impl fmt::Display for R64Error { match self { - Self::Base64(e) => e.fmt(f), + Self::Base64(..) => f.write_str("base-64 decoding failed"), Self::Content(e) => e.fmt(f), } } @@ -1184,7 +1184,7 @@ impl Error for R64Error match self { Self::Base64(e) => Some(e), - Self::Content(e) => Some(e), + Self::Content(e) => e.source(), } } } @@ -1218,7 +1218,7 @@ impl fmt::Display for W64Error { match self { - Self::Base64(e) => e.fmt(f), + Self::Base64(..) => f.write_str("base-64 encoding failed"), Self::Content(e) => e.fmt(f), } } @@ -1231,7 +1231,7 @@ impl Error for W64Error match self { Self::Base64(e) => Some(e), - Self::Content(e) => Some(e), + Self::Content(e) => e.source(), } } } diff --git a/src/exe/args.rs b/src/exe/args.rs index 1c83c63..c3843b8 100644 --- a/src/exe/args.rs +++ b/src/exe/args.rs @@ -40,7 +40,8 @@ impl<E: error::Error + 'static> error::Error for Error<E> { match self { - Self::Handler{pos: _, val} => Some(val), + // forward past the inner error because we decorate it in our Display impl + Self::Handler{val, ..} => val.source(), _ => None, } } diff --git a/src/exe/mod.rs b/src/exe/mod.rs index e5f6760..dfa0365 100644 --- a/src/exe/mod.rs +++ b/src/exe/mod.rs @@ -3,6 +3,31 @@ use std::env::Args; pub mod args; pub mod print; +macro_rules!print_err +{ + ($err:expr, $($msg:tt)*) => + { + { + use std::error::Error; + + let err = $err; + eprint!($($msg)*); + eprintln!(": {err}"); + let mut err_ref = &err as &dyn Error; + loop + { + if let Some(next) = err_ref.source() + { + eprintln!("\tSource: {next}"); + err_ref = next; + } + else {break;} + } + } + }; +} +pub(crate) use print_err; + pub fn main(mut args: Args) { match args.next() diff --git a/src/exe/print.rs b/src/exe/print.rs index 1cafc56..78876ce 100644 --- a/src/exe/print.rs +++ b/src/exe/print.rs @@ -6,6 +6,7 @@ use std::fs; use crate::block::build_registry; use crate::data::{DataRead, Serializer}; use crate::data::schematic::{Schematic, SchematicSerializer}; +use crate::exe::print_err; use crate::exe::args::{self, ArgCount, ArgOption, OptionHandler}; pub fn main(mut args: Args, arg_off: usize) @@ -15,7 +16,7 @@ pub fn main(mut args: Args, arg_off: usize) let opt_interact = handler.add(ArgOption::new(Some('i'), Some(Cow::Borrowed("interactive")), ArgCount::Forbidden)).unwrap(); if let Err(e) = args::parse(&mut args, &mut handler, arg_off) { - println!("Command error: {e}"); + print_err!(e, "Command error"); return; } @@ -51,7 +52,7 @@ pub fn main(mut args: Args, arg_off: usize) if need_space {println!();} first = false; need_space = false; - println!("Could not read schematic: {e}"); + print_err!(e, "Could not read schematic from {path}"); }, } }, @@ -61,7 +62,7 @@ pub fn main(mut args: Args, arg_off: usize) if need_space {println!();} first = false; need_space = false; - println!("Could not read file {path:?}: {e}"); + print_err!(e, "Could not read file {path:?}"); }, } } @@ -87,7 +88,7 @@ pub fn main(mut args: Args, arg_off: usize) if need_space {println!();} first = false; need_space = false; - println!("Could not read schematic: {e}"); + print_err!(e, "Could not read schematic"); }, } } @@ -129,14 +130,14 @@ pub fn main(mut args: Args, arg_off: usize) { if need_space {println!();} need_space = false; - println!("Could not read schematic: {e:?}") + print_err!(e, "Could not read schematic"); }, } }, Err(e) => { if need_space {println!();} - println!("Failed to read next line: {e}"); + print_err!(e, "Failed to read next schematic"); break; }, } |