mindustry logic execution, map- and schematic- parsing and rendering
clippy it
bendn 2023-08-09
parent 4aa7e8a · commit 28c62e6
-rw-r--r--Cargo.toml2
-rw-r--r--build.rs4
-rw-r--r--src/block/distribution.rs9
-rw-r--r--src/block/liquid.rs9
-rw-r--r--src/block/logic.rs10
-rw-r--r--src/block/mod.rs28
-rw-r--r--src/block/power.rs4
-rw-r--r--src/block/simple.rs4
-rw-r--r--src/content.rs7
-rw-r--r--src/data/autotile.rs21
-rw-r--r--src/data/base64.rs4
-rw-r--r--src/data/dynamic.rs8
-rw-r--r--src/data/map.rs55
-rw-r--r--src/data/mod.rs18
-rw-r--r--src/data/renderer.rs31
-rw-r--r--src/data/schematic.rs31
-rw-r--r--src/item/storage.rs11
-rw-r--r--src/logic/mod.rs115
-rw-r--r--src/team.rs12
-rw-r--r--src/utils/lazy.rs6
20 files changed, 209 insertions, 180 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 21e0352..c7e5b7f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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 = [
diff --git a/build.rs b/build.rs
index 2b382f4..b696779 100644
--- a/build.rs
+++ b/build.rs
@@ -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
}