mindustry logic execution, map- and schematic- parsing and rendering
-rw-r--r--src/block/fluid.rs4
-rw-r--r--src/block/logic.rs14
-rw-r--r--src/block/mod.rs21
-rw-r--r--src/block/payload.rs4
-rw-r--r--src/block/transport.rs6
-rw-r--r--src/data/base64.rs2
-rw-r--r--src/data/dynamic.rs8
-rw-r--r--src/data/mod.rs2
-rw-r--r--src/data/schematic.rs48
-rw-r--r--src/exe/args.rs3
-rw-r--r--src/exe/mod.rs25
-rw-r--r--src/exe/print.rs13
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;
},
}