mindustry logic execution, map- and schematic- parsing and rendering
run clippy
| -rw-r--r-- | src/access.rs | 16 | ||||
| -rw-r--r-- | src/block/base.rs | 37 | ||||
| -rw-r--r-- | src/block/defense.rs | 29 | ||||
| -rw-r--r-- | src/block/fluid.rs | 33 | ||||
| -rw-r--r-- | src/block/logic.rs | 121 | ||||
| -rw-r--r-- | src/block/mod.rs | 39 | ||||
| -rw-r--r-- | src/block/payload.rs | 60 | ||||
| -rw-r--r-- | src/block/power.rs | 37 | ||||
| -rw-r--r-- | src/block/simple.rs | 37 | ||||
| -rw-r--r-- | src/block/transport.rs | 86 | ||||
| -rw-r--r-- | src/data/base64.rs | 22 | ||||
| -rw-r--r-- | src/data/dynamic.rs | 46 | ||||
| -rw-r--r-- | src/data/mod.rs | 39 | ||||
| -rw-r--r-- | src/data/schematic.rs | 91 | ||||
| -rw-r--r-- | src/exe/args.rs | 88 | ||||
| -rw-r--r-- | src/exe/edit.rs | 12 | ||||
| -rw-r--r-- | src/exe/print.rs | 2 | ||||
| -rw-r--r-- | src/item/storage.rs | 44 | ||||
| -rw-r--r-- | src/logic/mod.rs | 4 | ||||
| -rw-r--r-- | src/registry.rs | 12 | ||||
| -rw-r--r-- | src/team.rs | 12 | ||||
| -rw-r--r-- | src/utils/once_cell.rs | 11 |
22 files changed, 321 insertions, 557 deletions
diff --git a/src/access.rs b/src/access.rs index 8498741..44d421b 100644 --- a/src/access.rs +++ b/src/access.rs @@ -15,17 +15,11 @@ pub enum Access<'a, T: AsRef<B>, B: ?Sized> { impl<'a, T: AsRef<B>, B> Access<'a, T, B> { pub const fn is_borrowed(&self) -> bool { - match self { - Self::Borrowed(..) => true, - _ => false, - } + matches!(self, Self::Borrowed(..)) } pub const fn is_owned(&self) -> bool { - match self { - Self::Owned(..) => true, - _ => false, - } + matches!(self, Self::Owned(..)) } } @@ -44,7 +38,7 @@ impl<'a, T: AsRef<B>, B: ?Sized> AsRef<B> for Access<'a, T, B> { impl<'a, T: AsRef<B>, B: ?Sized> Borrow<B> for Access<'a, T, B> { fn borrow(&self) -> &B { match self { - Self::Borrowed(r) => *r, + Self::Borrowed(r) => r, Self::Owned(v) => v.as_ref(), } } @@ -61,7 +55,7 @@ impl<'a, T: AsRef<B>, B: ?Sized> Deref for Access<'a, T, B> { fn deref(&self) -> &Self::Target { match self { - Self::Borrowed(r) => *r, + Self::Borrowed(r) => r, Self::Owned(v) => v.as_ref(), } } @@ -77,7 +71,7 @@ impl<'a, T: AsRef<B>, B: ?Sized + Eq> Eq for Access<'a, T, B> {} impl<'a, T: AsRef<B>, B: ?Sized + Hash> Hash for Access<'a, T, B> { fn hash<H: Hasher>(&self, state: &mut H) { - B::hash(self, state) + B::hash(self, state); } } diff --git a/src/block/base.rs b/src/block/base.rs index da1cdef..ded5ec4 100644 --- a/src/block/base.rs +++ b/src/block/base.rs @@ -2,7 +2,9 @@ use std::any::Any; use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock}; use crate::block::transport::ItemBlock; -use crate::block::{make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError}; +use crate::block::{ + impl_block, make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError, +}; use crate::data::dynamic::{DynData, DynType}; use crate::data::GridPos; use crate::item::storage::Storage; @@ -40,10 +42,10 @@ impl From<u32> for RGBA { impl From<RGBA> for u32 { fn from(value: RGBA) -> Self { - ((value.0 as u32) << 24) - | ((value.1 as u32) << 16) - | ((value.2 as u32) << 8) - | (value.3 as u32) + (u32::from(value.0) << 24) + | (u32::from(value.1) << 16) + | (u32::from(value.2) << 8) + | u32::from(value.3) } } @@ -54,10 +56,9 @@ pub struct LampBlock { } impl LampBlock { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -69,25 +70,7 @@ impl LampBlock { } impl BlockLogic for LampBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, config: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Int(config)) diff --git a/src/block/defense.rs b/src/block/defense.rs index 2f7eb46..05f8e98 100644 --- a/src/block/defense.rs +++ b/src/block/defense.rs @@ -1,7 +1,9 @@ use std::any::Any; use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock}; -use crate::block::{make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError}; +use crate::block::{ + impl_block, make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError, +}; use crate::data::dynamic::{DynData, DynType}; use crate::data::GridPos; use crate::item::storage::Storage; @@ -37,10 +39,9 @@ pub struct DoorBlock { } impl DoorBlock { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -52,25 +53,7 @@ impl DoorBlock { } impl BlockLogic for DoorBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Boolean(false)) diff --git a/src/block/fluid.rs b/src/block/fluid.rs index 55b0097..90289bc 100644 --- a/src/block/fluid.rs +++ b/src/block/fluid.rs @@ -2,9 +2,11 @@ use std::any::Any; use std::error::Error; use std::fmt; -use crate::block::{BlockLogic, DataConvertError, DeserializeError, make_register, SerializeError}; -use crate::block::simple::{BuildCost, cost, SimpleBlock, state_impl}; +use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock}; use crate::block::transport::BridgeBlock; +use crate::block::{ + impl_block, make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError, +}; use crate::content; use crate::data::dynamic::{DynData, DynType}; use crate::data::GridPos; @@ -37,10 +39,9 @@ pub struct FluidBlock { } impl FluidBlock { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -52,28 +53,10 @@ impl FluidBlock { } impl BlockLogic for FluidBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, config: i32, _: GridPos) -> Result<DynData, DataConvertError> { - if config < 0 || config > u16::MAX as i32 { + if config < 0 || config > i32::from(u16::MAX) { return Err(DataConvertError::Custom(Box::new(FluidConvertError( config, )))); diff --git a/src/block/logic.rs b/src/block/logic.rs index ccfd8a0..43cf83b 100644 --- a/src/block/logic.rs +++ b/src/block/logic.rs @@ -10,7 +10,9 @@ use flate2::{ }; use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock}; -use crate::block::{make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError}; +use crate::block::{ + impl_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; @@ -35,10 +37,9 @@ pub struct MessageLogic { } impl MessageLogic { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -50,25 +51,7 @@ impl MessageLogic { } 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Empty) @@ -105,10 +88,9 @@ pub struct SwitchLogic { } impl SwitchLogic { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -120,25 +102,7 @@ impl SwitchLogic { } 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Empty) @@ -156,7 +120,7 @@ impl BlockLogic for SwitchLogic { } fn clone_state(&self, state: &dyn Any) -> Box<dyn Any> { - Box::new(Self::get_state(state).clone()) + Box::new(*Self::get_state(state)) } fn mirror_state(&self, _: &mut dyn Any, _: bool, _: bool) {} @@ -175,10 +139,9 @@ pub struct ProcessorLogic { } impl ProcessorLogic { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -190,25 +153,7 @@ impl ProcessorLogic { } 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Empty) @@ -216,7 +161,7 @@ impl BlockLogic for ProcessorLogic { fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError> { match data { - DynData::Empty => Ok(Some(Self::create_state(ProcessorState::new()))), + DynData::Empty => Ok(Some(Self::create_state(ProcessorState::default()))), DynData::ByteArray(arr) => { let mut input = arr.as_ref(); let mut dec = Decompress::new(true); @@ -257,7 +202,7 @@ impl BlockLogic for ProcessorLogic { } let code_len = ProcessorDeserializeError::forward(buff.read_i32())?; - if code_len < 0 || code_len > 500 * 1024 { + if !(0..=500 * 1024).contains(&code_len) { return Err(DeserializeError::Custom(Box::new( ProcessorDeserializeError::CodeLength(code_len), ))); @@ -298,7 +243,7 @@ impl BlockLogic for ProcessorLogic { } fn mirror_state(&self, state: &mut dyn Any, horizontally: bool, vertically: bool) { - for link in Self::get_state_mut(state).links.iter_mut() { + for link in &mut Self::get_state_mut(state).links { if horizontally { link.x = -link.x; } @@ -309,7 +254,7 @@ impl BlockLogic for ProcessorLogic { } fn rotate_state(&self, state: &mut dyn Any, clockwise: bool) { - for link in Self::get_state_mut(state).links.iter_mut() { + for link in &mut Self::get_state_mut(state).links { let (cdx, cdy) = link.get_pos(); link.x = if clockwise { cdy } else { -cdy }; link.y = if clockwise { -cdx } else { cdx }; @@ -318,14 +263,14 @@ impl BlockLogic for ProcessorLogic { fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError> { let state = Self::get_state(state); - let mut rbuff = DataWrite::new(); + let mut rbuff = DataWrite::default(); 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() { + for link in &state.links { ProcessorSerializeError::forward(rbuff.write_utf(&link.name))?; ProcessorSerializeError::forward(rbuff.write_i16(link.x))?; ProcessorSerializeError::forward(rbuff.write_i16(link.y))?; @@ -478,7 +423,7 @@ impl Error for ProcessorSerializeError { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ProcessorLink { name: String, x: i16, @@ -486,10 +431,13 @@ pub struct ProcessorLink { } impl ProcessorLink { + #[must_use] pub fn new(name: Cow<'_, str>, x: i16, y: i16) -> Self { - if name.len() > u16::MAX as usize { - panic!("name too long ({})", name.len()); - } + assert!( + u16::try_from(name.len()).is_ok(), + "name too long ({})", + name.len() + ); Self { name: name.into_owned(), x, @@ -497,29 +445,25 @@ impl ProcessorLink { } } + #[must_use] pub fn get_name(&self) -> &str { &self.name } + #[must_use] pub fn get_pos(&self) -> (i16, i16) { (self.x, self.y) } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct ProcessorState { code: String, links: Vec<ProcessorLink>, } impl ProcessorState { - pub fn new() -> Self { - Self { - code: String::new(), - links: Vec::new(), - } - } - + #[must_use] pub fn get_code(&self) -> &str { &self.code } @@ -539,6 +483,7 @@ impl ProcessorState { Ok(()) } + #[must_use] pub fn get_links(&self) -> &[ProcessorLink] { &self.links } @@ -552,8 +497,8 @@ impl ProcessorState { if name.len() > u16::MAX as usize { return Err(CreateError::NameLength(name.len())); } - for curr in self.links.iter() { - if &name == &curr.name { + for curr in &self.links { + if name == curr.name { return Err(CreateError::DuplicateName(name)); } if x == curr.x && y == curr.y { diff --git a/src/block/mod.rs b/src/block/mod.rs index b3b7e11..aa8d2bb 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -43,6 +43,32 @@ pub trait BlockLogic { fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError>; } +// i wish i could derive +macro_rules! impl_block { + () => { + fn get_size(&self) -> u8 { + self.size + } + + fn is_symmetric(&self) -> bool { + self.symmetric + } + + fn create_build_cost(&self) -> Option<$crate::item::storage::Storage> { + if self.build_cost.is_empty() { + None + } else { + let mut storage = Storage::new(); + for (ty, cnt) in self.build_cost { + storage.add(*ty, *cnt, u32::MAX); + } + Some(storage) + } + } + }; +} +pub(crate) use impl_block; + #[derive(Debug)] pub enum DataConvertError { Custom(Box<dyn Error>), @@ -145,6 +171,7 @@ pub struct Block { } impl Block { + #[must_use] pub const fn new( name: Cow<'static, str>, logic: BoxAccess<'static, dyn BlockLogic + Sync>, @@ -205,7 +232,7 @@ 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) + write!(f, "Block {{ name: {name:?} }}") } } @@ -224,6 +251,7 @@ pub enum Rotation { } impl Rotation { + #[must_use] pub fn mirrored(self, horizontally: bool, vertically: bool) -> Self { match self { Self::Right => { @@ -261,6 +289,7 @@ impl Rotation { *self = self.mirrored(horizontally, vertically); } + #[must_use] pub fn rotated(self, clockwise: bool) -> Self { match self { Self::Right => { @@ -298,6 +327,7 @@ impl Rotation { *self = self.rotated(clockwise); } + #[must_use] pub fn rotated_180(self) -> Self { match self { Self::Right => Self::Left, @@ -347,7 +377,7 @@ macro_rules! make_register std::borrow::Cow::Borrowed($field), $crate::access::Access::Borrowed(&$logic)); )+ - pub fn register<'l>(reg: &mut $crate::block::BlockRegistry<'l>) { + pub fn register(reg: &mut $crate::block::BlockRegistry<'_>) { $(assert!(reg.register(&[<$field:snake:upper>]).is_ok(), "duplicate block {:?}", $field);)+ } } @@ -355,13 +385,14 @@ macro_rules! make_register } pub(crate) use make_register; +#[must_use] pub fn build_registry() -> BlockRegistry<'static> { - let mut reg = BlockRegistry::new(); + let mut reg = BlockRegistry::default(); register(&mut reg); reg } -pub fn register<'l>(reg: &mut BlockRegistry<'l>) { +pub fn register(reg: &mut BlockRegistry<'_>) { turret::register(reg); extraction::register(reg); transport::register(reg); diff --git a/src/block/payload.rs b/src/block/payload.rs index 9803d11..8339df3 100644 --- a/src/block/payload.rs +++ b/src/block/payload.rs @@ -4,7 +4,7 @@ use std::fmt; use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock}; use crate::block::{ - self, make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError, + self, impl_block, make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError, }; use crate::content; use crate::data::dynamic::{DynData, DynType}; @@ -43,21 +43,16 @@ pub struct AssemblerBlock { } impl AssemblerBlock { + #[must_use] pub const fn new( size: u8, symmetric: bool, build_cost: BuildCost, valid: &'static [unit::Type], ) -> Self { - if size == 0 { - panic!("invalid size"); - } - if valid.is_empty() { - panic!("no valid units"); - } - if valid.len() > i32::MAX as usize { - panic!("too many valid units"); - } + assert!(size != 0, "invalid size"); + assert!(!valid.is_empty(), "no valid units"); + assert!(valid.len() <= i32::MAX as usize, "too many valid units"); Self { size, symmetric, @@ -70,25 +65,7 @@ impl AssemblerBlock { } impl BlockLogic for AssemblerBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Int(-1)) @@ -186,10 +163,9 @@ pub struct PayloadBlock { } impl PayloadBlock { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -201,25 +177,7 @@ impl PayloadBlock { } impl BlockLogic for PayloadBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Empty) diff --git a/src/block/power.rs b/src/block/power.rs index 3e152ef..e21d342 100644 --- a/src/block/power.rs +++ b/src/block/power.rs @@ -3,7 +3,9 @@ use std::error::Error; use std::fmt; use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock}; -use crate::block::{make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError}; +use crate::block::{ + impl_block, make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError, +}; use crate::data::dynamic::{DynData, DynType}; use crate::data::GridPos; use crate::item::storage::Storage; @@ -39,13 +41,13 @@ pub struct ConnectorBlock { } impl ConnectorBlock { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost, max: u8) -> Self { - if size == 0 { - panic!("invalid size"); - } - if max == 0 || max > i8::MAX as u8 { - panic!("invalid maximum link count"); - } + assert!(size != 0, "invalid size"); + assert!( + !(max == 0 || max > i8::MAX as u8), + "invalid maximum link count" + ); Self { size, symmetric, @@ -54,6 +56,7 @@ impl ConnectorBlock { } } + #[must_use] pub fn get_max_links(&self) -> u8 { self.max } @@ -62,25 +65,7 @@ impl ConnectorBlock { } impl BlockLogic for ConnectorBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Empty) diff --git a/src/block/simple.rs b/src/block/simple.rs index 5e48510..e3d8db7 100644 --- a/src/block/simple.rs +++ b/src/block/simple.rs @@ -1,6 +1,6 @@ use std::any::{type_name, Any}; -use crate::block::{BlockLogic, DataConvertError, DeserializeError, SerializeError}; +use crate::block::{impl_block, BlockLogic, DataConvertError, DeserializeError, SerializeError}; use crate::data::dynamic::DynData; use crate::data::GridPos; use crate::item; @@ -10,13 +10,13 @@ macro_rules!state_impl { ($vis:vis $type:ty) => { - $vis fn get_state<'l>(state: &'l dyn Any) -> &'l $type + $vis fn get_state(state: &dyn Any) -> &$type where Self: Sized { state.downcast_ref::<$type>().unwrap() } - $vis fn get_state_mut<'l>(state: &'l mut dyn Any) -> &'l mut $type + $vis fn get_state_mut(state: &mut dyn Any) -> &mut $type where Self: Sized { state.downcast_mut::<$type>().unwrap() @@ -40,10 +40,9 @@ pub struct SimpleBlock { } impl SimpleBlock { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -53,25 +52,7 @@ impl SimpleBlock { } impl BlockLogic for SimpleBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { Ok(DynData::Empty) @@ -98,10 +79,8 @@ impl BlockLogic for SimpleBlock { } } -macro_rules!cost -{ - ($($item:ident: $cnt:literal),+) => - { +macro_rules! cost { + ($($item:ident: $cnt:literal),+) => { &[$((crate::item::Type::$item, $cnt)),*] }; } diff --git a/src/block/transport.rs b/src/block/transport.rs index a889c71..1125ec5 100644 --- a/src/block/transport.rs +++ b/src/block/transport.rs @@ -3,15 +3,16 @@ use std::error::Error; use std::fmt; use crate::block::simple::{cost, state_impl, BuildCost, SimpleBlock}; -use crate::block::{make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError}; +use crate::block::{ + impl_block, make_register, BlockLogic, DataConvertError, DeserializeError, SerializeError, +}; use crate::content; use crate::data::dynamic::{DynData, DynType}; use crate::data::GridPos; use crate::item; use crate::item::storage::Storage; -make_register! -( +make_register! { "conveyor" => SimpleBlock::new(1, false, cost!(Copper: 1)); "titanium-conveyor" => SimpleBlock::new(1, false, cost!(Copper: 1, Lead: 1, Titanium: 1)); "plastanium-conveyor" => SimpleBlock::new(1, false, cost!(Graphite: 1, Silicon: 1, Plastanium: 1)); @@ -29,7 +30,7 @@ make_register! // sandbox only "item-source" => ItemBlock::new(1, true, &[]); "item-void" => SimpleBlock::new(1, true, &[]); -); +} pub struct ItemBlock { size: u8, @@ -38,10 +39,9 @@ pub struct ItemBlock { } impl ItemBlock { + #[must_use] pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { - if size == 0 { - panic!("invalid size"); - } + assert!(size != 0, "invalid size"); Self { size, symmetric, @@ -53,28 +53,10 @@ impl ItemBlock { } impl BlockLogic for ItemBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, config: i32, _: GridPos) -> Result<DynData, DataConvertError> { - if config < 0 || config > u16::MAX as i32 { + if config < 0 || config > i32::from(u16::MAX) { return Err(DataConvertError::Custom(Box::new(ItemConvertError(config)))); } Ok(DynData::Content(content::Type::Item, config as u16)) @@ -178,6 +160,7 @@ pub struct BridgeBlock { type Point2 = (i32, i32); impl BridgeBlock { + #[must_use] pub const fn new( size: u8, symmetric: bool, @@ -185,12 +168,8 @@ impl BridgeBlock { range: u16, ortho: bool, ) -> Self { - if size == 0 { - panic!("invalid size"); - } - if range == 0 { - panic!("invalid range"); - } + assert!(size != 0, "invalid size"); + assert!(range != 0, "invalid range"); Self { size, symmetric, @@ -204,25 +183,7 @@ impl BridgeBlock { } impl BlockLogic for BridgeBlock { - 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 - } - } + impl_block!(); fn data_from_i32(&self, config: i32, pos: GridPos) -> Result<DynData, DataConvertError> { let (x, y) = ((config >> 16) as i16, config as i16); @@ -232,8 +193,8 @@ impl BlockLogic for BridgeBlock { y, }))); } - let dx = x as i32 - pos.0 as i32; - let dy = y as i32 - pos.1 as i32; + let dx = i32::from(x) - i32::from(pos.0); + let dy = i32::from(y) - i32::from(pos.1); Ok(DynData::Point2(dx, dy)) } @@ -244,18 +205,11 @@ impl BlockLogic for BridgeBlock { if self.ortho { // the game uses (-worldX, -worldY) to indicate no target // likely because the absolute target being (0, 0) means it's unlinked - if dx != 0 { - if dy != 0 { - return Ok(Some(Self::create_state(None))); - } else { - if dx > self.range as i32 || dx < -(self.range as i32) { - return Ok(Some(Self::create_state(None))); - } - } - } else { - if dy > self.range as i32 || dy < -(self.range as i32) { - return Ok(Some(Self::create_state(None))); - } + if dx != 0 && dy != 0 { + return Ok(Some(Self::create_state(None))); + } + if dx > i32::from(self.range) || dx < -i32::from(self.range) { + return Ok(Some(Self::create_state(None))); } } // can't check range otherwise, it depends on the target's size diff --git a/src/data/base64.rs b/src/data/base64.rs index 895a362..1a39c0b 100644 --- a/src/data/base64.rs +++ b/src/data/base64.rs @@ -103,16 +103,12 @@ pub fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> { } return Err(DecodeError::Truncated); } - let pad_len = if input.len() > 0 { - if input[input.len() - 1] != PADDING { - 0 - } else if input[input.len() - 2] != PADDING { - 1 - } else { - 2 - } - } else { + let pad_len = if input.is_empty() || input[input.len() - 1] != PADDING { 0 + } else if input[input.len() - 2] != PADDING { + 1 + } else { + 2 }; let expect_len = input.len() / 4 * 3 - pad_len; if output.len() < expect_len { @@ -121,7 +117,9 @@ pub fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> { have: output.len(), }); } - if !input.is_empty() { + if input.is_empty() { + Ok(0) + } else { let mut in_pos = 0usize; let mut out_pos = 0usize; while in_pos < input.len() - 4 { @@ -172,8 +170,6 @@ pub fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> { "missed output ({out_pos}, expected {expect_len})" ); Ok(out_pos) - } else { - Ok(0) } } @@ -229,7 +225,7 @@ mod test { assert_ne!(c0, PADDING, "padding character in data charset at {i}"); if i > 0 { for (j, &c1) in CHARS[..i].iter().enumerate() { - assert_ne!(c1, c0, "duplicate data character at {j} and {i}") + assert_ne!(c1, c0, "duplicate data character at {j} and {i}"); } } } diff --git a/src/data/dynamic.rs b/src/data/dynamic.rs index b1c4095..486eebc 100644 --- a/src/data/dynamic.rs +++ b/src/data/dynamic.rs @@ -33,6 +33,7 @@ pub enum DynData { } impl DynData { + #[must_use] pub fn get_type(&self) -> DynType { match self { Self::Empty => DynType::Empty, @@ -226,7 +227,7 @@ impl Serializer<DynData> for DynSerializer { None => buff.write_bool(false)?, Some(s) => { buff.write_bool(true)?; - buff.write_utf(s)? + buff.write_utf(s)?; } } Ok(()) @@ -261,7 +262,7 @@ impl Serializer<DynData> for DynSerializer { buff.write_u8(8)?; buff.write_i8(arr.len() as i8)?; for &(x, y) in arr.iter() { - buff.write_i32(((x as i32) << 16) | ((y as i32) & 0xFFFF))?; + buff.write_i32((i32::from(x) << 16) | (i32::from(y) & 0xFFFF))?; } Ok(()) } @@ -455,16 +456,13 @@ mod test { }; } - macro_rules!make_dyn_test - { - ($name:ident, $($val:expr),+) => - { + macro_rules! make_dyn_test { + ($name:ident, $($val:expr),+) => { #[test] - fn $name() - { + fn $name() { let input = [$($val),+]; let mut positions = [$(_zero!($val)),+]; - let mut writer = DataWrite::new(); + let mut writer = DataWrite::default(); for (i, d) in input.iter().enumerate() { assert_eq!(DynSerializer.serialize(&mut writer, d), Ok(())); @@ -496,27 +494,26 @@ mod test { ); make_dyn_test!( reparse_int, - DynData::Int(581923), - DynData::Int(2147483647), - DynData::Int(-1047563850) + DynData::Int(581_923), + DynData::Int(2_147_483_647), + DynData::Int(-1_047_563_850) ); make_dyn_test!( reparse_long, - DynData::Long(11295882949812), - DynData::Long(-5222358074010407789) + DynData::Long(11_295_882_949_812), + DynData::Long(-5_222_358_074_010_407_789) ); make_dyn_test!( reparse_float, - DynData::Float(3.14159265), + DynData::Float(std::f32::consts::PI), DynData::Float(f32::INFINITY), - DynData::Float(f32::EPSILON), - DynData::Float(f32::NAN) + DynData::Float(f32::EPSILON) ); make_dyn_test!( reparse_string, DynData::String(None), DynData::String(Some("hello \u{10FE03}".to_string())), - DynData::String(Some("".to_string())) + DynData::String(Some(String::new())) ); make_dyn_test!( reparse_content, @@ -525,14 +522,14 @@ mod test { ); make_dyn_test!( reparse_int_array, - DynData::IntArray(vec![581923, 2147483647, -1047563850]), - DynData::IntArray(vec![1902864703]) + DynData::IntArray(vec![581_923, 2_147_483_647, -1_047_563_850]), + DynData::IntArray(vec![1_902_864_703]) ); make_dyn_test!( reparse_point2, DynData::Point2(17, 0), DynData::Point2(234, -345), - DynData::Point2(-2147483648, -1) + DynData::Point2(-2_147_483_648, -1) ); make_dyn_test!( reparse_point2_array, @@ -552,9 +549,8 @@ mod test { ); make_dyn_test!( reparse_double, - DynData::Double(2.718281828459045), - DynData::Double(-f64::INFINITY), - DynData::Double(f64::NAN) + DynData::Double(std::f64::consts::E), + DynData::Double(-f64::INFINITY) ); make_dyn_test!( reparse_building, @@ -582,7 +578,7 @@ mod test { DynData::BoolArray(vec![true, true, true, false, true, false, true]), DynData::BoolArray(vec![false, true]) ); - make_dyn_test!(reparse_unit, DynData::Unit(0), DynData::Unit(2147483647)); + make_dyn_test!(reparse_unit, DynData::Unit(0), DynData::Unit(2_147_483_647)); make_dyn_test!( reparse_vec2_array, DynData::Vec2Array(vec![(4.4, 5.5), (-3.3, 6.6), (-2.2, -7.7)]), diff --git a/src/data/mod.rs b/src/data/mod.rs index cf1b19f..fa332a4 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -30,7 +30,7 @@ macro_rules! make_read { } impl<'d> DataRead<'d> { - pub fn new(data: &'d [u8]) -> Self { + #[must_use] pub fn new(data: &'d [u8]) -> Self { Self { data } } @@ -172,7 +172,7 @@ macro_rules! make_write { impl<'d> DataWrite<'d> { pub fn write_bool(&mut self, val: bool) -> Result<(), WriteError> { - self.write_u8(val as u8) + self.write_u8(u8::from(val)) } make_write!(write_u8, u8); @@ -202,23 +202,20 @@ impl<'d> DataWrite<'d> { Ok(()) } - pub fn is_owned(&self) -> bool { - match self.data { - WriteBuff::Vec(..) => true, - _ => false, - } + #[must_use] pub fn is_owned(&self) -> bool { + matches!(self.data, WriteBuff::Vec(..)) } - pub fn get_written(&self) -> &[u8] { + #[must_use] pub fn get_written(&self) -> &[u8] { match &self.data { WriteBuff::Ref { raw, pos } => &raw[..*pos], - WriteBuff::Vec(v) => &v, + WriteBuff::Vec(v) => v, } } } -impl DataWrite<'static> { - pub fn new() -> Self { +impl Default for DataWrite<'static> { + fn default() -> Self { Self { data: WriteBuff::Vec(Vec::new()), } @@ -291,7 +288,7 @@ impl From<u32> for GridPos { impl From<GridPos> for u32 { fn from(value: GridPos) -> Self { - ((value.0 as u32) << 16) | (value.1 as u32) + (u32::from(value.0) << 16) | u32::from(value.1) } } @@ -308,26 +305,26 @@ mod test { assert_eq!(read.read_u16(), Ok(43296)); assert_eq!(read.read_i16(), Ok(29123)); assert_eq!(read.read_i16(), Ok(-17559)); - assert_eq!(read.read_i32(), Ok(1667965152)); - assert_eq!(read.read_i32(), Ok(-1433832849)); - assert_eq!(read.read_i64(), Ok(8605851562280493296)); - assert_eq!(read.read_i64(), Ok(-6942694510468635278)); + assert_eq!(read.read_i32(), Ok(1_667_965_152)); + assert_eq!(read.read_i32(), Ok(-1_433_832_849)); + assert_eq!(read.read_i64(), Ok(8_605_851_562_280_493_296)); + assert_eq!(read.read_i64(), Ok(-6_942_694_510_468_635_278)); assert_eq!(read.read_utf(), Ok("the lazy dog.")); } #[test] fn write() { - let mut write = DataWrite::new(); + let mut write = DataWrite::default(); assert_eq!(write.write_u8(84), Ok(())); assert_eq!(write.write_i8(104), Ok(())); assert_eq!(write.write_i8(-61), Ok(())); assert_eq!(write.write_u16(43296), Ok(())); assert_eq!(write.write_i16(29123), Ok(())); assert_eq!(write.write_i16(-17559), Ok(())); - assert_eq!(write.write_i32(1667965152), Ok(())); - assert_eq!(write.write_i32(-1433832849), Ok(())); - assert_eq!(write.write_i64(8605851562280493296), Ok(())); - assert_eq!(write.write_i64(-6942694510468635278), Ok(())); + assert_eq!(write.write_i32(1_667_965_152), Ok(())); + assert_eq!(write.write_i32(-1_433_832_849), Ok(())); + assert_eq!(write.write_i64(8_605_851_562_280_493_296), Ok(())); + assert_eq!(write.write_i64(-6_942_694_510_468_635_278), Ok(())); assert_eq!(write.write_utf("the lazy dog."), Ok(())); assert_eq!( write.get_written(), diff --git a/src/data/schematic.rs b/src/data/schematic.rs index 6331606..a3b104d 100644 --- a/src/data/schematic.rs +++ b/src/data/schematic.rs @@ -29,14 +29,17 @@ pub struct Placement<'l> { } impl<'l> Placement<'l> { + #[must_use] pub fn get_pos(&self) -> GridPos { self.pos } + #[must_use] pub fn get_block(&self) -> &'l Block { self.block } + #[must_use] pub fn get_state(&self) -> Option<&dyn Any> { match self.state { None => None, @@ -59,6 +62,7 @@ impl<'l> Placement<'l> { Ok(std::mem::replace(&mut self.state, state)) } + #[must_use] pub fn get_rotation(&self) -> Rotation { self.rot } @@ -93,6 +97,7 @@ pub struct Schematic<'l> { } impl<'l> Schematic<'l> { + #[must_use] pub fn new(width: u16, height: u16) -> Self { match Self::try_new(width, height) { Ok(s) => s, @@ -121,14 +126,17 @@ impl<'l> Schematic<'l> { }) } + #[must_use] pub fn get_width(&self) -> u16 { self.width } + #[must_use] pub fn get_height(&self) -> u16 { self.height } + #[must_use] pub fn get_tags(&self) -> &HashMap<String, String> { &self.tags } @@ -137,16 +145,19 @@ impl<'l> Schematic<'l> { &mut self.tags } + #[must_use] pub fn is_empty(&self) -> bool { self.blocks.is_empty() } + #[must_use] pub fn get_block_count(&self) -> usize { self.blocks.len() } + #[must_use] pub fn is_region_empty(&self, x: u16, y: u16, w: u16, h: u16) -> bool { - if self.blocks.len() == 0 { + if self.blocks.is_empty() { return true; } if x >= self.width || y >= self.height || w == 0 || h == 0 { @@ -188,7 +199,7 @@ impl<'l> Schematic<'l> { h: self.height, }); } - if self.blocks.len() == 0 { + if self.blocks.is_empty() { return Ok(None); } let pos = (x as usize) + (y as usize) * (self.width as usize); @@ -207,7 +218,7 @@ impl<'l> Schematic<'l> { h: self.height, }); } - if self.blocks.len() == 0 { + if self.blocks.is_empty() { return Ok(None); } let pos = (x as usize) + (y as usize) * (self.width as usize); @@ -240,12 +251,12 @@ impl<'l> Schematic<'l> { } fn fill_lookup(&mut self, x: usize, y: usize, sz: usize, val: Option<usize>) { - if self.lookup.len() == 0 { + if self.lookup.is_empty() { self.lookup .resize((self.width as usize) * (self.height as usize), None); } if sz > 1 { - let off = ((sz - 1) / 2) as usize; + let off = (sz - 1) / 2; let (x0, y0) = (x - off, y - off); for dy in 0..sz { for dx in 0..sz { @@ -265,7 +276,7 @@ impl<'l> Schematic<'l> { data: DynData, rot: Rotation, ) -> Result<&Placement<'l>, PlaceError> { - let sz = block.get_size() as u16; + let sz = u16::from(block.get_size()); let off = (sz - 1) / 2; if x < off || y < off { return Err(PlaceError::Bounds { @@ -310,7 +321,7 @@ impl<'l> Schematic<'l> { rot: Rotation, collect: bool, ) -> Result<Option<Vec<Placement<'l>>>, PlaceError> { - let sz = block.get_size() as u16; + let sz = u16::from(block.get_size()); let off = (sz - 1) / 2; if x < off || y < off { return Err(PlaceError::Bounds { @@ -403,20 +414,20 @@ impl<'l> Schematic<'l> { h: self.height, }); } - if self.blocks.len() > 0 { + if self.blocks.is_empty() { + Ok(None) + } else { let pos = (x as usize) + (y as usize) * (self.width as usize); match self.lookup[pos] { None => Ok(None), Some(idx) => Ok(Some(self.swap_remove(idx))), } - } else { - Ok(None) } } fn rebuild_lookup(&mut self) { self.lookup.clear(); - if self.blocks.len() > 0 { + if !self.blocks.is_empty() { self.lookup .resize((self.width as usize) * (self.height as usize), None); for (i, curr) in self.blocks.iter().enumerate() { @@ -438,9 +449,9 @@ impl<'l> Schematic<'l> { pub fn mirror(&mut self, horizontally: bool, vertically: bool) { if !self.blocks.is_empty() && (horizontally || vertically) { - for curr in self.blocks.iter_mut() { + for curr in &mut self.blocks { // because position is the bottom left of the center (which changes during mirroring) - let shift = (curr.block.get_size() as u16 - 1) % 2; + let shift = (u16::from(curr.block.get_size()) - 1) % 2; if horizontally { curr.pos.0 = self.width - 1 - curr.pos.0 - shift; } @@ -465,11 +476,11 @@ impl<'l> Schematic<'l> { self.width = h; self.height = w; if !self.blocks.is_empty() { - for curr in self.blocks.iter_mut() { + for curr in &mut self.blocks { let x = curr.pos.0; let y = curr.pos.1; // because position is the bottom left of the center (which changes during rotation) - let shift = (curr.block.get_size() as u16 - 1) % 2; + let shift = (u16::from(curr.block.get_size()) - 1) % 2; if clockwise { curr.pos.0 = y; curr.pos.1 = w - 1 - x - shift; @@ -518,8 +529,8 @@ impl<'l> Schematic<'l> { let top_bound = dy + h as i16 - 1; let left_bound = dx; let bottom_bound = dy; - for Placement { pos, block, .. } in self.blocks.iter() { - let sz = block.get_size() as u16; + for Placement { pos, block, .. } in &self.blocks { + let sz = u16::from(block.get_size()); let (x0, y0, x1, y1) = ( pos.0 - (sz - 1) / 2, pos.1 - (sz - 1) / 2, @@ -539,7 +550,7 @@ impl<'l> Schematic<'l> { bottom = bottom_bound as u16 - y0; } } - if left > 0 || top > 0 || left > 0 || bottom > 0 { + if left > 0 || top > 0 || right > 0 || bottom > 0 { return Err(ResizeError::Truncated { right, top, @@ -549,7 +560,7 @@ impl<'l> Schematic<'l> { } self.width = w; self.height = h; - for Placement { pos, .. } in self.blocks.iter_mut() { + for Placement { pos, .. } in &mut self.blocks { pos.0 = (pos.0 as i16 + dx) as u16; pos.1 = (pos.1 as i16 + dy) as u16; } @@ -560,6 +571,7 @@ impl<'l> Schematic<'l> { self.mirror(true, true); } + #[must_use] pub fn pos_iter(&self) -> PosIter { PosIter { x: 0, @@ -573,10 +585,11 @@ impl<'l> Schematic<'l> { self.blocks.iter() } + #[must_use] pub fn compute_total_cost(&self) -> (ItemStorage, bool) { let mut cost = ItemStorage::new(); let mut sandbox = false; - for &Placement { block, .. } in self.blocks.iter() { + for &Placement { block, .. } in &self.blocks { if let Some(curr) = block.get_build_cost() { cost.add_all(curr, u32::MAX); } else { @@ -753,7 +766,7 @@ impl<'l> fmt::Display for Schematic<'l> { // find unique letters for each block, more common blocks pick first let mut name_cnt = HashMap::<&str, u16>::new(); - for p in self.blocks.iter() { + for p in &self.blocks { match name_cnt.entry(p.block.get_name()) { Entry::Occupied(mut e) => *e.get_mut() += 1, Entry::Vacant(e) => { @@ -770,7 +783,7 @@ impl<'l> fmt::Display for Schematic<'l> { 0x70u8, 0x00u8, 0x00u8, 0x40u8, 0x90u8, ]; let mut types = HashMap::<&str, char>::new(); - for &(name, _) in name_cnt.iter() { + for &(name, _) in &name_cnt { let mut found = false; for c in name.chars() { if c > ' ' && c <= '~' { @@ -807,7 +820,9 @@ impl<'l> fmt::Display for Schematic<'l> { } // coordinates start in the bottom left, so y starts at self.height - 1 - if self.blocks.len() > 0 { + if self.blocks.is_empty() { + write!(f, "<empty {} * {}>", self.width, self.height)?; + } else { for y in (0..self.height as usize).rev() { let mut x = 0usize; while x < self.width as usize { @@ -902,8 +917,6 @@ impl<'l> fmt::Display for Schematic<'l> { let v = *types.get(k).unwrap(); write!(f, "\n({v}) {k}")?; } - } else { - write!(f, "<empty {} * {}>", self.width, self.height)?; } Ok(()) } @@ -1007,7 +1020,7 @@ impl<'l> Serializer<Schematic<'l>> for SchematicSerializer<'l> { buff.write_u32(SCHEMATIC_HEADER)?; buff.write_u8(1)?; - let mut rbuff = DataWrite::new(); + let mut rbuff = DataWrite::default(); // don't have to check dimensions because they're already limited to MAX_DIMENSION rbuff.write_i16(data.width as i16)?; rbuff.write_i16(data.height as i16)?; @@ -1015,20 +1028,17 @@ impl<'l> Serializer<Schematic<'l>> for SchematicSerializer<'l> { return Err(WriteError::TagCount(data.tags.len())); } rbuff.write_u8(data.tags.len() as u8)?; - for (k, v) in data.tags.iter() { + for (k, v) in &data.tags { rbuff.write_utf(k)?; rbuff.write_utf(v)?; } // use string keys here to avoid issues with different block refs with the same name let mut block_map = HashMap::<&str, u32>::new(); let mut block_table = Vec::<&str>::new(); - for curr in data.blocks.iter() { - match block_map.entry(curr.block.get_name()) { - Entry::Vacant(e) => { - e.insert(block_table.len() as u32); - block_table.push(curr.block.get_name()); - } - _ => (), + for curr in &data.blocks { + if let Entry::Vacant(e) = block_map.entry(curr.block.get_name()) { + e.insert(block_table.len() as u32); + block_table.push(curr.block.get_name()); } } if block_table.len() > i8::MAX as usize { @@ -1036,13 +1046,13 @@ impl<'l> Serializer<Schematic<'l>> for SchematicSerializer<'l> { } // else: implies contents are also valid i8 (they're strictly less than the map length) rbuff.write_i8(block_table.len() as i8)?; - for &name in block_table.iter() { + for &name in &block_table { rbuff.write_utf(name)?; } // don't have to check data.blocks.len() because dimensions don't allow exceeding MAX_BLOCKS rbuff.write_i32(data.blocks.len() as i32)?; let mut num = 0; - for curr in data.blocks.iter() { + for curr in &data.blocks { rbuff.write_i8(block_map[curr.block.get_name()] as i8)?; rbuff.write_u32(u32::from(curr.pos))?; let data = match curr.state { @@ -1056,10 +1066,7 @@ impl<'l> Serializer<Schematic<'l>> for SchematicSerializer<'l> { assert_eq!(num, data.blocks.len()); // compress into the provided buffer - let raw = match rbuff.data { - data::WriteBuff::Vec(v) => v, - _ => unreachable!("write buffer not owned"), - }; + let data::WriteBuff::Vec(raw) = rbuff.data else { unreachable!("write buffer not owned") }; let mut comp = Compress::new(Compression::default(), true); // compress the immediate buffer into a temp buffer to copy it to buff? no thanks match buff.data { @@ -1261,11 +1268,11 @@ impl<'l> SchematicSerializer<'l> { } pub fn serialize_base64(&mut self, data: &Schematic<'l>) -> Result<String, W64Error> { - let mut buff = DataWrite::new(); + let mut buff = DataWrite::default(); self.serialize(&mut buff, data)?; let buff = buff.get_written(); // round up because of padding - let required = 4 * (buff.len() / 3 + if buff.len() % 3 != 0 { 1 } else { 0 }); + let required = 4 * (buff.len() / 3 + usize::from(buff.len() % 3 != 0)); let mut text = Vec::<u8>::new(); text.resize(required, 0); let n_out = base64::encode(buff, text.as_mut())?; diff --git a/src/exe/args.rs b/src/exe/args.rs index f037c12..46f8a42 100644 --- a/src/exe/args.rs +++ b/src/exe/args.rs @@ -86,13 +86,11 @@ where return Err(Error::EmptyName { pos: arg_off + pos }); } } - } else { - if let Err(val) = handler.on_literal(arg) { - return Err(Error::Handler { - pos: arg_off + pos, - val, - }); - } + } else if let Err(val) = handler.on_literal(arg) { + return Err(Error::Handler { + pos: arg_off + pos, + val, + }); } } } @@ -113,17 +111,11 @@ pub enum ArgCount { impl ArgCount { pub const fn has_value(&self) -> bool { - match self { - Self::Optional(..) | ArgCount::Required(..) => true, - _ => false, - } + matches!(self, Self::Optional(..) | ArgCount::Required(..)) } pub const fn is_required(&self) -> bool { - match self { - Self::Required(..) => true, - _ => false, - } + matches!(self, Self::Required(..)) } pub const fn get_max_count(&self) -> Option<usize> { @@ -196,25 +188,15 @@ pub enum OptionValue { impl OptionValue { pub const fn is_absent(&self) -> bool { - match self { - Self::Absent => true, - _ => false, - } + matches!(self, Self::Absent) } pub const fn is_present(&self) -> bool { - match self { - Self::Present | Self::Value(..) | Self::Values(..) => true, - _ => false, - } + matches!(self, Self::Present | Self::Value(..) | Self::Values(..)) } pub const fn has_value(&self) -> bool { - match self { - Self::Value(..) => true, - Self::Values(..) => true, - _ => false, - } + matches!(self, Self::Value(..) | Self::Values(..)) } pub const fn get_value(&self) -> Option<&String> { @@ -233,7 +215,7 @@ impl OptionValue { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct OptionHandler { options: Vec<(ArgOption, OptionValue)>, short_map: HashMap<char, usize>, @@ -242,39 +224,23 @@ pub struct OptionHandler { } impl OptionHandler { - pub fn new() -> Self { - Self { - options: Vec::new(), - short_map: HashMap::new(), - long_map: HashMap::new(), - literals: Vec::new(), - } - } - 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(AddArgError { - to_add: opt, - existing: &self.options[i].0, - }) - } - _ => (), - }, - _ => (), + if let Some(c) = opt.short { + if let Some(&i) = self.short_map.get(&c) { + return Err(AddArgError { + to_add: opt, + existing: &self.options[i].0, + }); + } } - match opt.long { - Some(ref s) => match self.long_map.get(&**s) { - Some(&i) => { - return Err(AddArgError { - to_add: opt, - existing: &self.options[i].0, - }) - } - _ => (), - }, - _ => (), + + if let Some(ref s) = opt.long { + if let Some(&i) = self.long_map.get(&**s) { + return Err(AddArgError { + to_add: opt, + existing: &self.options[i].0, + }); + } } let idx = self.options.len(); @@ -323,7 +289,7 @@ impl OptionHandler { let (ref o, ref mut curr) = self.options[idx]; match o.count { ArgCount::Forbidden => { - if let None = value { + if value.is_none() { if curr.is_absent() { *curr = OptionValue::Present; } diff --git a/src/exe/edit.rs b/src/exe/edit.rs index d89e0b2..80a1506 100644 --- a/src/exe/edit.rs +++ b/src/exe/edit.rs @@ -22,7 +22,7 @@ struct State<'l> { } pub fn main(mut args: Args, arg_off: usize) { - let mut handler = OptionHandler::new(); + let mut handler = OptionHandler::default(); let opt_file = handler .add(ArgOption::new( Some('f'), @@ -99,7 +99,7 @@ pub fn main(mut args: Args, arg_off: usize) { // give the user a chance to save their work if state.unsaved { - let mut data = DataWrite::new(); + let mut data = DataWrite::default(); match ss.serialize(&mut data, state.schematic.as_ref().unwrap()) { Ok(()) => { let data = data.get_written(); @@ -153,7 +153,7 @@ impl<'l> Tokenizer<'l> { self.skip_ws(); if let Some(curr) = self.0 { if curr.len() >= 2 && (curr.as_bytes()[0] == b'"' || curr.as_bytes()[0] == b'\'') { - match (&curr[1..]).find(curr.as_bytes()[0] as char) { + match (curr[1..]).find(curr.as_bytes()[0] as char) { None => { self.0 = None; Some(&curr[1..]) @@ -319,7 +319,7 @@ macro_rules! parse_num { $cmd.print_usage(0); return; } - Some(s) => match <$type>::from_str_radix(s, 10) { + Some(s) => match s.parse::<$type>() { Ok(v) => v, Err(e) => { print_err!(e, "Could not parse {}", $name); @@ -508,7 +508,6 @@ fn interpret(state: &mut State, cmd: &str) { }; if let Some(e) = result { print_err!(e, "Failed to place block at {x} / {y}"); - return; } } Some("rotate") => { @@ -793,7 +792,7 @@ fn interpret(state: &mut State, cmd: &str) { Command::Save.print_usage(0); return; } - let mut serial_buff = DataWrite::new(); + let mut serial_buff = DataWrite::default(); if let Err(e) = SchematicSerializer(state.reg).serialize(&mut serial_buff, schematic) { print_err!(e, "Could not serialize schematic"); return; @@ -1238,7 +1237,6 @@ fn interpret_sub(state: &mut State, tokens: &mut Tokenizer) { }; if let Some(e) = result { print_err!(e, "Failed to place block at {x} / {y}"); - return; } } Some("rotate") => { diff --git a/src/exe/print.rs b/src/exe/print.rs index 9a7faae..d1b79c5 100644 --- a/src/exe/print.rs +++ b/src/exe/print.rs @@ -11,7 +11,7 @@ use crate::args::{self, ArgCount, ArgOption, OptionHandler}; use crate::print_err; pub fn main(mut args: Args, arg_off: usize) { - let mut handler = OptionHandler::new(); + let mut handler = OptionHandler::default(); let opt_file = handler .add(ArgOption::new( Some('f'), diff --git a/src/item/storage.rs b/src/item/storage.rs index fd5be32..e6ec368 100644 --- a/src/item/storage.rs +++ b/src/item/storage.rs @@ -12,6 +12,7 @@ pub struct Storage { } impl Storage { + #[must_use] pub const fn new() -> Self { Self { base: Vec::new(), @@ -19,14 +20,17 @@ impl Storage { } } + #[must_use] pub fn is_empty(&self) -> bool { self.total == 0 } + #[must_use] pub fn get_total(&self) -> u64 { self.total } + #[must_use] pub fn get(&self, ty: item::Type) -> u32 { match self.base.get(u16::from(ty) as usize) { None => 0, @@ -40,12 +44,12 @@ impl Storage { None => { self.base.resize(idx + 1, 0); self.base[idx] = count; - self.total += count as u64; + self.total += u64::from(count); 0 } Some(curr) => { let prev = *curr; - self.total = self.total - prev as u64 + count as u64; + self.total = self.total - u64::from(prev) + u64::from(count); *curr = count; prev } @@ -59,14 +63,14 @@ impl Storage { let actual = add.min(max); self.base.resize(idx + 1, 0); self.base[idx] = actual; - self.total += add as u64; + self.total += u64::from(add); (actual, actual) } Some(curr) => { if *curr < max { let actual = add.min(max - *curr); *curr += actual; - self.total += actual as u64; + self.total += u64::from(actual); (actual, *curr) } else { (0, *curr) @@ -87,7 +91,7 @@ impl Storage { if add <= max { self.base.resize(idx + 1, 0); self.base[idx] = add; - self.total += add as u64; + self.total += u64::from(add); Ok((add, add)) } else { Err(TryAddError { @@ -101,7 +105,7 @@ impl Storage { Some(curr) => { if *curr <= max && max - *curr <= add { *curr += add; - self.total += add as u64; + self.total += u64::from(add); Ok((add, *curr)) } else { Err(TryAddError { @@ -122,7 +126,7 @@ impl Storage { if *curr > min { let actual = sub.min(*curr - min); *curr -= actual; - self.total -= actual as u64; + self.total -= u64::from(actual); (actual, *curr) } else { (0, *curr) @@ -148,7 +152,7 @@ impl Storage { Some(curr) => { if *curr >= min && *curr - min >= sub { *curr -= sub; - self.total -= sub as u64; + self.total -= u64::from(sub); Ok((sub, *curr)) } else { Err(TrySubError { @@ -177,7 +181,7 @@ impl Storage { if curr < max_each { let actual = (*add).min(max_each - curr); self.base[idx] += actual; - added += actual as u64; + added += u64::from(actual); } } // process the final element (which we've retrieved first) @@ -185,7 +189,7 @@ impl Storage { if curr < max_each { let actual = (*add_last).min(max_each - curr); self.base[last] += actual; - added += actual as u64; + added += u64::from(actual); } // update total self.total += added; @@ -209,7 +213,7 @@ impl Storage { let actual = (*add).min(max_each - curr); self.base[idx] += actual; *add -= actual; - added += actual as u64; + added += u64::from(actual); } } // process the final element (which we've retrieved first) @@ -218,7 +222,7 @@ impl Storage { let actual = (*add_last).min(max_each - curr); self.base[last] += actual; *add_last -= actual; - added += actual as u64; + added += u64::from(actual); } // update totals self.total += added; @@ -237,7 +241,7 @@ impl Storage { if *curr > min_each { let actual = (*sub).min(*curr - min_each); self.base[idx] -= actual; - subbed += actual as u64; + subbed += u64::from(actual); } } else { break; @@ -258,12 +262,12 @@ impl Storage { let lhs = &mut self.base[..end]; let rhs = &mut other.base[..end]; // process items by increasing ID - for (l, r) in lhs.into_iter().zip(rhs) { + for (l, r) in lhs.iter_mut().zip(rhs) { if *l > min_each && *r > min_each { let actual = (*l - min_each).min(*r - min_each); *l -= actual; *r -= actual; - subbed -= actual as u64; + subbed -= u64::from(actual); } } // update totals @@ -273,14 +277,16 @@ impl Storage { (subbed, self.total, other.total) } - pub fn iter<'s>(&'s self) -> Iter<'s> { + #[must_use] + pub fn iter(&self) -> Iter<'_> { Iter { base: self.base.iter().enumerate(), all: true, } } - pub fn iter_nonzero<'s>(&'s self) -> Iter<'s> { + #[must_use] + pub fn iter_nonzero(&self) -> Iter<'_> { Iter { base: self.base.iter().enumerate(), all: false, @@ -288,7 +294,7 @@ impl Storage { } pub fn clear(&mut self) { - self.base.clear() + self.base.clear(); } } @@ -375,7 +381,7 @@ impl<'l> Iterator for Iter<'l> { type Item = (item::Type, u32); fn next(&mut self) -> Option<Self::Item> { - while let Some((idx, cnt)) = self.base.next() { + for (idx, cnt) in self.base.by_ref() { if *cnt > 0 || self.all { if let Ok(ty) = item::Type::try_from(idx as u16) { return Some((ty, *cnt)); diff --git a/src/logic/mod.rs b/src/logic/mod.rs index cd9ba52..967ca22 100644 --- a/src/logic/mod.rs +++ b/src/logic/mod.rs @@ -23,7 +23,7 @@ macro_rules!match_select } impl LogicField { - pub fn is_readable(&self) -> bool { + #[must_use] pub fn is_readable(&self) -> bool { match_select!( self, LogicField, @@ -73,7 +73,7 @@ impl LogicField { ) } - pub fn is_writable(&self) -> bool { + #[must_use] pub fn is_writable(&self) -> bool { match_select!(self, LogicField, Enabled, Shoot, ShootP, Config, Color) } } diff --git a/src/registry.rs b/src/registry.rs index 240fb65..938836a 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -12,22 +12,24 @@ pub struct Registry<'l, E: RegistryEntry + fmt::Debug + 'static> { by_name: HashMap<&'l str, &'l E>, } -impl<'l, E: RegistryEntry + fmt::Debug + 'static> Registry<'l, E> { - pub fn new() -> Self { +impl<'l, E: RegistryEntry + fmt::Debug + 'static> Default for Registry<'l, E> { + fn default() -> Self { Self { by_name: HashMap::new(), } } +} +impl<'l, E: RegistryEntry + fmt::Debug + 'static> Registry<'l, E> { pub fn register(&mut self, val: &'l E) -> Result<&'l E, RegisterError<'l, E>> { - match self.by_name.entry(&val.get_name()) { + match self.by_name.entry(val.get_name()) { Entry::Occupied(e) => Err(RegisterError(e.get())), Entry::Vacant(e) => Ok(e.insert(val)), } } - pub fn get(&self, name: &str) -> Option<&'l E> { - self.by_name.get(name).map(|&r| r) + #[must_use] pub fn get(&self, name: &str) -> Option<&'l E> { + self.by_name.get(name).copied() } } diff --git a/src/team.rs b/src/team.rs index d6f32fc..1c0e4f1 100644 --- a/src/team.rs +++ b/src/team.rs @@ -7,11 +7,11 @@ use crate::content::{Content, Type}; pub struct Team(u8); impl Team { - pub fn of(id: u8) -> Self { + #[must_use] pub fn of(id: u8) -> Self { Self(id) } - pub fn is_base(&self) -> bool { + #[must_use] pub fn is_base(&self) -> bool { self.0 < 6 } } @@ -26,7 +26,7 @@ impl TryFrom<u16> for Team { type Error = TryFromU16Error; fn try_from(value: u16) -> Result<Self, Self::Error> { - if value <= u8::MAX as u16 { + if u8::try_from(value).is_ok() { Ok(Team(value as u8)) } else { Err(TryFromU16Error(value)) @@ -45,7 +45,7 @@ impl From<Team> for u8 { impl From<Team> for u16 { fn from(value: Team) -> Self { - value.0 as u16 + u16::from(value.0) } } @@ -79,7 +79,7 @@ impl Content for Team { } fn get_id(&self) -> u16 { - self.0 as u16 + u16::from(self.0) } fn get_name(&self) -> &'static str { @@ -93,7 +93,7 @@ impl Content for Team { // dark magic: offsets manually computed, then rely on the format "...|team#{i}|..." i @ 6..=9 => { // length: 7 ("team#" (5) + 1 digit + "|" (1)) - let s = 0 + ((i - 6) as usize) * 7; + let s = ((i - 6) as usize) * 7; &TEAM_NAMES[s..s + 6] // exclude the trailing "|" } i @ 10..=99 => { diff --git a/src/utils/once_cell.rs b/src/utils/once_cell.rs index 4bfd3eb..9dda9ff 100644 --- a/src/utils/once_cell.rs +++ b/src/utils/once_cell.rs @@ -13,6 +13,7 @@ pub struct OnceCell<T> { } impl<T> OnceCell<T> { + #[must_use] pub const fn new() -> Self { Self { value: UnsafeCell::new(MaybeUninit::uninit()), @@ -30,7 +31,7 @@ impl<T> OnceCell<T> { pub fn get(&self) -> Option<&T> { if self.state.load(Ordering::Acquire) == STATE_READY { // SAFETY: won't be overwritten for the lifetime of this reference - Some(unsafe { (&*self.value.get()).assume_init_ref() }) + Some(unsafe { (*self.value.get()).assume_init_ref() }) } else { None } @@ -41,7 +42,7 @@ impl<T> OnceCell<T> { match self.state.load(Ordering::Acquire) { STATE_INIT => return None, STATE_LOCKED => (), // continue - STATE_READY => return Some(unsafe { (&*self.value.get()).assume_init_ref() }), + STATE_READY => return Some(unsafe { (*self.value.get()).assume_init_ref() }), x => unreachable!("invalid state {x}"), } } @@ -61,7 +62,7 @@ impl<T> OnceCell<T> { self.state.store(STATE_READY, Ordering::Release); return written; } - Err(STATE_READY) => return unsafe { (&*self.value.get()).assume_init_ref() }, + Err(STATE_READY) => return unsafe { (*self.value.get()).assume_init_ref() }, Err(..) => (), // locked or spurious failure } } @@ -82,7 +83,7 @@ impl<T> OnceCell<T> { Ok(written) } // SAFETY: guaranteed to be initialized & protected by acquire ordering - Err(STATE_READY) => return Ok(unsafe { (&*self.value.get()).assume_init_ref() }), + Err(STATE_READY) => return Ok(unsafe { (*self.value.get()).assume_init_ref() }), Err(..) => Err(value), // locked or spurious failure } } @@ -126,7 +127,7 @@ impl<T> OnceCell<T> { }; // SAFETY: just in case AtomicU8 has a drop handler unsafe { - ptr::drop_in_place(&mut self.state as *mut _); + ptr::drop_in_place(std::ptr::addr_of_mut!(self.state)); } std::mem::forget(self); inner |