mindustry logic execution, map- and schematic- parsing and rendering
clippy it
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | build.rs | 4 | ||||
| -rw-r--r-- | src/block/distribution.rs | 9 | ||||
| -rw-r--r-- | src/block/liquid.rs | 9 | ||||
| -rw-r--r-- | src/block/logic.rs | 10 | ||||
| -rw-r--r-- | src/block/mod.rs | 28 | ||||
| -rw-r--r-- | src/block/power.rs | 4 | ||||
| -rw-r--r-- | src/block/simple.rs | 4 | ||||
| -rw-r--r-- | src/content.rs | 7 | ||||
| -rw-r--r-- | src/data/autotile.rs | 21 | ||||
| -rw-r--r-- | src/data/base64.rs | 4 | ||||
| -rw-r--r-- | src/data/dynamic.rs | 8 | ||||
| -rw-r--r-- | src/data/map.rs | 55 | ||||
| -rw-r--r-- | src/data/mod.rs | 18 | ||||
| -rw-r--r-- | src/data/renderer.rs | 31 | ||||
| -rw-r--r-- | src/data/schematic.rs | 31 | ||||
| -rw-r--r-- | src/item/storage.rs | 11 | ||||
| -rw-r--r-- | src/logic/mod.rs | 115 | ||||
| -rw-r--r-- | src/team.rs | 12 | ||||
| -rw-r--r-- | src/utils/lazy.rs | 6 |
20 files changed, 209 insertions, 180 deletions
@@ -1,6 +1,6 @@ [package] name = "mindus" -version = "3.0.1" +version = "3.0.3" edition = "2021" description = "A library for working with mindustry data formats (eg schematics and maps) (fork of plandustry)" authors = [ @@ -59,10 +59,10 @@ fn main() { } let mut warmup = File::create(o.join("warmup.rs")).unwrap(); - wr!(warmup => "/// SAFETY: this function must only be called once."); + wr!(warmup => "/// # Safety\n///\n/// this function must only be called once."); wr!(warmup => "pub unsafe fn warmup() {{"); wr!(warmup => "LazyLock::load(&EMPTY);"); - for e in walkdir.into_iter().filter_map(|e| e.ok()) { + for e in walkdir.into_iter().filter_map(Result::ok) { let path = e.path(); if path.is_file() && let Some(e) = path.extension() && e == "png" { let p = DynamicImage::from_decoder(PngDecoder::new(BufReader::new(File::open(path).unwrap())).unwrap()).unwrap().into_rgba8(); diff --git a/src/block/distribution.rs b/src/block/distribution.rs index aa64a13..413f903 100644 --- a/src/block/distribution.rs +++ b/src/block/distribution.rs @@ -214,10 +214,11 @@ impl BlockLogic for ItemBlock { fn rotate_state(&self, _: &mut State, _: bool) {} fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> { - match Self::get_state(state) { - None => Ok(DynData::Empty), - Some(item) => Ok(DynData::Content(content::Type::Item, (*item).into())), - } + Ok(Self::get_state(state) + .as_ref() + .map_or(DynData::Empty, |&item| { + DynData::Content(content::Type::Item, item.into()) + })) } fn draw( diff --git a/src/block/liquid.rs b/src/block/liquid.rs index 98cc65c..4816e5a 100644 --- a/src/block/liquid.rs +++ b/src/block/liquid.rs @@ -102,10 +102,11 @@ impl BlockLogic for FluidBlock { } fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> { - match Self::get_state(state) { - None => Ok(DynData::Empty), - Some(fluid) => Ok(DynData::Content(content::Type::Fluid, (*fluid).into())), - } + Ok(Self::get_state(state) + .as_ref() + .map_or(DynData::Empty, |&fluid| { + DynData::Content(content::Type::Fluid, fluid.into()) + })) } fn draw( diff --git a/src/block/logic.rs b/src/block/logic.rs index ebdda1e..4179b89 100644 --- a/src/block/logic.rs +++ b/src/block/logic.rs @@ -68,17 +68,17 @@ impl CanvasBlock { assert!(size != 0, "invalid size"); assert!(canvas_size != 0, "invalid size"); Self { - canvas_size, size, symmetric, build_cost, + canvas_size, } } state_impl!(pub RgbImage); } -fn deser_canvas_image(b: Vec<u8>, size: usize) -> RgbImage { +fn deser_canvas_image(b: &[u8], size: usize) -> RgbImage { let mut p = RgbImage::new(size as u32, size as u32); for i in 0..(size * size) { let offset = i * 3; @@ -91,7 +91,7 @@ fn deser_canvas_image(b: Vec<u8>, size: usize) -> RgbImage { i as u32 % size as u32, i as u32 / size as u32, PALETTE[n as usize], - ) + ); } p } @@ -106,7 +106,7 @@ impl BlockLogic for CanvasBlock { fn deserialize_state(&self, data: DynData) -> Result<Option<State>, DeserializeError> { match data { DynData::ByteArray(b) => Ok(Some(Self::create_state(deser_canvas_image( - b, + &b, self.canvas_size as usize, )))), _ => Err(DeserializeError::InvalidType { @@ -198,7 +198,7 @@ impl BlockLogic for CanvasBlock { let mut b = vec![0; n]; buff.read_bytes(&mut b)?; build.state = Some(Self::create_state(deser_canvas_image( - b, + &b, self.canvas_size as usize, ))); Ok(()) diff --git a/src/block/mod.rs b/src/block/mod.rs index 238f28b..55bb35e 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -3,7 +3,7 @@ //! categorized as mindustry categorizes them in its assets folder, for easy drawing. //! //! with the exception of sandbox, that is. -use bobbin_bits::U4::{self, *}; +use bobbin_bits::U4::{self, B0000, B0001, B0010, B0100, B1000}; use std::any::Any; use std::error::Error; use std::fmt; @@ -258,24 +258,29 @@ impl Block { logic: BlockLogicEnum, image: Option<[&'static Lock<RgbaImage>; 3]>, ) -> Self { - Self { name, logic, image } + Self { image, name, logic } } /// this blocks name /// ``` /// assert!(mindus::block::distribution::DISTRIBUTOR.name() == "distributor") /// ``` + #[must_use] pub fn name(&self) -> &'static str { self.name } /// should you send context to [`image`]? + #[must_use] pub fn wants_context(&self) -> bool { self.logic.want_context() } /// draw this block, with this state - /// SAFETY: call [`warmup`](crate::warmup) first + /// # Safety + /// + /// UB if called before [`warmup`](crate::warmup) + #[must_use] pub unsafe fn image( &self, state: Option<&State>, @@ -284,22 +289,25 @@ impl Block { scale: Scale, ) -> ImageHolder { if let Some(imgs) = self.image { - return ImageHolder::from(unsafe { Lock::get(imgs.get_unchecked(scale as usize)) }); + return ImageHolder::from(Lock::get(imgs[scale as usize])); } self.logic.draw(self.name, state, context, rot, scale) } /// size. + #[must_use] pub fn get_size(&self) -> u8 { self.logic.get_size() } /// does it matter if its rotated + #[must_use] pub fn is_symmetric(&self) -> bool { self.logic.is_symmetric() } /// cost + #[must_use] pub fn get_build_cost(&self) -> Option<ItemStorage> { self.logic.create_build_cost() } @@ -371,13 +379,13 @@ pub enum Rotation { impl Rotation { #[must_use] /// count rotations - pub fn count(self) -> u8 { + pub const fn count(self) -> u8 { self as u8 } #[must_use] /// mask - pub fn mask(self) -> U4 { + pub const fn mask(self) -> U4 { match self { Rotation::Up => B1000, Rotation::Right => B0100, @@ -388,7 +396,7 @@ impl Rotation { #[must_use] /// character of this rot (Right => >, Up => ^, Left => <, Down => v) - pub fn ch(self) -> char { + pub const fn ch(self) -> char { match self { Rotation::Right => '>', Rotation::Up => '^', @@ -399,7 +407,7 @@ impl Rotation { #[must_use] /// mirror the directions. - pub fn mirrored(self, horizontally: bool, vertically: bool) -> Self { + pub const fn mirrored(self, horizontally: bool, vertically: bool) -> Self { match self { Self::Right => { if horizontally { @@ -439,7 +447,7 @@ impl Rotation { #[must_use] /// rotate the rotation - pub fn rotated(self, clockwise: bool) -> Self { + pub const fn rotated(self, clockwise: bool) -> Self { match self { Self::Right => { if clockwise { @@ -479,7 +487,7 @@ impl Rotation { #[must_use] /// rotate 180 - pub fn rotated_180(self) -> Self { + pub const fn rotated_180(self) -> Self { match self { Self::Right => Self::Left, Self::Up => Self::Down, diff --git a/src/block/power.rs b/src/block/power.rs index e04481d..ada60c9 100644 --- a/src/block/power.rs +++ b/src/block/power.rs @@ -116,7 +116,7 @@ impl BlockLogic for ConnectorBlock { } fn mirror_state(&self, state: &mut State, horizontally: bool, vertically: bool) { - for (dx, dy) in Self::get_state_mut(state).iter_mut() { + for (dx, dy) in &mut *Self::get_state_mut(state) { if horizontally { *dx = -*dx; } @@ -127,7 +127,7 @@ impl BlockLogic for ConnectorBlock { } fn rotate_state(&self, state: &mut State, clockwise: bool) { - for (dx, dy) in Self::get_state_mut(state).iter_mut() { + for (dx, dy) in &mut *Self::get_state_mut(state) { let (cdx, cdy) = (*dx, *dy); *dx = if clockwise { cdy } else { -cdy }; *dy = if clockwise { -cdx } else { cdx }; diff --git a/src/block/simple.rs b/src/block/simple.rs index a07a6ea..1c00079 100644 --- a/src/block/simple.rs +++ b/src/block/simple.rs @@ -3,7 +3,7 @@ use crate::item; macro_rules! state_impl { ($vis:vis $type:ty) => { - $vis fn get_state(state: &$crate::block::State) -> &$type + #[must_use] $vis fn get_state(state: &$crate::block::State) -> &$type where Self: Sized { state.downcast_ref::<$type>().unwrap() } @@ -23,7 +23,7 @@ macro_rules! state_impl { pub(crate) use state_impl; /// draw is called with self, name, state, context, rotation -/// read is called with build, reg, entity_mapping, buff +/// read is called with build, reg, `entity_mapping`, buff macro_rules! make_simple { ($name: ident, $draw: expr, $read: expr, $wants_context: literal) => { pub struct $name { diff --git a/src/content.rs b/src/content.rs index 44db19f..65619e4 100644 --- a/src/content.rs +++ b/src/content.rs @@ -95,7 +95,8 @@ macro_rules! color_content_enum { }); impl Type { - pub fn color(&self) -> image::Rgb<u8> { + #[must_use] + pub const fn color(&self) -> image::Rgb<u8> { match &self { $(Self::[<$val:camel>] => { image::Rgb(color_hex::color_from_hex!($col)) @@ -139,7 +140,7 @@ macro_rules! gen_by_id { } impl Type { - pub fn get(&self, id: u16) -> Result<Box<dyn Content>, Box<dyn Error>> { + pub fn get(self, id: u16) -> Result<Box<dyn Content>, Box<dyn Error>> { match self { Self::Item => gen_by_id!(crate::item::Type, id), Self::Block => gen_by_id!(crate::block::content::Type, id), @@ -147,7 +148,7 @@ impl Type { Self::Modifier => gen_by_id!(crate::modifier::Type, id), Self::Unit => gen_by_id!(crate::unit::Type, id), Self::Team => gen_by_id!(crate::team::Team, id), - _ => Ok(Box::new(Generic(*self, id))), + _ => Ok(Box::new(Generic(self, id))), } } } diff --git a/src/data/autotile.rs b/src/data/autotile.rs index 28b864d..76aed59 100644 --- a/src/data/autotile.rs +++ b/src/data/autotile.rs @@ -81,7 +81,7 @@ fn print_crosses(v: Vec<Cross<'_>>, height: usize) -> String { for c in v.chunks(height) { for c in c { s.push(c[0].map_or('_', |(_, r)| r.ch())); - for c in c[1..].iter() { + for c in &c[1..] { s.push(','); s.push(c.map_or('_', |(_, r)| r.ch())); } @@ -97,7 +97,10 @@ pub fn tile(ctx: &RenderingContext<'_>, name: &str, rot: Rotation, s: Scale) -> } pub fn mask2rotations(mask: U4, rot: Rotation) -> (u8, u8, u8) { - use U4::*; + use U4::{ + B0000, B0001, B0010, B0011, B0100, B0101, B0110, B0111, B1000, B1001, B1010, B1011, B1100, + B1101, B1110, B1111, + }; macro_rules! p { ($image:literal, $rotation:literal) => { ($image, $rotation, 0) @@ -113,14 +116,14 @@ pub fn mask2rotations(mask: U4, rot: Rotation) -> (u8, u8, u8) { Rotation::Down => p!(1, 1, FLIP_Y), // ┐ Rotation::Right => p!(0, 0), // ─ Rotation::Up => p!(1, 3), // ┘ - _ => unreachable!(), + Rotation::Left => unreachable!(), }, // from below B0010 => match rot { Rotation::Left => p!(1, 2), // ┐ Rotation::Right => p!(1, 1), // ┌ Rotation::Up => p!(0, 3), // │ - _ => unreachable!(), + Rotation::Down => unreachable!(), }, // from bottom + left B0011 => match rot { @@ -133,7 +136,7 @@ pub fn mask2rotations(mask: U4, rot: Rotation) -> (u8, u8, u8) { Rotation::Left => p!(0, 2), // ─ Rotation::Down => p!(1, 1), // ┌ Rotation::Up => p!(1, 1, FLIP_X), // └ - _ => unreachable!(), + Rotation::Right => unreachable!(), }, // from sides B0101 => match rot { @@ -157,7 +160,7 @@ pub fn mask2rotations(mask: U4, rot: Rotation) -> (u8, u8, u8) { Rotation::Down => p!(0, 1), // │ Rotation::Left => p!(1, 0, FLIP_X), // ┘ Rotation::Right => p!(1, 0), // └ - _ => unreachable!(), + Rotation::Up => unreachable!(), }, // from top and left B1001 => match rot { @@ -219,7 +222,7 @@ pub fn flrot(flip: u8, rot: u8, with: &mut ImageHolder) { with.rotate(rot); } -/// TODO figure out if a flip is cheaper than a rotate_270 +/// TODO figure out if a flip is cheaper than a `rotate_270` pub fn rotations2tile((index, rot, flip): (u8, u8, u8), name: &str, scale: Scale) -> ImageHolder { let mut p = match index { 0 => { @@ -257,7 +260,7 @@ pub fn mask(ctx: &RenderingContext, rot: Rotation, n: &str) -> U4 { } }}; } - use Rotation::*; + use Rotation::{Down, Left, Right, Up}; let mut x = 0b0000; x |= 8 * c!(ctx.cross[0], rot, n, Down); @@ -273,7 +276,7 @@ pub trait RotationState { pub trait BlockState<'l> { fn get_block(&'l self) -> Option<&'l Block>; } -pub(crate) trait Crossable { +pub trait Crossable { fn cross(&self, j: usize, c: &PositionContext) -> Cross; } diff --git a/src/data/base64.rs b/src/data/base64.rs index 2651b08..303e9e0 100644 --- a/src/data/base64.rs +++ b/src/data/base64.rs @@ -3,10 +3,10 @@ pub use base64::{DecodeSliceError as DecodeError, EncodeSliceError as EncodeErro const BASE64: general_purpose::GeneralPurpose = general_purpose::STANDARD; -pub(crate) fn encode(input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> { +pub fn encode(input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> { BASE64.encode_slice(input, output) } -pub(crate) fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> { +pub fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> { BASE64.decode_slice(input, output) } diff --git a/src/data/dynamic.rs b/src/data/dynamic.rs index b901725..877a612 100644 --- a/src/data/dynamic.rs +++ b/src/data/dynamic.rs @@ -245,7 +245,7 @@ impl Serializer<DynData> for DynSerializer { } buff.write_u8(6)?; buff.write_i16(arr.len() as i16)?; - for &v in arr.iter() { + for &v in arr { buff.write_i32(v)?; } Ok(()) @@ -262,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() { + for &(x, y) in arr { buff.write_i32((i32::from(x) << 16) | (i32::from(y) & 0xFFFF))?; } Ok(()) @@ -313,7 +313,7 @@ impl Serializer<DynData> for DynSerializer { } buff.write_u8(16)?; buff.write_i32(arr.len() as i32)?; - for &b in arr.iter() { + for &b in arr { buff.write_bool(b)?; } Ok(()) @@ -329,7 +329,7 @@ impl Serializer<DynData> for DynSerializer { } buff.write_u8(18)?; buff.write_i16(arr.len() as i16)?; - for &(x, y) in arr.iter() { + for &(x, y) in arr { buff.write_f32(x)?; buff.write_f32(y)?; } diff --git a/src/data/map.rs b/src/data/map.rs index acd0c88..2545a65 100644 --- a/src/data/map.rs +++ b/src/data/map.rs @@ -99,6 +99,7 @@ pub struct Tile<'l> { pub type EntityMapping = HashMap<u8, Box<dyn Content>>; impl<'l> Tile<'l> { + #[must_use] pub fn new(floor: BlockEnum, ore: BlockEnum) -> Self { Self { floor, @@ -119,7 +120,8 @@ impl<'l> Tile<'l> { }); } - pub fn build(&self) -> Option<&Build<'l>> { + #[must_use] + pub const fn build(&self) -> Option<&Build<'l>> { self.build.as_ref() } @@ -128,6 +130,7 @@ impl<'l> Tile<'l> { /// ._. /// /// dont think about it too much + #[must_use] pub fn size(&self) -> u8 { if let Some(b) = &self.build { return b.block.get_size(); @@ -135,6 +138,11 @@ impl<'l> Tile<'l> { 1 } + /// Draw the floor of this tile + /// + /// # Safety + /// + /// UB if called before [`warmup`](crate::warmup) pub unsafe fn floor_image(&self, s: Scale) -> ImageHolder { macro_rules! lo { ($v:expr => [$(|)? $($k:literal $(|)?)+], $scale: ident) => { paste::paste! { @@ -212,8 +220,11 @@ impl<'l> Tile<'l> { floor() } + /// Draw this tiles build. + /// /// # Safety - /// Must call [`warmup`](crate::warmup) first + /// UB if called before [`warmup`](crate::warmup) + #[must_use] pub unsafe fn build_image(&self, context: Option<&RenderingContext>, s: Scale) -> ImageHolder { // building covers floore let Some(b) = &self.build else { @@ -232,12 +243,12 @@ impl std::fmt::Debug for Tile<'_> { if self.ore != BlockEnum::Air { format!("+{}", self.ore.get_name()) } else { - "".into() + String::new() }, if let Some(build) = &self.build { format!(":{}", build.block.name()) } else { - "".to_string() + String::new() } ) } @@ -291,10 +302,7 @@ impl Clone for Build<'_> { block: self.block, items: self.items.clone(), liquids: self.liquids.clone(), - state: match self.state { - None => None, - Some(ref s) => Some(self.block.clone_state(s)), - }, + state: self.state.as_ref().map(|s| self.block.clone_state(s)), rotation: self.rotation, team: self.team, data: self.data, @@ -303,23 +311,25 @@ impl Clone for Build<'_> { } impl<'l> Build<'l> { + #[must_use] pub fn new(block: &'l Block) -> Build<'l> { Self { block, - items: Default::default(), - liquids: Default::default(), - state: Default::default(), + items: Storage::default(), + liquids: Storage::default(), + state: None, rotation: Rotation::Up, team: team::SHARDED, data: 0, } } - pub unsafe fn image(&self, context: Option<&RenderingContext>, s: Scale) -> ImageHolder { + unsafe fn image(&self, context: Option<&RenderingContext>, s: Scale) -> ImageHolder { self.block .image(self.state.as_ref(), context, self.rotation, s) } + #[must_use] pub fn name(&self) -> &str { self.block.name() } @@ -347,17 +357,13 @@ impl<'l> Build<'l> { mask = buff.read_u8()?; } - const ITEMS: u8 = 1; - const POWER: u8 = 2; - const LIQUIDS: u8 = 4; - - if mask & ITEMS != 0 { + if mask & 1 != 0 { read_items(buff, &mut self.items)?; } - if mask & POWER != 0 { + if mask & 2 != 0 { read_power(buff)?; } - if mask & LIQUIDS != 0 { + if mask & 4 != 0 { read_liquids(buff, &mut self.liquids)?; } // "efficiency"? @@ -507,6 +513,7 @@ impl<'l> Crossable for Map<'l> { } impl<'l> Map<'l> { + #[must_use] pub fn new(width: usize, height: usize, tags: HashMap<String, String>) -> Self { Self { tiles: vec![Tile::new(BlockEnum::Stone, BlockEnum::Air); width * height], @@ -604,7 +611,7 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { let consecutives = buff.read_u8()? as usize; if consecutives > 0 { for i in (i + 1)..(i + 1 + consecutives) { - map[i] = Tile::new(floor, ore) + map[i] = Tile::new(floor, ore); } i += consecutives; } @@ -619,14 +626,14 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { let central = if entity { buff.read_bool()? } else { false }; let block = BlockEnum::try_from(block_id) .map_err(|_| ReadError::NoSuchBlock(block_id.to_string()))?; - let block = if block != BlockEnum::Air { + let block = if block == BlockEnum::Air { + None + } else { Some( self.0 .get(block.get_name()) .ok_or_else(|| ReadError::NoSuchBlock(block.to_string()))?, ) - } else { - None }; if central { if let Some(block) = block { @@ -665,7 +672,7 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { } i += consecutives; } - i += 1 + i += 1; } m = Some(map); Ok::<(), ReadError>(()) diff --git a/src/data/mod.rs b/src/data/mod.rs index 6a8c533..5d950bf 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -54,7 +54,7 @@ macro_rules! make_read { impl<'d> DataRead<'d> { #[must_use] - pub fn new(data: &'d [u8]) -> Self { + pub const fn new(data: &'d [u8]) -> Self { Self { data, read: 0 } } @@ -143,12 +143,11 @@ impl<'d> DataRead<'d> { match r { Err(e) => { // skip this chunk - if len < self.read { - #[cfg(debug_assertions)] - panic!("overread; supposed to read {len}; read {}", self.read); - #[cfg(not(debug_assertions))] - return Err(e); - } + assert!( + len >= self.read, + "overread; supposed to read {len}; read {}", + self.read + ); let n = len - self.read; if n != 0 { #[cfg(debug_assertions)] @@ -321,7 +320,7 @@ impl<'d> DataWrite<'d> { } #[must_use] - pub fn is_owned(&self) -> bool { + pub const fn is_owned(&self) -> bool { matches!(self.data, WriteBuff::Vec(..)) } @@ -336,6 +335,7 @@ impl<'d> DataWrite<'d> { /// eat this datawrite /// /// panics if ref write buffer + #[must_use] pub fn consume(self) -> Vec<u8> { match self.data { WriteBuff::Vec(v) => v, @@ -449,7 +449,7 @@ impl<'d> TryFrom<DataWrite<'d>> for Vec<u8> { fn try_from(value: DataWrite<'d>) -> Result<Self, Self::Error> { match value.data { WriteBuff::Vec(v) => Ok(v), - _ => Err(()), + WriteBuff::Ref { .. } => Err(()), } } } diff --git a/src/data/renderer.rs b/src/data/renderer.rs index 70babd6..adb7d63 100644 --- a/src/data/renderer.rs +++ b/src/data/renderer.rs @@ -21,6 +21,7 @@ pub enum ImageHolder { } impl ImageHolder { + #[must_use] pub fn own(self) -> RgbaImage { match self { Self::Own(x) => x, @@ -94,7 +95,7 @@ pub enum Scale { } impl Scale { - fn px(self) -> u8 { + pub const fn px(self) -> u8 { match self { Self::Full => 32, Self::Quarter => 32 / 4, @@ -161,7 +162,10 @@ pub(crate) use load; /// trait for renderable objects pub trait Renderable { /// create a picture - /// SAFETY: call the [warmup] function first. + /// + /// # Safety + /// + /// UB if called before [`warmup`](crate::warmup) unsafe fn render(&self) -> RgbImage; } @@ -178,6 +182,10 @@ impl Renderable for Schematic<'_> { /// // this is now safe, because we have warmed up /// let output /*: RgbImage */ = unsafe { s.render() }; /// ``` + /// + /// # Safety + /// + /// UB if called before [`warmup`](crate::warmup) unsafe fn render(&self) -> RgbImage { // fill background let mut bg = RgbImage::repeated( @@ -243,6 +251,10 @@ impl Renderable for Schematic<'_> { } impl Renderable for Map<'_> { + /// Draws a map + /// + /// # Safety + /// UB if called before [`warmup`](crate::warmup) unsafe fn render(&self) -> RgbImage { let scale = if self.width + self.height < 2000 { Scale::Quarter @@ -296,8 +308,19 @@ impl Renderable for Map<'_> { } } +#[allow(clippy::needless_doctest_main)] /// Loads all the images into memory (about 300mb) -/// SAFETY: only call once. or else. +/// This is a necessary function. Call it once in main. +/// +/// ``` +/// fn main() { +/// unsafe { mindus::warmup(); } +/// } +/// ``` +/// +/// # Safety +/// +/// only call once, else UB pub unsafe fn warmup() { full::warmup(); quar::warmup(); @@ -324,7 +347,7 @@ fn all_blocks() { } let name = dbg!(t.get_name()); let t = reg.get(name).unwrap(); - unsafe { + let _ = unsafe { t.image( None, Some(&RenderingContext { diff --git a/src/data/schematic.rs b/src/data/schematic.rs index de606ca..4357ed4 100644 --- a/src/data/schematic.rs +++ b/src/data/schematic.rs @@ -39,6 +39,7 @@ impl fmt::Debug for Placement<'_> { impl<'l> Placement<'l> { /// make a placement from a block + #[must_use] pub fn new(block: &'l Block) -> Self { Self { block, @@ -59,7 +60,10 @@ impl<'l> Placement<'l> { } /// draws this placement in particular - /// SAFETY: call [`warmup`](crate::warmup) first + /// + /// # Safety + /// UB if called before [`warmup`](crate::warmup) + #[must_use] pub unsafe fn image( &self, context: Option<&RenderingContext>, @@ -116,10 +120,7 @@ impl<'l> Clone for Placement<'l> { fn clone(&self) -> Self { Self { block: self.block, - state: match self.state { - None => None, - Some(ref s) => Some(self.block.clone_state(s)), - }, + state: self.state.as_ref().map(|s| self.block.clone_state(s)), rot: self.rot, } } @@ -259,11 +260,7 @@ impl<'l> Schematic<'l> { h: self.height, }); } - let b = &self.blocks[x][y]; - match b { - Some(b) => Ok(Some(b)), - _ => Ok(None), - } + Ok(self.blocks[x][y].as_ref()) } /// gets a block, mutably @@ -276,14 +273,10 @@ impl<'l> Schematic<'l> { h: self.height, }); } - let b = &mut self.blocks[x][y]; - match b { - Some(b) => Ok(Some(b)), - _ => Ok(None), - } + Ok(self.blocks[x][y].as_mut()) } - /// put a block in (same as [Schematic::set], but less arguments and builder-ness). panics!!! + /// put a block in (same as [`Schematic::set`], but less arguments and builder-ness). panics!!! /// ``` /// # use mindus::Schematic; /// @@ -335,7 +328,7 @@ impl<'l> Schematic<'l> { }); } let state = block.deserialize_state(data)?; - let p = Placement { block, state, rot }; + let p = Placement { block, rot, state }; self.blocks[x][y] = Some(p); Ok(()) } @@ -378,7 +371,7 @@ impl<'l> Schematic<'l> { #[must_use] /// see how much this schematic costs. - /// returns (cost, is_sandbox) + /// returns (cost, `is_sandbox`) /// ``` /// # use mindus::Schematic; /// # use mindus::DynData; @@ -490,7 +483,7 @@ impl fmt::Display for TruncatedError { const SCHEMATIC_HEADER: u32 = ((b'm' as u32) << 24) | ((b's' as u32) << 16) | ((b'c' as u32) << 8) | (b'h' as u32); -/// serde_schematic +/// `serde_schematic` pub struct SchematicSerializer<'l>(pub &'l BlockRegistry<'l>); impl<'l> Serializer<Schematic<'l>> for SchematicSerializer<'l> { diff --git a/src/item/storage.rs b/src/item/storage.rs index 6eeb018..ec7f219 100644 --- a/src/item/storage.rs +++ b/src/item/storage.rs @@ -20,7 +20,7 @@ impl<T> Default for Storage<T> { Self { base: Vec::default(), total: 0, - holds: Default::default(), + holds: PhantomData, } } } @@ -43,7 +43,7 @@ where #[must_use] /// total items - pub fn get_total(&self) -> u64 { + pub const fn get_total(&self) -> u64 { self.total } @@ -61,7 +61,7 @@ where /// s.sub(item::Type::Copper, 500, 0); /// assert!(s.is_empty()); /// ``` - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.total == 0 } @@ -81,10 +81,7 @@ where /// ``` #[must_use] pub fn get(&self, ty: T) -> u32 { - match self.base.get(u16::from(ty) as usize) { - None => 0, - Some(cnt) => *cnt, - } + self.base.get(u16::from(ty) as usize).copied().unwrap_or(0) } /// set item count of certain element /// diff --git a/src/logic/mod.rs b/src/logic/mod.rs index b8a98fc..b5e7cc6 100644 --- a/src/logic/mod.rs +++ b/src/logic/mod.rs @@ -10,72 +10,67 @@ numeric_enum! { } } -macro_rules!match_select -{ - ($val:expr, $base:ty, $($name:ident),+) => - { - match $val - { - $(<$base>::$name => true,)+ - _ => false, - } - }; -} - impl LogicField { #[must_use] - pub fn is_readable(&self) -> bool { - match_select!( + pub const fn is_readable(self) -> bool { + use LogicField::{ + Ammo, AmmoCapacity, Boosting, Color, Controlled, Controller, Dead, Efficiency, Enabled, + FirstItem, Flag, Health, Heat, ItemCapacity, LiquidCapacity, MaxHealth, MineX, MineY, + Mining, Name, PayloadCount, PayloadType, PosX, PosY, PowerCapacity, PowerNetCapacity, + PowerNetIn, PowerNetOut, PowerNetStored, Progress, Range, Rotation, ShootX, ShootY, + Shooting, Size, Speed, Team, Timescale, TotalItems, TotalLiquids, TotalPower, Type, + }; + matches!( self, - LogicField, - TotalItems, - FirstItem, - TotalLiquids, - TotalPower, - ItemCapacity, - LiquidCapacity, - PowerCapacity, - PowerNetCapacity, - PowerNetStored, - PowerNetIn, - PowerNetOut, - Ammo, - AmmoCapacity, - Health, - MaxHealth, - Heat, - Efficiency, - Progress, - Timescale, - Rotation, - PosX, - PosY, - ShootX, - ShootY, - Size, - Dead, - Range, - Shooting, - Boosting, - MineX, - MineY, - Mining, - Speed, - Team, - Type, - Flag, - Controlled, - Controller, - Name, - PayloadCount, - PayloadType, - Enabled, - Color + TotalItems + | FirstItem + | TotalLiquids + | TotalPower + | ItemCapacity + | LiquidCapacity + | PowerCapacity + | PowerNetCapacity + | PowerNetStored + | PowerNetIn + | PowerNetOut + | Ammo + | AmmoCapacity + | Health + | MaxHealth + | Heat + | Efficiency + | Progress + | Timescale + | Rotation + | PosX + | PosY + | ShootX + | ShootY + | Size + | Dead + | Range + | Shooting + | Boosting + | MineX + | MineY + | Mining + | Speed + | Team + | Type + | Flag + | Controlled + | Controller + | Name + | PayloadCount + | PayloadType + | Enabled + | Color ) } #[must_use] - pub fn is_writable(&self) -> bool { - match_select!(self, LogicField, Enabled, Shoot, ShootP, Config, Color) + pub const fn is_writable(self) -> bool { + use LogicField::{Color, Config, Enabled, Shoot, ShootP}; + matches!(self, Enabled | Shoot | ShootP | Config | Color) } } diff --git a/src/team.rs b/src/team.rs index da4a34f..c2f8510 100644 --- a/src/team.rs +++ b/src/team.rs @@ -9,13 +9,13 @@ pub struct Team(u8); impl Team { #[must_use] - pub fn of(id: u8) -> Self { + pub const fn of(id: u8) -> Self { Self(id) } #[must_use] - pub fn is_base(&self) -> bool { - self.0 < 6 + pub const fn is_base(self) -> bool { + self.0 < 7 } } @@ -89,7 +89,7 @@ impl Content for Team { 5 => "blue", 6 => "neoplastic", // dark magic: offsets manually computed, then rely on the format "...|team#{i}|..." - i @ 6..=9 => { + i @ 7..=9 => { // length: 7 ("team#" (5) + 1 digit + "|" (1)) let s = ((i - 6) as usize) * 7; &TEAM_NAMES[s..s + 6] // exclude the trailing "|" @@ -109,13 +109,13 @@ impl Content for Team { } impl Team { - pub fn color(&self) -> Rgb<u8> { + pub const fn color(self) -> Rgb<u8> { macro_rules! h { ($x:literal) => { Rgb(color_hex::color_from_hex!($x)) }; } - match *self { + match self { SHARDED => h!("ffd37f"), DERELICT => h!("4d4e58"), CRUX => h!("f25555"), diff --git a/src/utils/lazy.rs b/src/utils/lazy.rs index 5a19029..4d30aa2 100644 --- a/src/utils/lazy.rs +++ b/src/utils/lazy.rs @@ -1,4 +1,4 @@ -//! [LazyLock] copy +//! [`LazyLock`](std::sync::LazyLock) copy use std::cell::UnsafeCell; use std::mem::ManuallyDrop; use std::panic::{RefUnwindSafe, UnwindSafe}; @@ -23,7 +23,7 @@ impl<T, F: FnOnce() -> T> Lock<T, F> { } #[inline] - // SAFETY: CALL ONLY ONCE! NOT CHECKED + /// SAFETY: CALL ONLY ONCE! NOT CHECKED pub unsafe fn load(this: &Lock<T, F>) { let data = &mut *this.data.get(); let f = ManuallyDrop::take(&mut data.f); @@ -34,7 +34,7 @@ impl<T, F: FnOnce() -> T> Lock<T, F> { impl<T, F> Lock<T, F> { #[inline] - // SAFETY: CALL [load] FIRST! + /// SAFETY: CALL [load] FIRST! pub unsafe fn get(&self) -> &T { &(*self.data.get()).value } |