mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/block/logic.rs')
-rw-r--r--src/block/logic.rs1129
1 files changed, 534 insertions, 595 deletions
diff --git a/src/block/logic.rs b/src/block/logic.rs
index 879c8b3..ccfd8a0 100644
--- a/src/block/logic.rs
+++ b/src/block/logic.rs
@@ -4,675 +4,614 @@ use std::error::Error;
use std::fmt;
use std::string::FromUtf8Error;
-use flate2::{Compress, CompressError, Compression, Decompress, DecompressError, FlushCompress, FlushDecompress, Status};
+use flate2::{
+ Compress, CompressError, Compression, Decompress, DecompressError, FlushCompress,
+ FlushDecompress, Status,
+};
-use crate::block::{BlockLogic, DataConvertError, DeserializeError, make_register, SerializeError};
-use crate::block::simple::{BuildCost, cost, SimpleBlock, state_impl};
-use crate::data::{self, DataRead, DataWrite, GridPos};
+use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock};
+use crate::block::{make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError};
use crate::data::dynamic::{DynData, DynType};
+use crate::data::{self, DataRead, DataWrite, GridPos};
use crate::item::storage::Storage;
make_register!
(
- MESSAGE: "message" => MessageLogic::new(1, true, cost!(Copper: 5, Graphite: 5));
- SWITCH: "switch" => SwitchLogic::new(1, true, cost!(Copper: 5, Graphite: 5));
- MICRO_PROCESSOR: "micro-processor" => ProcessorLogic::new(1, true, cost!(Copper: 90, Lead: 50, Silicon: 50));
- LOGIC_PROCESSOR: "logic-processor" => ProcessorLogic::new(2, true, cost!(Lead: 320, Graphite: 60, Thorium: 50, Silicon: 80));
- HYPER_PROCESSOR: "hyper-processor" => ProcessorLogic::new(3, true, cost!(Lead: 450, Thorium: 75, Silicon: 150, SurgeAlloy: 50));
- MEMORY_CELL: "memory-cell" => SimpleBlock::new(1, true, cost!(Copper: 30, Graphite: 30, Silicon: 30));
- MEMORY_BANK: "memory-bank" => SimpleBlock::new(2, true, cost!(Copper: 30, Graphite: 80, Silicon: 80, PhaseFabric: 30));
- LOGIC_DISPLAY: "logic-display" => SimpleBlock::new(3, true, cost!(Lead: 100, Metaglass: 50, Silicon: 50));
- LARGE_LOGIC_DISPLAY: "large-logic-display" => SimpleBlock::new(6, true, cost!(Lead: 200, Metaglass: 100, Silicon: 150, PhaseFabric: 75));
+ "message" => MessageLogic::new(1, true, cost!(Copper: 5, Graphite: 5));
+ "switch" => SwitchLogic::new(1, true, cost!(Copper: 5, Graphite: 5));
+ "micro-processor" => ProcessorLogic::new(1, true, cost!(Copper: 90, Lead: 50, Silicon: 50));
+ "logic-processor" => ProcessorLogic::new(2, true, cost!(Lead: 320, Graphite: 60, Thorium: 50, Silicon: 80));
+ "hyper-processor" => ProcessorLogic::new(3, true, cost!(Lead: 450, Thorium: 75, Silicon: 150, SurgeAlloy: 50));
+ "memory-cell" => SimpleBlock::new(1, true, cost!(Copper: 30, Graphite: 30, Silicon: 30));
+ "memory-bank" => SimpleBlock::new(2, true, cost!(Copper: 30, Graphite: 80, Silicon: 80, PhaseFabric: 30));
+ "logic-display" => SimpleBlock::new(3, true, cost!(Lead: 100, Metaglass: 50, Silicon: 50));
+ "large-logic-display" => SimpleBlock::new(6, true, cost!(Lead: 200, Metaglass: 100, Silicon: 150, PhaseFabric: 75));
);
-pub struct MessageLogic
-{
- size: u8,
- symmetric: bool,
- build_cost: BuildCost,
+pub struct MessageLogic {
+ size: u8,
+ symmetric: bool,
+ build_cost: BuildCost,
}
-impl MessageLogic
-{
- pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self
- {
- if size == 0
- {
- panic!("invalid size");
- }
- Self{size, symmetric, build_cost}
- }
-
- state_impl!(pub String);
+impl MessageLogic {
+ pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self {
+ if size == 0 {
+ panic!("invalid size");
+ }
+ Self {
+ size,
+ symmetric,
+ build_cost,
+ }
+ }
+
+ state_impl!(pub String);
}
-impl BlockLogic for MessageLogic
-{
- fn get_size(&self) -> u8
- {
- self.size
- }
-
- fn is_symmetric(&self) -> bool
- {
- self.symmetric
- }
-
- fn create_build_cost(&self) -> Option<Storage>
- {
- if !self.build_cost.is_empty()
- {
- let mut storage = Storage::new();
- for (ty, cnt) in self.build_cost
- {
- storage.add(*ty, *cnt, u32::MAX);
- }
- Some(storage)
- }
- else {None}
- }
-
- fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError>
- {
- Ok(DynData::Empty)
- }
-
- fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError>
- {
- match data
- {
- DynData::Empty | DynData::String(None) => Ok(Some(Self::create_state(String::new()))),
- DynData::String(Some(s)) => Ok(Some(Self::create_state(s))),
- _ => Err(DeserializeError::InvalidType{have: data.get_type(), expect: DynType::String}),
- }
- }
-
- fn clone_state(&self, state: &dyn Any) -> Box<dyn Any>
- {
- Box::new(Self::get_state(state).clone())
- }
-
- fn mirror_state(&self, _: &mut dyn Any, _: bool, _: bool)
- {
- }
-
- fn rotate_state(&self, _: &mut dyn Any, _: bool)
- {
- }
-
- fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError>
- {
- Ok(DynData::String(Some(Self::get_state(state).clone())))
- }
+impl BlockLogic for MessageLogic {
+ fn get_size(&self) -> u8 {
+ self.size
+ }
+
+ fn is_symmetric(&self) -> bool {
+ self.symmetric
+ }
+
+ fn create_build_cost(&self) -> Option<Storage> {
+ if !self.build_cost.is_empty() {
+ let mut storage = Storage::new();
+ for (ty, cnt) in self.build_cost {
+ storage.add(*ty, *cnt, u32::MAX);
+ }
+ Some(storage)
+ } else {
+ None
+ }
+ }
+
+ fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> {
+ Ok(DynData::Empty)
+ }
+
+ fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError> {
+ match data {
+ DynData::Empty | DynData::String(None) => Ok(Some(Self::create_state(String::new()))),
+ DynData::String(Some(s)) => Ok(Some(Self::create_state(s))),
+ _ => Err(DeserializeError::InvalidType {
+ have: data.get_type(),
+ expect: DynType::String,
+ }),
+ }
+ }
+
+ fn clone_state(&self, state: &dyn Any) -> Box<dyn Any> {
+ Box::new(Self::get_state(state).clone())
+ }
+
+ fn mirror_state(&self, _: &mut dyn Any, _: bool, _: bool) {}
+
+ fn rotate_state(&self, _: &mut dyn Any, _: bool) {}
+
+ fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError> {
+ Ok(DynData::String(Some(Self::get_state(state).clone())))
+ }
}
-pub struct SwitchLogic
-{
- size: u8,
- symmetric: bool,
- build_cost: BuildCost,
+pub struct SwitchLogic {
+ size: u8,
+ symmetric: bool,
+ build_cost: BuildCost,
}
-impl SwitchLogic
-{
- pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self
- {
- if size == 0
- {
- panic!("invalid size");
- }
- Self{size, symmetric, build_cost}
- }
-
- state_impl!(pub bool);
+impl SwitchLogic {
+ pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self {
+ if size == 0 {
+ panic!("invalid size");
+ }
+ Self {
+ size,
+ symmetric,
+ build_cost,
+ }
+ }
+
+ state_impl!(pub bool);
}
-impl BlockLogic for SwitchLogic
-{
- fn get_size(&self) -> u8
- {
- self.size
- }
-
- fn is_symmetric(&self) -> bool
- {
- self.symmetric
- }
-
- fn create_build_cost(&self) -> Option<Storage>
- {
- if !self.build_cost.is_empty()
- {
- let mut storage = Storage::new();
- for (ty, cnt) in self.build_cost
- {
- storage.add(*ty, *cnt, u32::MAX);
- }
- Some(storage)
- }
- else {None}
- }
-
- fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError>
- {
- Ok(DynData::Empty)
- }
-
- fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError>
- {
- match data
- {
- DynData::Empty => Ok(Some(Self::create_state(true))),
- DynData::Boolean(enabled) => Ok(Some(Self::create_state(enabled))),
- _ => Err(DeserializeError::InvalidType{have: data.get_type(), expect: DynType::Boolean}),
- }
- }
-
- fn clone_state(&self, state: &dyn Any) -> Box<dyn Any>
- {
- Box::new(Self::get_state(state).clone())
- }
-
- fn mirror_state(&self, _: &mut dyn Any, _: bool, _: bool)
- {
- }
-
- fn rotate_state(&self, _: &mut dyn Any, _: bool)
- {
- }
-
- fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError>
- {
- Ok(DynData::Boolean(*Self::get_state(state)))
- }
+impl BlockLogic for SwitchLogic {
+ fn get_size(&self) -> u8 {
+ self.size
+ }
+
+ fn is_symmetric(&self) -> bool {
+ self.symmetric
+ }
+
+ fn create_build_cost(&self) -> Option<Storage> {
+ if !self.build_cost.is_empty() {
+ let mut storage = Storage::new();
+ for (ty, cnt) in self.build_cost {
+ storage.add(*ty, *cnt, u32::MAX);
+ }
+ Some(storage)
+ } else {
+ None
+ }
+ }
+
+ fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> {
+ Ok(DynData::Empty)
+ }
+
+ fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError> {
+ match data {
+ DynData::Empty => Ok(Some(Self::create_state(true))),
+ DynData::Boolean(enabled) => Ok(Some(Self::create_state(enabled))),
+ _ => Err(DeserializeError::InvalidType {
+ have: data.get_type(),
+ expect: DynType::Boolean,
+ }),
+ }
+ }
+
+ fn clone_state(&self, state: &dyn Any) -> Box<dyn Any> {
+ Box::new(Self::get_state(state).clone())
+ }
+
+ fn mirror_state(&self, _: &mut dyn Any, _: bool, _: bool) {}
+
+ fn rotate_state(&self, _: &mut dyn Any, _: bool) {}
+
+ fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError> {
+ Ok(DynData::Boolean(*Self::get_state(state)))
+ }
}
-pub struct ProcessorLogic
-{
- size: u8,
- symmetric: bool,
- build_cost: BuildCost,
+pub struct ProcessorLogic {
+ size: u8,
+ symmetric: bool,
+ build_cost: BuildCost,
}
-impl ProcessorLogic
-{
- pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self
- {
- if size == 0
- {
- panic!("invalid size");
- }
- Self{size, symmetric, build_cost}
- }
-
- state_impl!(pub ProcessorState);
+impl ProcessorLogic {
+ pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self {
+ if size == 0 {
+ panic!("invalid size");
+ }
+ Self {
+ size,
+ symmetric,
+ build_cost,
+ }
+ }
+
+ state_impl!(pub ProcessorState);
}
-impl BlockLogic for ProcessorLogic
-{
- fn get_size(&self) -> u8
- {
- self.size
- }
-
- fn is_symmetric(&self) -> bool
- {
- self.symmetric
- }
-
- fn create_build_cost(&self) -> Option<Storage>
- {
- if !self.build_cost.is_empty()
- {
- let mut storage = Storage::new();
- for (ty, cnt) in self.build_cost
- {
- storage.add(*ty, *cnt, u32::MAX);
- }
- Some(storage)
- }
- else {None}
- }
-
- fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError>
- {
- Ok(DynData::Empty)
- }
-
- fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError>
- {
- match data
- {
- DynData::Empty => Ok(Some(Self::create_state(ProcessorState::new()))),
- DynData::ByteArray(arr) =>
- {
- let mut input = arr.as_ref();
- let mut dec = Decompress::new(true);
- let mut raw = Vec::<u8>::new();
- raw.reserve(1024);
- loop
- {
- let t_in = dec.total_in();
- let t_out = dec.total_out();
- let res = ProcessorDeserializeError::forward(dec.decompress_vec(input, &mut raw, FlushDecompress::Finish))?;
- if dec.total_in() > t_in
- {
- // we have to advance input every time, decompress_vec only knows the output position
- input = &input[(dec.total_in() - t_in) as usize..];
- }
- match res
- {
- // there's no more input (and the flush mode says so), we need to reserve additional space
- Status::Ok | Status::BufError => (),
- // input was already at the end, so this is referring to the output
- Status::StreamEnd => break,
- }
- if dec.total_in() == t_in && dec.total_out() == t_out
- {
- // protect against looping forever
- return Err(DeserializeError::Custom(Box::new(ProcessorDeserializeError::DecompressStall)));
- }
- raw.reserve(1024);
- }
- let mut buff = DataRead::new(&raw);
- let ver = ProcessorDeserializeError::forward(buff.read_u8())?;
- if ver != 1
- {
- return Err(DeserializeError::Custom(Box::new(ProcessorDeserializeError::Version(ver))));
- }
-
- let code_len = ProcessorDeserializeError::forward(buff.read_i32())?;
- if code_len < 0 || code_len > 500 * 1024
- {
- return Err(DeserializeError::Custom(Box::new(ProcessorDeserializeError::CodeLength(code_len))));
- }
- let mut code = Vec::<u8>::new();
- code.resize(code_len as usize, 0);
- ProcessorDeserializeError::forward(buff.read_bytes(&mut code))?;
- let code = ProcessorDeserializeError::forward(String::from_utf8(code))?;
- let link_cnt = ProcessorDeserializeError::forward(buff.read_i32())?;
- if link_cnt < 0
- {
- return Err(DeserializeError::Custom(Box::new(ProcessorDeserializeError::LinkCount(link_cnt))));
- }
- let mut links = Vec::<ProcessorLink>::new();
- links.reserve(link_cnt as usize);
- for _ in 0..link_cnt
- {
- let name = ProcessorDeserializeError::forward(buff.read_utf())?;
- let x = ProcessorDeserializeError::forward(buff.read_i16())?;
- let y = ProcessorDeserializeError::forward(buff.read_i16())?;
- links.push(ProcessorLink{name: String::from(name), x, y});
- }
- Ok(Some(Self::create_state(ProcessorState{code, links})))
- },
- _ => Err(DeserializeError::InvalidType{have: data.get_type(), expect: DynType::Boolean}),
- }
- }
-
- fn clone_state(&self, state: &dyn Any) -> Box<dyn Any>
- {
- Box::new(Self::get_state(state).clone())
- }
-
- fn mirror_state(&self, state: &mut dyn Any, horizontally: bool, vertically: bool)
- {
- for link in Self::get_state_mut(state).links.iter_mut()
- {
- if horizontally {link.x = -link.x;}
- if vertically {link.y = -link.y;}
- }
- }
-
- fn rotate_state(&self, state: &mut dyn Any, clockwise: bool)
- {
- for link in Self::get_state_mut(state).links.iter_mut()
- {
- let (cdx, cdy) = link.get_pos();
- link.x = if clockwise {cdy} else {-cdy};
- link.y = if clockwise {-cdx} else {cdx};
- }
- }
-
- fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError>
- {
- let state = Self::get_state(state);
- let mut rbuff = DataWrite::new();
- ProcessorSerializeError::forward(rbuff.write_u8(1))?;
- assert!(state.code.len() < 500 * 1024);
- ProcessorSerializeError::forward(rbuff.write_i32(state.code.len() as i32))?;
- ProcessorSerializeError::forward(rbuff.write_bytes(state.code.as_bytes()))?;
- assert!(state.links.len() < i32::MAX as usize);
- ProcessorSerializeError::forward(rbuff.write_i32(state.links.len() as i32))?;
- for link in state.links.iter()
- {
- ProcessorSerializeError::forward(rbuff.write_utf(&link.name))?;
- ProcessorSerializeError::forward(rbuff.write_i16(link.x))?;
- ProcessorSerializeError::forward(rbuff.write_i16(link.y))?;
- }
- let mut input = rbuff.get_written();
- let mut comp = Compress::new(Compression::default(), true);
- let mut dst = Vec::<u8>::new();
- dst.reserve(1024);
- loop
- {
- let t_in = comp.total_in();
- let t_out = comp.total_out();
- let res = ProcessorSerializeError::forward(comp.compress_vec(input, &mut dst, FlushCompress::Finish))?;
- if comp.total_in() > t_in
- {
- // we have to advance input every time, compress_vec only knows the output position
- input = &input[(comp.total_in() - t_in) as usize..];
- }
- match res
- {
- // there's no more input (and the flush mode says so), we need to reserve additional space
- Status::Ok | Status::BufError => (),
- // input was already at the end, so this is referring to the output
- Status::StreamEnd => break,
- }
- if comp.total_in() == t_in && comp.total_out() == t_out
- {
- // protect against looping forever
- return Err(SerializeError::Custom(Box::new(ProcessorSerializeError::CompressStall)));
- }
- dst.reserve(1024);
- }
- Ok(DynData::ByteArray(dst))
- }
+impl BlockLogic for ProcessorLogic {
+ fn get_size(&self) -> u8 {
+ self.size
+ }
+
+ fn is_symmetric(&self) -> bool {
+ self.symmetric
+ }
+
+ fn create_build_cost(&self) -> Option<Storage> {
+ if !self.build_cost.is_empty() {
+ let mut storage = Storage::new();
+ for (ty, cnt) in self.build_cost {
+ storage.add(*ty, *cnt, u32::MAX);
+ }
+ Some(storage)
+ } else {
+ None
+ }
+ }
+
+ fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> {
+ Ok(DynData::Empty)
+ }
+
+ fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError> {
+ match data {
+ DynData::Empty => Ok(Some(Self::create_state(ProcessorState::new()))),
+ DynData::ByteArray(arr) => {
+ let mut input = arr.as_ref();
+ let mut dec = Decompress::new(true);
+ let mut raw = Vec::<u8>::new();
+ raw.reserve(1024);
+ loop {
+ let t_in = dec.total_in();
+ let t_out = dec.total_out();
+ let res = ProcessorDeserializeError::forward(dec.decompress_vec(
+ input,
+ &mut raw,
+ FlushDecompress::Finish,
+ ))?;
+ if dec.total_in() > t_in {
+ // we have to advance input every time, decompress_vec only knows the output position
+ input = &input[(dec.total_in() - t_in) as usize..];
+ }
+ match res {
+ // there's no more input (and the flush mode says so), we need to reserve additional space
+ Status::Ok | Status::BufError => (),
+ // input was already at the end, so this is referring to the output
+ Status::StreamEnd => break,
+ }
+ if dec.total_in() == t_in && dec.total_out() == t_out {
+ // protect against looping forever
+ return Err(DeserializeError::Custom(Box::new(
+ ProcessorDeserializeError::DecompressStall,
+ )));
+ }
+ raw.reserve(1024);
+ }
+ let mut buff = DataRead::new(&raw);
+ let ver = ProcessorDeserializeError::forward(buff.read_u8())?;
+ if ver != 1 {
+ return Err(DeserializeError::Custom(Box::new(
+ ProcessorDeserializeError::Version(ver),
+ )));
+ }
+
+ let code_len = ProcessorDeserializeError::forward(buff.read_i32())?;
+ if code_len < 0 || code_len > 500 * 1024 {
+ return Err(DeserializeError::Custom(Box::new(
+ ProcessorDeserializeError::CodeLength(code_len),
+ )));
+ }
+ let mut code = Vec::<u8>::new();
+ code.resize(code_len as usize, 0);
+ ProcessorDeserializeError::forward(buff.read_bytes(&mut code))?;
+ let code = ProcessorDeserializeError::forward(String::from_utf8(code))?;
+ let link_cnt = ProcessorDeserializeError::forward(buff.read_i32())?;
+ if link_cnt < 0 {
+ return Err(DeserializeError::Custom(Box::new(
+ ProcessorDeserializeError::LinkCount(link_cnt),
+ )));
+ }
+ let mut links = Vec::<ProcessorLink>::new();
+ links.reserve(link_cnt as usize);
+ for _ in 0..link_cnt {
+ let name = ProcessorDeserializeError::forward(buff.read_utf())?;
+ let x = ProcessorDeserializeError::forward(buff.read_i16())?;
+ let y = ProcessorDeserializeError::forward(buff.read_i16())?;
+ links.push(ProcessorLink {
+ name: String::from(name),
+ x,
+ y,
+ });
+ }
+ Ok(Some(Self::create_state(ProcessorState { code, links })))
+ }
+ _ => Err(DeserializeError::InvalidType {
+ have: data.get_type(),
+ expect: DynType::Boolean,
+ }),
+ }
+ }
+
+ fn clone_state(&self, state: &dyn Any) -> Box<dyn Any> {
+ Box::new(Self::get_state(state).clone())
+ }
+
+ fn mirror_state(&self, state: &mut dyn Any, horizontally: bool, vertically: bool) {
+ for link in Self::get_state_mut(state).links.iter_mut() {
+ if horizontally {
+ link.x = -link.x;
+ }
+ if vertically {
+ link.y = -link.y;
+ }
+ }
+ }
+
+ fn rotate_state(&self, state: &mut dyn Any, clockwise: bool) {
+ for link in Self::get_state_mut(state).links.iter_mut() {
+ let (cdx, cdy) = link.get_pos();
+ link.x = if clockwise { cdy } else { -cdy };
+ link.y = if clockwise { -cdx } else { cdx };
+ }
+ }
+
+ fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError> {
+ let state = Self::get_state(state);
+ let mut rbuff = DataWrite::new();
+ ProcessorSerializeError::forward(rbuff.write_u8(1))?;
+ assert!(state.code.len() < 500 * 1024);
+ ProcessorSerializeError::forward(rbuff.write_i32(state.code.len() as i32))?;
+ ProcessorSerializeError::forward(rbuff.write_bytes(state.code.as_bytes()))?;
+ assert!(state.links.len() < i32::MAX as usize);
+ ProcessorSerializeError::forward(rbuff.write_i32(state.links.len() as i32))?;
+ for link in state.links.iter() {
+ ProcessorSerializeError::forward(rbuff.write_utf(&link.name))?;
+ ProcessorSerializeError::forward(rbuff.write_i16(link.x))?;
+ ProcessorSerializeError::forward(rbuff.write_i16(link.y))?;
+ }
+ let mut input = rbuff.get_written();
+ let mut comp = Compress::new(Compression::default(), true);
+ let mut dst = Vec::<u8>::new();
+ dst.reserve(1024);
+ loop {
+ let t_in = comp.total_in();
+ let t_out = comp.total_out();
+ let res = ProcessorSerializeError::forward(comp.compress_vec(
+ input,
+ &mut dst,
+ FlushCompress::Finish,
+ ))?;
+ if comp.total_in() > t_in {
+ // we have to advance input every time, compress_vec only knows the output position
+ input = &input[(comp.total_in() - t_in) as usize..];
+ }
+ match res {
+ // there's no more input (and the flush mode says so), we need to reserve additional space
+ Status::Ok | Status::BufError => (),
+ // input was already at the end, so this is referring to the output
+ Status::StreamEnd => break,
+ }
+ if comp.total_in() == t_in && comp.total_out() == t_out {
+ // protect against looping forever
+ return Err(SerializeError::Custom(Box::new(
+ ProcessorSerializeError::CompressStall,
+ )));
+ }
+ dst.reserve(1024);
+ }
+ Ok(DynData::ByteArray(dst))
+ }
}
#[derive(Debug)]
-pub enum ProcessorDeserializeError
-{
- Read(data::ReadError),
- Decompress(DecompressError),
- DecompressStall,
- FromUtf8(FromUtf8Error),
- Version(u8),
- CodeLength(i32),
- LinkCount(i32),
+pub enum ProcessorDeserializeError {
+ Read(data::ReadError),
+ Decompress(DecompressError),
+ DecompressStall,
+ FromUtf8(FromUtf8Error),
+ Version(u8),
+ CodeLength(i32),
+ LinkCount(i32),
}
-impl ProcessorDeserializeError
-{
- pub fn forward<T, E: Into<Self>>(result: Result<T, E>) -> Result<T, DeserializeError>
- {
- match result
- {
- Ok(v) => Ok(v),
- Err(e) => Err(DeserializeError::Custom(Box::new(e.into()))),
- }
- }
+impl ProcessorDeserializeError {
+ pub fn forward<T, E: Into<Self>>(result: Result<T, E>) -> Result<T, DeserializeError> {
+ match result {
+ Ok(v) => Ok(v),
+ Err(e) => Err(DeserializeError::Custom(Box::new(e.into()))),
+ }
+ }
}
-impl From<data::ReadError> for ProcessorDeserializeError
-{
- fn from(value: data::ReadError) -> Self
- {
- Self::Read(value)
- }
+impl From<data::ReadError> for ProcessorDeserializeError {
+ fn from(value: data::ReadError) -> Self {
+ Self::Read(value)
+ }
}
-impl From<DecompressError> for ProcessorDeserializeError
-{
- fn from(value: DecompressError) -> Self
- {
- Self::Decompress(value)
- }
+impl From<DecompressError> for ProcessorDeserializeError {
+ fn from(value: DecompressError) -> Self {
+ Self::Decompress(value)
+ }
}
-impl From<FromUtf8Error> for ProcessorDeserializeError
-{
- fn from(value: FromUtf8Error) -> Self
- {
- Self::FromUtf8(value)
- }
+impl From<FromUtf8Error> for ProcessorDeserializeError {
+ fn from(value: FromUtf8Error) -> Self {
+ Self::FromUtf8(value)
+ }
}
-impl fmt::Display for ProcessorDeserializeError
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
- {
- match self
- {
- 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})"),
- }
- }
+impl fmt::Display for ProcessorDeserializeError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ 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})"),
+ }
+ }
}
-impl Error for ProcessorDeserializeError
-{
- fn source(&self) -> Option<&(dyn Error + 'static)>
- {
- match self
- {
- Self::Decompress(e) => Some(e),
- Self::FromUtf8(e) => Some(e),
- _ => None,
- }
- }
+impl Error for ProcessorDeserializeError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::Decompress(e) => Some(e),
+ Self::FromUtf8(e) => Some(e),
+ _ => None,
+ }
+ }
}
#[derive(Debug)]
-pub enum ProcessorSerializeError
-{
- Write(data::WriteError),
- Compress(CompressError),
- CompressEof(usize),
- CompressStall,
+pub enum ProcessorSerializeError {
+ Write(data::WriteError),
+ Compress(CompressError),
+ CompressEof(usize),
+ CompressStall,
}
-impl ProcessorSerializeError
-{
- pub fn forward<T, E: Into<Self>>(result: Result<T, E>) -> Result<T, SerializeError>
- {
- match result
- {
- Ok(v) => Ok(v),
- Err(e) => Err(SerializeError::Custom(Box::new(e.into()))),
- }
- }
+impl ProcessorSerializeError {
+ pub fn forward<T, E: Into<Self>>(result: Result<T, E>) -> Result<T, SerializeError> {
+ match result {
+ Ok(v) => Ok(v),
+ Err(e) => Err(SerializeError::Custom(Box::new(e.into()))),
+ }
+ }
}
-impl From<data::WriteError> for ProcessorSerializeError
-{
- fn from(value: data::WriteError) -> Self
- {
- Self::Write(value)
- }
+impl From<data::WriteError> for ProcessorSerializeError {
+ fn from(value: data::WriteError) -> Self {
+ Self::Write(value)
+ }
}
-impl From<CompressError> for ProcessorSerializeError
-{
- fn from(value: CompressError) -> Self
- {
- Self::Compress(value)
- }
+impl From<CompressError> for ProcessorSerializeError {
+ fn from(value: CompressError) -> Self {
+ Self::Compress(value)
+ }
}
-impl fmt::Display for ProcessorSerializeError
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
- {
- match self
- {
- 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 => f.write_str("compressor stalled before completion"),
- }
- }
+impl fmt::Display for ProcessorSerializeError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ 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 => f.write_str("compressor stalled before completion"),
+ }
+ }
}
-impl Error for ProcessorSerializeError
-{
- fn source(&self) -> Option<&(dyn Error + 'static)>
- {
- match self
- {
- Self::Compress(e) => Some(e),
- _ => None,
- }
- }
+impl Error for ProcessorSerializeError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::Compress(e) => Some(e),
+ _ => None,
+ }
+ }
}
#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct ProcessorLink
-{
- name: String,
- x: i16,
- y: i16,
+pub struct ProcessorLink {
+ name: String,
+ x: i16,
+ y: i16,
}
-impl ProcessorLink
-{
- pub fn new(name: Cow<'_, str>, x: i16, y: i16) -> Self
- {
- if name.len() > u16::MAX as usize
- {
- panic!("name too long ({})", name.len());
- }
- Self{name: name.into_owned(), x, y}
- }
-
- pub fn get_name(&self) -> &str
- {
- &self.name
- }
-
- pub fn get_pos(&self) -> (i16, i16)
- {
- (self.x, self.y)
- }
+impl ProcessorLink {
+ pub fn new(name: Cow<'_, str>, x: i16, y: i16) -> Self {
+ if name.len() > u16::MAX as usize {
+ panic!("name too long ({})", name.len());
+ }
+ Self {
+ name: name.into_owned(),
+ x,
+ y,
+ }
+ }
+
+ pub fn get_name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn get_pos(&self) -> (i16, i16) {
+ (self.x, self.y)
+ }
}
#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct ProcessorState
-{
- code: String,
- links: Vec<ProcessorLink>
+pub struct ProcessorState {
+ code: String,
+ links: Vec<ProcessorLink>,
}
-impl ProcessorState
-{
- pub fn new() -> Self
- {
- Self{code: String::new(), links: Vec::new()}
- }
-
- pub fn get_code(&self) -> &str
- {
- &self.code
- }
-
- pub fn set_code(&mut self, code: Cow<'_, str>) -> Result<(), CodeError>
- {
- let as_str = &code as &str;
- if as_str.len() > 500 * 1024
- {
- return Err(CodeError::TooLong(as_str.len()));
- }
- match code
- {
- Cow::Borrowed(s) =>
- {
- self.code.clear();
- self.code.push_str(s);
- },
- Cow::Owned(s) => self.code = s,
- }
- Ok(())
- }
-
- pub fn get_links(&self) -> &[ProcessorLink]
- {
- &self.links
- }
-
- pub fn create_link(&mut self, mut name: String, x: i16, y: i16) -> Result<&ProcessorLink, CreateError>
- {
- if name.len() > u16::MAX as usize
- {
- return Err(CreateError::NameLength(name.len()))
- }
- for curr in self.links.iter()
- {
- if &name == &curr.name
- {
- return Err(CreateError::DuplicateName(name));
- }
- if x == curr.x && y == curr.y
- {
- name.clear();
- name.push_str(&curr.name);
- return Err(CreateError::DuplicatePos{name, x, y});
- }
- }
- let idx = self.links.len();
- self.links.push(ProcessorLink{name, x, y});
- Ok(&self.links[idx])
- }
-
- pub fn add_link(&mut self, link: ProcessorLink) -> Result<&ProcessorLink, CreateError>
- {
- self.create_link(link.name, link.x, link.y)
- }
-
- pub fn remove_link(&mut self, idx: usize) -> Option<ProcessorLink>
- {
- if idx < self.links.len()
- {
- Some(self.links.remove(idx))
- }
- else {None}
- }
+impl ProcessorState {
+ pub fn new() -> Self {
+ Self {
+ code: String::new(),
+ links: Vec::new(),
+ }
+ }
+
+ pub fn get_code(&self) -> &str {
+ &self.code
+ }
+
+ pub fn set_code(&mut self, code: Cow<'_, str>) -> Result<(), CodeError> {
+ let as_str = &code as &str;
+ if as_str.len() > 500 * 1024 {
+ return Err(CodeError::TooLong(as_str.len()));
+ }
+ match code {
+ Cow::Borrowed(s) => {
+ self.code.clear();
+ self.code.push_str(s);
+ }
+ Cow::Owned(s) => self.code = s,
+ }
+ Ok(())
+ }
+
+ pub fn get_links(&self) -> &[ProcessorLink] {
+ &self.links
+ }
+
+ pub fn create_link(
+ &mut self,
+ mut name: String,
+ x: i16,
+ y: i16,
+ ) -> Result<&ProcessorLink, CreateError> {
+ if name.len() > u16::MAX as usize {
+ return Err(CreateError::NameLength(name.len()));
+ }
+ for curr in self.links.iter() {
+ if &name == &curr.name {
+ return Err(CreateError::DuplicateName(name));
+ }
+ if x == curr.x && y == curr.y {
+ name.clear();
+ name.push_str(&curr.name);
+ return Err(CreateError::DuplicatePos { name, x, y });
+ }
+ }
+ let idx = self.links.len();
+ self.links.push(ProcessorLink { name, x, y });
+ Ok(&self.links[idx])
+ }
+
+ pub fn add_link(&mut self, link: ProcessorLink) -> Result<&ProcessorLink, CreateError> {
+ self.create_link(link.name, link.x, link.y)
+ }
+
+ pub fn remove_link(&mut self, idx: usize) -> Option<ProcessorLink> {
+ if idx < self.links.len() {
+ Some(self.links.remove(idx))
+ } else {
+ None
+ }
+ }
}
#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum CodeError
-{
- TooLong(usize),
+pub enum CodeError {
+ TooLong(usize),
}
-impl fmt::Display for CodeError
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
- {
- match self
- {
- Self::TooLong(len) => write!(f, "code too long ({len} bytes)"),
- }
- }
+impl fmt::Display for CodeError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::TooLong(len) => write!(f, "code too long ({len} bytes)"),
+ }
+ }
}
impl Error for CodeError {}
#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum CreateError
-{
- NameLength(usize),
- DuplicateName(String),
- DuplicatePos{name: String, x: i16, y: i16},
+pub enum CreateError {
+ NameLength(usize),
+ DuplicateName(String),
+ DuplicatePos { name: String, x: i16, y: i16 },
}
-impl fmt::Display for CreateError
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
- {
- match self
- {
- Self::NameLength(len) => write!(f, "link name too long ({len} bytes)"),
- Self::DuplicateName(name) => write!(f, "there already is a link named {name}"),
- Self::DuplicatePos{name, x, y} => write!(f, "link {name} already points to {x} / {y}"),
- }
- }
+impl fmt::Display for CreateError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::NameLength(len) => write!(f, "link name too long ({len} bytes)"),
+ Self::DuplicateName(name) => write!(f, "there already is a link named {name}"),
+ Self::DuplicatePos { name, x, y } => {
+ write!(f, "link {name} already points to {x} / {y}")
+ }
+ }
+ }
}
impl Error for CreateError {}