From 8f7eb2e0259bbab9d60fd72c50c4d474cf8e3fef Mon Sep 17 00:00:00 2001 From: Alula Date: Mon, 31 Aug 2020 20:33:01 +0200 Subject: [PATCH] some flag naming and refactoring --- src/common.rs | 711 +++++----------------------------------------- src/macros.rs | 622 ++++++++++++++++++++++++++++++++++++++++ src/main.rs | 6 +- src/player.rs | 101 ++----- src/player_hit.rs | 50 ++-- 5 files changed, 738 insertions(+), 752 deletions(-) create mode 100644 src/macros.rs diff --git a/src/common.rs b/src/common.rs index b2005b2..007b8d8 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,16 +1,69 @@ -#[doc(hidden)] -pub use core::convert::Into; -#[doc(hidden)] -pub use core::fmt; -#[doc(hidden)] -pub use core::mem::size_of; -use std::cell::RefCell; -use std::io::Cursor; - -use byteorder::ReadBytesExt; -use num_derive::FromPrimitive; use num_traits::Num; +use crate::bitfield; + +bitfield! { + #[derive(Clone)] + pub struct Flags(u32); + impl Debug; + + pub hit_left_wall, set_hit_left_wall: 0; // 0x01 + pub hit_top_wall, set_hit_top_wall: 1; // 0x02 + pub hit_right_wall, set_hit_right_wall: 2; // 0x04 + pub hit_bottom_wall, set_hit_bottom_wall: 3; // 0x08 + pub hit_right_slope, set_hit_right_slope: 4; // 0x10 + pub hit_left_slope, set_hit_left_slope: 5; // 0x20 + pub flag_x40, set_flag_x40: 6; // 0x40 + pub flag_x80, set_flag_x80: 7; // 0x80 + pub in_water, set_in_water: 8; // 0x100 + pub flag_x200, set_flag_x200: 9; // 0x200 + pub hit_by_spike, set_hit_by_spike: 10; // 0x400 + pub water_splash_facing_right, set_water_splash_facing_right: 11; // 0x800 + pub force_left, set_force_left: 12; // 0x1000 + pub force_up, set_force_up: 13; // 0x2000 + pub force_right, set_force_right: 14; // 0x4000 + pub force_down, set_force_down: 15; // 0x8000 + pub hit_left_bigger_half, set_hit_left_bigger_half: 16; // 0x10000 + pub hit_left_smaller_half, set_hit_left_smaller_half: 17; // 0x20000 + pub hit_right_smaller_half, set_hit_right_smaller_half: 18; // 0x40000 + pub hit_right_bigger_half, set_hit_right_bigger_half: 19; // 0x80000 + + // engine specific flags + pub head_bounced, set_head_bounced: 31; +} + +bitfield! { + #[derive(Clone)] + pub struct Equip(u16); + impl Debug; + + pub has_booster_0_8, set_booster_0_8: 0; + pub has_map, set_map: 1; + pub has_arms_barrier, set_arms_barrier: 2; + pub has_turbocharge, set_turbocharge: 3; + pub has_air_tank, set_air_tank: 4; + pub has_booster_2_0, set_booster_2_0: 5; + pub has_mimiga_mask, set_mimiga_mask: 6; + pub has_whimsical_star, set_whimsical_star: 7; + pub has_nikumaru, set_nikumaru: 8; + // 7 bits wasted, thx pixel +} + +bitfield! { + #[derive(Clone)] + pub struct Cond(u16); + impl Debug; + + pub cond_x01, set_cond_x01: 0; + pub hidden, set_hidden: 1; + pub cond_x04, set_cond_x04: 2; + pub cond_x08, set_cond_x08: 3; + pub damage_boss, set_damage_boss: 4; + pub cond_x20, set_cond_x20: 5; + pub cond_x40, set_cond_x40: 6; + pub alive, set_alive: 7; +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum FadeDirection { @@ -130,639 +183,3 @@ impl Rect { } } } - -#[derive(Debug)] -pub struct CursorIterator<'a> { - cursor: RefCell>>, -} - -impl<'a> CursorIterator<'a> { - pub fn new(cursor: RefCell>>) -> CursorIterator<'a> { - CursorIterator { cursor } - } -} - -impl<'a> Iterator for CursorIterator<'a> { - type Item = u8; - - #[inline] - fn next(&mut self) -> Option { - self.cursor.borrow_mut().read_u8().ok() - } -} - -#[macro_export] -macro_rules! str { - () => { - String::new() - }; - ($x:expr) => { - ToString::to_string(&$x) - }; -} - -// extended version of https://github.com/dzamlo/rust-bitfield - -#[macro_export(local_inner_macros)] -macro_rules! bitfield_fields { - (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, - $lsb:expr, $count:expr) => { - $(#[$attribute])* - #[allow(unknown_lints)] - #[allow(eq_op)] - $($vis)* fn $setter(&mut self, index: usize, value: $from) { - use crate::common::BitRange; - __bitfield_debug_assert!(index < $count); - let width = $msb - $lsb + 1; - let lsb = $lsb + index*width; - let msb = lsb + width - 1; - self.set_bit_range(msb, lsb, crate::common::Into::<$t>::into(value)); - } - }; - (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, - $lsb:expr) => { - $(#[$attribute])* - $($vis)* fn $setter(&mut self, value: $from) { - use crate::common::BitRange; - self.set_bit_range($msb, $lsb, crate::common::Into::<$t>::into(value)); - } - }; - (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $bit:expr) => { - $(#[$attribute])* - $($vis)* fn $setter(&mut self, value: bool) { - use crate::common::Bit; - self.set_bit($bit, value); - } - }; - (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, - $lsb:expr, $count:expr) => { - $(#[$attribute])* - #[allow(unknown_lints)] - #[allow(eq_op)] - $($vis)* fn $getter(&self, index: usize) -> $into { - use crate::common::BitRange; - __bitfield_debug_assert!(index < $count); - let width = $msb - $lsb + 1; - let lsb = $lsb + index*width; - let msb = lsb + width - 1; - let raw_value: $t = self.bit_range(msb, lsb); - crate::common::Into::into(raw_value) - } - }; - (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, - $lsb:expr) => { - $(#[$attribute])* - $($vis)* fn $getter(&self) -> $into { - use crate::common::BitRange; - let raw_value: $t = self.bit_range($msb, $lsb); - crate::common::Into::into(raw_value) - } - }; - (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $bit:expr) => { - $(#[$attribute])* - $($vis)* fn $getter(&self) -> bool { - use crate::common::Bit; - self.bit($bit) - } - - paste::paste! { - #[allow(dead_code)] - $($vis)* fn [](&self) -> bool { - use crate::common::Bit; - self.bit_only($bit) - } - } - }; - - (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, $setter:ident: - $($exprs:expr),*) => { - bitfield_fields!(@field $(#[$attribute])* ($($vis)*) $t, $from, $into, $getter, _: $($exprs),*); - bitfield_fields!(@field $(#[$attribute])* ($($vis)*) $t, $from, $into, _, $setter: $($exprs),*); - }; - - ($t:ty;) => {}; - ($default_ty:ty; pub $($rest:tt)*) => { - bitfield_fields!{$default_ty; () pub $($rest)*} - }; - ($default_ty:ty; #[$attribute:meta] $($rest:tt)*) => { - bitfield_fields!{$default_ty; (#[$attribute]) $($rest)*} - }; - ($default_ty:ty; ($(#[$attributes:meta])*) #[$attribute:meta] $($rest:tt)*) => { - bitfield_fields!{$default_ty; ($(#[$attributes])* #[$attribute]) $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, from into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* (pub) $t, $into, $into, $getter, $setter: $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* (pub) $t, $t, $into, $getter, $setter: $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, $getter:tt, $setter:tt: $($exprs:expr),*; - $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* (pub) $t, $t, $t, $getter, $setter: $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) pub from into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $into, $into, $getter, $setter: - $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) pub into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $default_ty, $into, $getter, $setter: - $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) pub $getter:tt, $setter:tt: $($exprs:expr),*; - $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $default_ty, $default_ty, $getter, $setter: - $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - - ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, from into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* () $t, $into, $into, $getter, $setter: $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - - ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* () $t, $t, $into, $getter, $setter: $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - - ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, $getter:tt, $setter:tt: $($exprs:expr),*; - $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* () $t, $t, $t, $getter, $setter: $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) from into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* () $default_ty, $into, $into, $getter, $setter: - $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) into $into:ty, $getter:tt, $setter:tt: - $($exprs:expr),*; $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* () $default_ty, $default_ty, $into, $getter, $setter: - $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; ($(#[$attribute:meta])*) $getter:tt, $setter:tt: $($exprs:expr),*; - $($rest:tt)*) => { - bitfield_fields!{@field $(#[$attribute])* () $default_ty, $default_ty, $default_ty, $getter, $setter: - $($exprs),*} - bitfield_fields!{$default_ty; $($rest)*} - }; - ($previous_default_ty:ty; $default_ty:ty; $($rest:tt)*) => { - bitfield_fields!{$default_ty; $($rest)*} - }; - ($default_ty:ty; $($rest:tt)*) => { - bitfield_fields!{$default_ty; () $($rest)*} - }; - ($($rest:tt)*) => { - bitfield_fields!{SET_A_DEFAULT_TYPE_OR_SPECIFY_THE_TYPE_FOR_EACH_FIELDS; $($rest)*} - } -} - -/// Generates a `fmt::Debug` implementation. -/// -/// This macros must be called from a `impl Debug for ...` block. It will generate the `fmt` method. -/// -/// In most of the case, you will not directly call this macros, but use `bitfield`. -/// -/// The syntax is `struct TheNameOfTheStruct` followed by the syntax of `bitfield_fields`. -/// -/// The write-only fields are ignored. -/// -/// # Example -/// -/// ```rust -/// # #[macro_use] extern crate bitfield; -/// struct FooBar(u32); -/// bitfield_bitrange!{struct FooBar(u32)} -/// impl FooBar{ -/// bitfield_fields!{ -/// u32; -/// field1, _: 7, 0; -/// field2, _: 31, 24; -/// } -/// } -/// -/// impl std::fmt::Debug for FooBar { -/// bitfield_debug!{ -/// struct FooBar; -/// field1, _: 7, 0; -/// field2, _: 31, 24; -/// } -/// } -/// -/// fn main() { -/// let foobar = FooBar(0x11223344); -/// println!("{:?}", foobar); - -/// } -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! bitfield_debug { - (struct $name:ident; $($rest:tt)*) => { - fn fmt(&self, f: &mut crate::common::fmt::Formatter) -> crate::common::fmt::Result { - let mut debug_struct = f.debug_struct(__bitfield_stringify!($name)); - debug_struct.field(".0", &self.0); - bitfield_debug!{debug_struct, self, $($rest)*} - debug_struct.finish() - } - }; - ($debug_struct:ident, $self:ident, #[$attribute:meta] $($rest:tt)*) => { - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, pub $($rest:tt)*) => { - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, _, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => { - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, $type:ty; $($rest:tt)*) => { - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, $getter:ident, $setter:tt: $msb:expr, $lsb:expr, $count:expr; - $($rest:tt)*) => { - let mut array = [$self.$getter(0); $count]; - for (i, e) in (&mut array).into_iter().enumerate() { - *e = $self.$getter(i); - } - $debug_struct.field(__bitfield_stringify!($getter), &array); - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, $getter:ident, $setter:tt: $($exprs:expr),*; $($rest:tt)*) - => { - $debug_struct.field(__bitfield_stringify!($getter), &$self.$getter()); - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, from into $into:ty, $($rest:tt)*) => { - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, into $into:ty, $($rest:tt)*) => { - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, $type:ty, $($rest:tt)*) => { - bitfield_debug!{$debug_struct, $self, $($rest)*} - }; - ($debug_struct:ident, $self:ident, ) => {}; -} - -/// Implements `BitRange` for a tuple struct (or "newtype"). -/// -/// This macro will generate an implementation of the `BitRange` trait for an existing single -/// element tuple struct. -/// -/// The syntax is more or less the same as declaring a "newtype", **without** the attributes, -/// documentation comments and pub keyword. -/// -/// The difference with a normal "newtype" is the type in parentheses. If the type is `[t]` (where -/// `t` is any of the unsigned integer type), the "newtype" will be generic and implement -/// `BitRange` for `T: AsMut<[t]> + AsRef<[t]>` (for example a slice, an array or a `Vec`). You can -/// also use `MSB0 [t]`. The difference will be the positions of the bit. You can use the -/// `bits_positions` example to see where each bits is. If the type is neither of this two, the -/// "newtype" will wrap a value of the specified type and implements `BitRange` the same ways as -/// the wrapped type. -/// -/// # Examples -/// -/// ```rust -/// # #[macro_use] extern crate bitfield; -/// # fn main() {} -/// struct BitField1(u32); -/// bitfield_bitrange!{struct BitField1(u32)} -/// -/// struct BitField2(T); -/// bitfield_bitrange!{struct BitField2([u8])} -/// -/// struct BitField3(T); -/// bitfield_bitrange!{struct BitField3(MSB0 [u8])} -/// ``` -/// -#[macro_export(local_inner_macros)] -macro_rules! bitfield_bitrange { - (@impl_bitrange_slice $name:ident, $slice_ty:ty, $bitrange_ty:ty) => { - impl + AsRef<[$slice_ty]>> crate::common::BitRange<$bitrange_ty> - for $name { - fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { - let bit_len = crate::common::size_of::<$slice_ty>()*8; - let value_bit_len = crate::common::size_of::<$bitrange_ty>()*8; - let mut value = 0; - for i in (lsb..=msb).rev() { - value <<= 1; - value |= ((self.0.as_ref()[i/bit_len] >> (i%bit_len)) & 1) as $bitrange_ty; - } - value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) - } - - fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { - let bit_len = crate::common::size_of::<$slice_ty>()*8; - let mut value = value; - for i in lsb..=msb { - self.0.as_mut()[i/bit_len] &= !(1 << (i%bit_len)); - self.0.as_mut()[i/bit_len] |= (value & 1) as $slice_ty << (i%bit_len); - value >>= 1; - } - } - } - }; - (@impl_bitrange_slice_msb0 $name:ident, $slice_ty:ty, $bitrange_ty:ty) => { - impl + AsRef<[$slice_ty]>> crate::common::BitRange<$bitrange_ty> - for $name { - fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { - let bit_len = crate::common::size_of::<$slice_ty>()*8; - let value_bit_len = crate::common::size_of::<$bitrange_ty>()*8; - let mut value = 0; - for i in lsb..=msb { - value <<= 1; - value |= ((self.0.as_ref()[i/bit_len] >> (bit_len - i%bit_len - 1)) & 1) - as $bitrange_ty; - } - value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) - } - - fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { - let bit_len = crate::common::size_of::<$slice_ty>()*8; - let mut value = value; - for i in (lsb..=msb).rev() { - self.0.as_mut()[i/bit_len] &= !(1 << (bit_len - i%bit_len - 1)); - self.0.as_mut()[i/bit_len] |= (value & 1) as $slice_ty - << (bit_len - i%bit_len - 1); - value >>= 1; - } - } - } - }; - (struct $name:ident([$t:ty])) => { - bitfield_bitrange!(@impl_bitrange_slice $name, $t, u8); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, u16); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, u32); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, u64); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, u128); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, i8); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, i16); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, i32); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, i64); - bitfield_bitrange!(@impl_bitrange_slice $name, $t, i128); - }; - (struct $name:ident(MSB0 [$t:ty])) => { - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u8); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u16); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u32); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u64); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u128); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i8); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i16); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i32); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i64); - bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i128); - }; - (struct $name:ident($t:ty)) => { - impl crate::common::BitRange for $name where $t: crate::common::BitRange { - fn get(&self) -> T { - self.0.get() - } - fn bit_range(&self, msb: usize, lsb: usize) -> T { - self.0.bit_range(msb, lsb) - } - fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T) { - self.0.set_bit_range(msb, lsb, value); - } - } - }; -} - -/// Combines `bitfield_bitrange` and `bitfield_fields`. -/// -/// The syntax of this macro is the syntax of a tuple struct, including attributes and -/// documentation comments, followed by a semicolon, some optional elements, and finally the fields -/// as described in the `bitfield_fields` documentation. -/// -/// The first optional element is `no default BitRange;`. With that, no implementation of -/// `BitRange` will be generated. -/// -/// The second optional element is `impl Debug;`. This will generate an implementation of -/// `fmt::Debug` with the `bitfield_debug` macro. -/// -/// The difference with calling those macros separately is that `bitfield_fields` is called -/// from an appropriate `impl` block. If you use the non-slice form of `bitfield_bitrange`, the -/// default type for `bitfield_fields` will be set to the wrapped fields. -/// -/// See the documentation of these macros for more information on their respective syntax. -/// -/// # Example -/// -/// ```rust -/// # #[macro_use] extern crate bitfield; -/// # fn main() {} -/// bitfield!{ -/// pub struct BitField1(u16); -/// impl Debug; -/// // The fields default to u16 -/// field1, set_field1: 10, 0; -/// pub field2, _ : 12, 3; -/// } -/// ``` -/// -/// or with a custom `BitRange` implementation : -/// ```rust -/// # #[macro_use] extern crate bitfield; -/// # use bitfield::BitRange; -/// # fn main() {} -/// bitfield!{ -/// pub struct BitField1(u16); -/// no default BitRange; -/// impl Debug; -/// u8; -/// field1, set_field1: 10, 0; -/// pub field2, _ : 12, 3; -/// } -/// impl BitRange for BitField1 { -/// fn bit_range(&self, msb: usize, lsb: usize) -> u8 { -/// let width = msb - lsb + 1; -/// let mask = (1 << width) - 1; -/// ((self.0 >> lsb) & mask) as u8 -/// } -/// fn set_bit_range(&mut self, msb: usize, lsb: usize, value: u8) { -/// self.0 = (value as u16) << lsb; -/// } -/// } -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! bitfield { - ($(#[$attribute:meta])* pub struct $($rest:tt)*) => { - bitfield!($(#[$attribute])* (pub) struct $($rest)*); - }; - ($(#[$attribute:meta])* struct $($rest:tt)*) => { - bitfield!($(#[$attribute])* () struct $($rest)*); - }; - // Force `impl Debug` to always be after `no default BitRange` it the two are present. - // This simplify the rest of the macro. - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($($type:tt)*); impl Debug; no default BitRange; $($rest:tt)*) => { - bitfield!{$(#[$attribute])* ($($vis)*) struct $name($($type)*); no default BitRange; impl Debug; $($rest)*} - }; - - // If we have `impl Debug` without `no default BitRange`, we will still match, because when - // we call `bitfield_bitrange`, we add `no default BitRange`. - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); no default BitRange; impl Debug; $($rest:tt)*) => { - impl + AsRef<[$t]> + crate::common::fmt::Debug> crate::common::fmt::Debug for $name { - bitfield_debug!{struct $name; $($rest)*} - } - - bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} - }; - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); no default BitRange; $($rest:tt)*) => { - $(#[$attribute])* - $($vis)* struct $name(pub T); - - impl + AsRef<[$t]>> $name { - bitfield_fields!{$($rest)*} - } - }; - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); $($rest:tt)*) => { - bitfield_bitrange!(struct $name([$t])); - bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} - }; - - // The only difference between the MSB0 version anf the non-MSB0 version, is the BitRange - // implementation. We delegate everything else to the non-MSB0 version of the macro. - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident(MSB0 [$t:ty]); no default BitRange; $($rest:tt)*) => { - bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} - }; - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident(MSB0 [$t:ty]); $($rest:tt)*) => { - bitfield_bitrange!(struct $name(MSB0 [$t])); - bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} - }; - - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); no default BitRange; impl Debug; $($rest:tt)*) => { - impl crate::common::fmt::Debug for $name { - bitfield_debug!{struct $name; $($rest)*} - } - - bitfield!{$(#[$attribute])* ($($vis)*) struct $name($t); no default BitRange; $($rest)*} - }; - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); no default BitRange; $($rest:tt)*) => { - $(#[$attribute])* - $($vis)* struct $name(pub $t); - - impl $name { - bitfield_fields!{$t; $($rest)*} - } - }; - ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); $($rest:tt)*) => { - bitfield_bitrange!(struct $name($t)); - bitfield!{$(#[$attribute])* ($($vis)*) struct $name($t); no default BitRange; $($rest)*} - }; -} - -/// A trait to get or set ranges of bits. -pub trait BitRange { - fn get(&self) -> T; - /// Get a range of bits. - fn bit_range(&self, msb: usize, lsb: usize) -> T; - /// Set a range of bits. - fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T); -} - -/// A trait to get or set a single bit. -/// -/// This trait is implemented for all type that implement `BitRange`. -pub trait Bit { - /// Get a single bit. - fn bit(&self, bit: usize) -> bool; - - /// Check if only specific bit is set. - fn bit_only(&self, bit: usize) -> bool; - - /// Set a single bit. - fn set_bit(&mut self, bit: usize, value: bool); -} - -impl> Bit for T { - fn bit(&self, bit: usize) -> bool { - self.bit_range(bit, bit) != 0 - } - - fn bit_only(&self, bit: usize) -> bool { - self.get() == (1 << bit) as u8 - } - - fn set_bit(&mut self, bit: usize, value: bool) { - self.set_bit_range(bit, bit, value as u8); - } -} - -macro_rules! impl_bitrange_for_u { - ($t:ty, $bitrange_ty:ty) => { - impl BitRange<$bitrange_ty> for $t { - #[inline] - fn get(&self) -> $bitrange_ty { - *self as $bitrange_ty - } - - #[inline] - fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { - let bit_len = size_of::<$t>()*8; - let result_bit_len = size_of::<$bitrange_ty>()*8; - let result = ((*self << (bit_len - msb - 1)) >> (bit_len - msb - 1 + lsb)) - as $bitrange_ty; - result << (result_bit_len - (msb - lsb + 1)) >> (result_bit_len - (msb - lsb + 1)) - } - - #[inline] - fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { - let bit_len = size_of::<$t>()*8; - let mask: $t = !(0 as $t) - << (bit_len - msb - 1) - >> (bit_len - msb - 1 + lsb) - << (lsb); - *self &= !mask; - *self |= (value as $t << lsb) & mask; - } - } - } -} - -macro_rules! impl_bitrange_for_u_combinations { -((),($($bitrange_ty:ty),*)) => { - -}; -(($t:ty),($($bitrange_ty:ty),*)) => { - $(impl_bitrange_for_u!{$t, $bitrange_ty})* -}; - (($t_head:ty, $($t_rest:ty),*),($($bitrange_ty:ty),*)) => { - impl_bitrange_for_u_combinations!{($t_head), ($($bitrange_ty),*)} - impl_bitrange_for_u_combinations!{($($t_rest),*), ($($bitrange_ty),*)} - }; -} - -impl_bitrange_for_u_combinations! {(u8, u16, u32, u64, u128), (u8, u16, u32, u64, u128)} -impl_bitrange_for_u_combinations! {(u8, u16, u32, u64, u128), (i8, i16, i32, i64, i128)} - -// Same as std::stringify but callable from local_inner_macros macros defined inside -// this crate. -#[macro_export] -#[doc(hidden)] -macro_rules! __bitfield_stringify { - ($s:ident) => { - stringify!($s) - }; -} - -// Same as std::debug_assert but callable from local_inner_macros macros defined inside -// this crate. -#[macro_export] -#[doc(hidden)] -macro_rules! __bitfield_debug_assert { - ($e:expr) => { - debug_assert!($e) - }; -} diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..bbd0a40 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,622 @@ +#[doc(hidden)] +pub use core::convert::Into; +#[doc(hidden)] +pub use core::fmt; +#[doc(hidden)] +pub use core::mem::size_of; + +#[macro_export] +macro_rules! str { + () => { + String::new() + }; + ($x:expr) => { + ToString::to_string(&$x) + }; +} + +// extended version of https://github.com/dzamlo/rust-bitfield + +#[macro_export(local_inner_macros)] +macro_rules! bitfield_fields { + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, + $lsb:expr, $count:expr) => { + $(#[$attribute])* + #[allow(unknown_lints)] + #[allow(eq_op)] + $($vis)* fn $setter(&mut self, index: usize, value: $from) { + use crate::macros::BitRange; + __bitfield_debug_assert!(index < $count); + let width = $msb - $lsb + 1; + let lsb = $lsb + index*width; + let msb = lsb + width - 1; + self.set_bit_range(msb, lsb, crate::macros::Into::<$t>::into(value)); + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, + $lsb:expr) => { + $(#[$attribute])* + $($vis)* fn $setter(&mut self, value: $from) { + use crate::macros::BitRange; + self.set_bit_range($msb, $lsb, crate::macros::Into::<$t>::into(value)); + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, _, $setter:ident: $bit:expr) => { + $(#[$attribute])* + $($vis)* fn $setter(&mut self, value: bool) { + use crate::macros::Bit; + self.set_bit($bit, value); + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, + $lsb:expr, $count:expr) => { + $(#[$attribute])* + #[allow(unknown_lints)] + #[allow(eq_op)] + $($vis)* fn $getter(&self, index: usize) -> $into { + use crate::macros::BitRange; + __bitfield_debug_assert!(index < $count); + let width = $msb - $lsb + 1; + let lsb = $lsb + index*width; + let msb = lsb + width - 1; + let raw_value: $t = self.bit_range(msb, lsb); + crate::macros::Into::into(raw_value) + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, + $lsb:expr) => { + $(#[$attribute])* + $($vis)* fn $getter(&self) -> $into { + use crate::macros::BitRange; + let raw_value: $t = self.bit_range($msb, $lsb); + crate::macros::Into::into(raw_value) + } + }; + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, _: $bit:expr) => { + $(#[$attribute])* + $($vis)* fn $getter(&self) -> bool { + use crate::macros::Bit; + self.bit($bit) + } + + paste::paste! { + #[allow(dead_code)] + $($vis)* fn [](&self) -> bool { + use crate::macros::Bit; + self.bit_only($bit) + } + } + }; + + (@field $(#[$attribute:meta])* ($($vis:tt)*) $t:ty, $from:ty, $into:ty, $getter:ident, $setter:ident: + $($exprs:expr),*) => { + bitfield_fields!(@field $(#[$attribute])* ($($vis)*) $t, $from, $into, $getter, _: $($exprs),*); + bitfield_fields!(@field $(#[$attribute])* ($($vis)*) $t, $from, $into, _, $setter: $($exprs),*); + }; + + ($t:ty;) => {}; + ($default_ty:ty; pub $($rest:tt)*) => { + bitfield_fields!{$default_ty; () pub $($rest)*} + }; + ($default_ty:ty; #[$attribute:meta] $($rest:tt)*) => { + bitfield_fields!{$default_ty; (#[$attribute]) $($rest)*} + }; + ($default_ty:ty; ($(#[$attributes:meta])*) #[$attribute:meta] $($rest:tt)*) => { + bitfield_fields!{$default_ty; ($(#[$attributes])* #[$attribute]) $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $t, $into, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $t, $t, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $t:ty, $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $t, $t, $t, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $into, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $default_ty, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) pub $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* (pub) $default_ty, $default_ty, $default_ty, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + + ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $t, $into, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + + ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $t, $t, $into, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + + ($default_ty:ty; ($(#[$attribute:meta])*) $t:ty, $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $t, $t, $t, $getter, $setter: $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) from into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $default_ty, $into, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) into $into:ty, $getter:tt, $setter:tt: + $($exprs:expr),*; $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $default_ty, $default_ty, $into, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; ($(#[$attribute:meta])*) $getter:tt, $setter:tt: $($exprs:expr),*; + $($rest:tt)*) => { + bitfield_fields!{@field $(#[$attribute])* () $default_ty, $default_ty, $default_ty, $getter, $setter: + $($exprs),*} + bitfield_fields!{$default_ty; $($rest)*} + }; + ($previous_default_ty:ty; $default_ty:ty; $($rest:tt)*) => { + bitfield_fields!{$default_ty; $($rest)*} + }; + ($default_ty:ty; $($rest:tt)*) => { + bitfield_fields!{$default_ty; () $($rest)*} + }; + ($($rest:tt)*) => { + bitfield_fields!{SET_A_DEFAULT_TYPE_OR_SPECIFY_THE_TYPE_FOR_EACH_FIELDS; $($rest)*} + } +} + +/// Generates a `fmt::Debug` implementation. +/// +/// This macros must be called from a `impl Debug for ...` block. It will generate the `fmt` method. +/// +/// In most of the case, you will not directly call this macros, but use `bitfield`. +/// +/// The syntax is `struct TheNameOfTheStruct` followed by the syntax of `bitfield_fields`. +/// +/// The write-only fields are ignored. +/// +/// # Example +/// +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// struct FooBar(u32); +/// bitfield_bitrange!{struct FooBar(u32)} +/// impl FooBar{ +/// bitfield_fields!{ +/// u32; +/// field1, _: 7, 0; +/// field2, _: 31, 24; +/// } +/// } +/// +/// impl std::fmt::Debug for FooBar { +/// bitfield_debug!{ +/// struct FooBar; +/// field1, _: 7, 0; +/// field2, _: 31, 24; +/// } +/// } +/// +/// fn main() { +/// let foobar = FooBar(0x11223344); +/// println!("{:?}", foobar); + +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitfield_debug { + (struct $name:ident; $($rest:tt)*) => { + fn fmt(&self, f: &mut crate::macros::fmt::Formatter) -> crate::macros::fmt::Result { + let mut debug_struct = f.debug_struct(__bitfield_stringify!($name)); + debug_struct.field(".0", &self.0); + bitfield_debug!{debug_struct, self, $($rest)*} + debug_struct.finish() + } + }; + ($debug_struct:ident, $self:ident, #[$attribute:meta] $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, pub $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, _, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $type:ty; $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $getter:ident, $setter:tt: $msb:expr, $lsb:expr, $count:expr; + $($rest:tt)*) => { + let mut array = [$self.$getter(0); $count]; + for (i, e) in (&mut array).into_iter().enumerate() { + *e = $self.$getter(i); + } + $debug_struct.field(__bitfield_stringify!($getter), &array); + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $getter:ident, $setter:tt: $($exprs:expr),*; $($rest:tt)*) + => { + $debug_struct.field(__bitfield_stringify!($getter), &$self.$getter()); + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, from into $into:ty, $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, into $into:ty, $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, $type:ty, $($rest:tt)*) => { + bitfield_debug!{$debug_struct, $self, $($rest)*} + }; + ($debug_struct:ident, $self:ident, ) => {}; +} + +/// Implements `BitRange` for a tuple struct (or "newtype"). +/// +/// This macro will generate an implementation of the `BitRange` trait for an existing single +/// element tuple struct. +/// +/// The syntax is more or less the same as declaring a "newtype", **without** the attributes, +/// documentation comments and pub keyword. +/// +/// The difference with a normal "newtype" is the type in parentheses. If the type is `[t]` (where +/// `t` is any of the unsigned integer type), the "newtype" will be generic and implement +/// `BitRange` for `T: AsMut<[t]> + AsRef<[t]>` (for example a slice, an array or a `Vec`). You can +/// also use `MSB0 [t]`. The difference will be the positions of the bit. You can use the +/// `bits_positions` example to see where each bits is. If the type is neither of this two, the +/// "newtype" will wrap a value of the specified type and implements `BitRange` the same ways as +/// the wrapped type. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// # fn main() {} +/// struct BitField1(u32); +/// bitfield_bitrange!{struct BitField1(u32)} +/// +/// struct BitField2(T); +/// bitfield_bitrange!{struct BitField2([u8])} +/// +/// struct BitField3(T); +/// bitfield_bitrange!{struct BitField3(MSB0 [u8])} +/// ``` +/// +#[macro_export(local_inner_macros)] +macro_rules! bitfield_bitrange { + (@impl_bitrange_slice $name:ident, $slice_ty:ty, $bitrange_ty:ty) => { + impl + AsRef<[$slice_ty]>> crate::macros::BitRange<$bitrange_ty> + for $name { + fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { + let bit_len = crate::macros::size_of::<$slice_ty>()*8; + let value_bit_len = crate::macros::size_of::<$bitrange_ty>()*8; + let mut value = 0; + for i in (lsb..=msb).rev() { + value <<= 1; + value |= ((self.0.as_ref()[i/bit_len] >> (i%bit_len)) & 1) as $bitrange_ty; + } + value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) + } + + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { + let bit_len = crate::macros::size_of::<$slice_ty>()*8; + let mut value = value; + for i in lsb..=msb { + self.0.as_mut()[i/bit_len] &= !(1 << (i%bit_len)); + self.0.as_mut()[i/bit_len] |= (value & 1) as $slice_ty << (i%bit_len); + value >>= 1; + } + } + } + }; + (@impl_bitrange_slice_msb0 $name:ident, $slice_ty:ty, $bitrange_ty:ty) => { + impl + AsRef<[$slice_ty]>> crate::macros::BitRange<$bitrange_ty> + for $name { + fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { + let bit_len = crate::macros::size_of::<$slice_ty>()*8; + let value_bit_len = crate::macros::size_of::<$bitrange_ty>()*8; + let mut value = 0; + for i in lsb..=msb { + value <<= 1; + value |= ((self.0.as_ref()[i/bit_len] >> (bit_len - i%bit_len - 1)) & 1) + as $bitrange_ty; + } + value << (value_bit_len - (msb - lsb + 1)) >> (value_bit_len - (msb - lsb + 1)) + } + + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { + let bit_len = crate::macros::size_of::<$slice_ty>()*8; + let mut value = value; + for i in (lsb..=msb).rev() { + self.0.as_mut()[i/bit_len] &= !(1 << (bit_len - i%bit_len - 1)); + self.0.as_mut()[i/bit_len] |= (value & 1) as $slice_ty + << (bit_len - i%bit_len - 1); + value >>= 1; + } + } + } + }; + (struct $name:ident([$t:ty])) => { + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u8); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u16); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u32); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u64); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, u128); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i8); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i16); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i32); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i64); + bitfield_bitrange!(@impl_bitrange_slice $name, $t, i128); + }; + (struct $name:ident(MSB0 [$t:ty])) => { + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u8); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u16); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u32); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u64); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, u128); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i8); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i16); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i32); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i64); + bitfield_bitrange!(@impl_bitrange_slice_msb0 $name, $t, i128); + }; + (struct $name:ident($t:ty)) => { + impl crate::macros::BitRange for $name where $t: crate::macros::BitRange { + fn get(&self) -> T { + self.0.get() + } + fn bit_range(&self, msb: usize, lsb: usize) -> T { + self.0.bit_range(msb, lsb) + } + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T) { + self.0.set_bit_range(msb, lsb, value); + } + } + }; +} + +/// Combines `bitfield_bitrange` and `bitfield_fields`. +/// +/// The syntax of this macro is the syntax of a tuple struct, including attributes and +/// documentation comments, followed by a semicolon, some optional elements, and finally the fields +/// as described in the `bitfield_fields` documentation. +/// +/// The first optional element is `no default BitRange;`. With that, no implementation of +/// `BitRange` will be generated. +/// +/// The second optional element is `impl Debug;`. This will generate an implementation of +/// `fmt::Debug` with the `bitfield_debug` macro. +/// +/// The difference with calling those macros separately is that `bitfield_fields` is called +/// from an appropriate `impl` block. If you use the non-slice form of `bitfield_bitrange`, the +/// default type for `bitfield_fields` will be set to the wrapped fields. +/// +/// See the documentation of these macros for more information on their respective syntax. +/// +/// # Example +/// +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// # fn main() {} +/// bitfield!{ +/// pub struct BitField1(u16); +/// impl Debug; +/// // The fields default to u16 +/// field1, set_field1: 10, 0; +/// pub field2, _ : 12, 3; +/// } +/// ``` +/// +/// or with a custom `BitRange` implementation : +/// ```rust +/// # #[macro_use] extern crate bitfield; +/// # use bitfield::BitRange; +/// # fn main() {} +/// bitfield!{ +/// pub struct BitField1(u16); +/// no default BitRange; +/// impl Debug; +/// u8; +/// field1, set_field1: 10, 0; +/// pub field2, _ : 12, 3; +/// } +/// impl BitRange for BitField1 { +/// fn bit_range(&self, msb: usize, lsb: usize) -> u8 { +/// let width = msb - lsb + 1; +/// let mask = (1 << width) - 1; +/// ((self.0 >> lsb) & mask) as u8 +/// } +/// fn set_bit_range(&mut self, msb: usize, lsb: usize, value: u8) { +/// self.0 = (value as u16) << lsb; +/// } +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitfield { + ($(#[$attribute:meta])* pub struct $($rest:tt)*) => { + bitfield!($(#[$attribute])* (pub) struct $($rest)*); + }; + ($(#[$attribute:meta])* struct $($rest:tt)*) => { + bitfield!($(#[$attribute])* () struct $($rest)*); + }; + // Force `impl Debug` to always be after `no default BitRange` it the two are present. + // This simplify the rest of the macro. + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($($type:tt)*); impl Debug; no default BitRange; $($rest:tt)*) => { + bitfield!{$(#[$attribute])* ($($vis)*) struct $name($($type)*); no default BitRange; impl Debug; $($rest)*} + }; + + // If we have `impl Debug` without `no default BitRange`, we will still match, because when + // we call `bitfield_bitrange`, we add `no default BitRange`. + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); no default BitRange; impl Debug; $($rest:tt)*) => { + impl + AsRef<[$t]> + crate::macros::fmt::Debug> crate::macros::fmt::Debug for $name { + bitfield_debug!{struct $name; $($rest)*} + } + + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); no default BitRange; $($rest:tt)*) => { + $(#[$attribute])* + $($vis)* struct $name(pub T); + + impl + AsRef<[$t]>> $name { + bitfield_fields!{$($rest)*} + } + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident([$t:ty]); $($rest:tt)*) => { + bitfield_bitrange!(struct $name([$t])); + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + + // The only difference between the MSB0 version anf the non-MSB0 version, is the BitRange + // implementation. We delegate everything else to the non-MSB0 version of the macro. + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident(MSB0 [$t:ty]); no default BitRange; $($rest:tt)*) => { + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident(MSB0 [$t:ty]); $($rest:tt)*) => { + bitfield_bitrange!(struct $name(MSB0 [$t])); + bitfield!{$(#[$attribute])* ($($vis)*) struct $name([$t]); no default BitRange; $($rest)*} + }; + + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); no default BitRange; impl Debug; $($rest:tt)*) => { + impl crate::macros::fmt::Debug for $name { + bitfield_debug!{struct $name; $($rest)*} + } + + bitfield!{$(#[$attribute])* ($($vis)*) struct $name($t); no default BitRange; $($rest)*} + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); no default BitRange; $($rest:tt)*) => { + $(#[$attribute])* + $($vis)* struct $name(pub $t); + + impl $name { + bitfield_fields!{$t; $($rest)*} + } + }; + ($(#[$attribute:meta])* ($($vis:tt)*) struct $name:ident($t:ty); $($rest:tt)*) => { + bitfield_bitrange!(struct $name($t)); + bitfield!{$(#[$attribute])* ($($vis)*) struct $name($t); no default BitRange; $($rest)*} + }; +} + +/// A trait to get or set ranges of bits. +pub trait BitRange { + fn get(&self) -> T; + /// Get a range of bits. + fn bit_range(&self, msb: usize, lsb: usize) -> T; + /// Set a range of bits. + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: T); +} + +/// A trait to get or set a single bit. +/// +/// This trait is implemented for all type that implement `BitRange`. +pub trait Bit { + /// Get a single bit. + fn bit(&self, bit: usize) -> bool; + + /// Check if only specific bit is set. + fn bit_only(&self, bit: usize) -> bool; + + /// Set a single bit. + fn set_bit(&mut self, bit: usize, value: bool); +} + +impl> Bit for T { + fn bit(&self, bit: usize) -> bool { + self.bit_range(bit, bit) != 0 + } + + fn bit_only(&self, bit: usize) -> bool { + self.get() == (1 << bit) as u8 + } + + fn set_bit(&mut self, bit: usize, value: bool) { + self.set_bit_range(bit, bit, value as u8); + } +} + +macro_rules! impl_bitrange_for_u { + ($t:ty, $bitrange_ty:ty) => { + impl BitRange<$bitrange_ty> for $t { + #[inline] + fn get(&self) -> $bitrange_ty { + *self as $bitrange_ty + } + + #[inline] + fn bit_range(&self, msb: usize, lsb: usize) -> $bitrange_ty { + let bit_len = size_of::<$t>()*8; + let result_bit_len = size_of::<$bitrange_ty>()*8; + let result = ((*self << (bit_len - msb - 1)) >> (bit_len - msb - 1 + lsb)) + as $bitrange_ty; + result << (result_bit_len - (msb - lsb + 1)) >> (result_bit_len - (msb - lsb + 1)) + } + + #[inline] + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $bitrange_ty) { + let bit_len = size_of::<$t>()*8; + let mask: $t = !(0 as $t) + << (bit_len - msb - 1) + >> (bit_len - msb - 1 + lsb) + << (lsb); + *self &= !mask; + *self |= (value as $t << lsb) & mask; + } + } + } +} + +macro_rules! impl_bitrange_for_u_combinations { +((),($($bitrange_ty:ty),*)) => { + +}; +(($t:ty),($($bitrange_ty:ty),*)) => { + $(impl_bitrange_for_u!{$t, $bitrange_ty})* +}; + (($t_head:ty, $($t_rest:ty),*),($($bitrange_ty:ty),*)) => { + impl_bitrange_for_u_combinations!{($t_head), ($($bitrange_ty),*)} + impl_bitrange_for_u_combinations!{($($t_rest),*), ($($bitrange_ty),*)} + }; +} + +impl_bitrange_for_u_combinations! {(u8, u16, u32, u64, u128), (u8, u16, u32, u64, u128)} +impl_bitrange_for_u_combinations! {(u8, u16, u32, u64, u128), (i8, i16, i32, i64, i128)} + +// Same as std::stringify but callable from local_inner_macros macros defined inside +// this crate. +#[macro_export] +#[doc(hidden)] +macro_rules! __bitfield_stringify { + ($s:ident) => { + stringify!($s) + }; +} + +// Same as std::debug_assert but callable from local_inner_macros macros defined inside +// this crate. +#[macro_export] +#[doc(hidden)] +macro_rules! __bitfield_debug_assert { + ($e:expr) => { + debug_assert!($e) + }; +} diff --git a/src/main.rs b/src/main.rs index a8f3575..1af8948 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,6 @@ use crate::stage::StageData; use crate::text_script::TextScriptVM; use crate::texture_set::TextureSet; use crate::ui::UI; -use crate::ggez::GameError::ResourceLoadError; mod bmfont; mod bmfont_renderer; @@ -55,6 +54,7 @@ mod enemy; mod frame; mod ggez; mod live_debugger; +mod macros; mod map; mod player; mod player_hit; @@ -164,8 +164,8 @@ impl Game { info!("NXEngine-evo data files detected."); } let font = BMFontRenderer::load(base_path, &constants.font_path, ctx)?; - //.or_else(|| Some(BMFontRenderer::load("/", "builtin/builtin_font.fnt", ctx)?)) - //.ok_or_else(|| ResourceLoadError(str!("Cannot load game font.")))?; + //.or_else(|| Some(BMFontRenderer::load("/", "builtin/builtin_font.fnt", ctx)?)) + //.ok_or_else(|| ResourceLoadError(str!("Cannot load game font.")))?; let s = Game { scene: None, diff --git a/src/player.rs b/src/player.rs index dacbc8a..77dc8a6 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,8 +1,9 @@ -use num_traits::clamp; use std::clone::Clone; -use crate::bitfield; +use num_traits::clamp; + use crate::caret::CaretType; +use crate::common::{Cond, Equip, Flags}; use crate::common::{Direction, Rect}; use crate::entity::GameEntity; use crate::frame::Frame; @@ -10,68 +11,6 @@ use crate::ggez::{Context, GameResult}; use crate::SharedGameState; use crate::str; -bitfield! { - #[derive(Clone)] - pub struct Flags(u32); - impl Debug; - - pub flag_x01, set_flag_x01: 0; - pub flag_x02, set_flag_x02: 1; - pub flag_x04, set_flag_x04: 2; - pub flag_x08, set_flag_x08: 3; - pub flag_x10, set_flag_x10: 4; - pub flag_x20, set_flag_x20: 5; - pub flag_x40, set_flag_x40: 6; - pub flag_x80, set_flag_x80: 7; - pub underwater, set_underwater: 8; // 0x100 - pub flag_x200, set_flag_x200: 9; - pub flag_x400, set_flag_x400: 10; - pub flag_x800, set_flag_x800: 11; - pub force_left, set_force_left: 12; // 0x1000 - pub force_up, set_force_up: 13; // 0x2000 - pub force_right, set_force_right: 14; // 0x4000 - pub force_down, set_force_down: 15; // 0x8000 - pub flag_x10000, set_flag_x10000: 16; // 0x10000 - pub flag_x20000, set_flag_x20000: 17; // 0x20000 - pub flag_x40000, set_flag_x40000: 18; // 0x40000 - pub flag_x80000, set_flag_x80000: 19; // 0x80000 - - // engine specific flags - pub head_bounced, set_head_bounced: 31; -} - -bitfield! { - #[derive(Clone)] - pub struct Equip(u16); - impl Debug; - - pub has_booster_0_8, set_booster_0_8: 0; - pub has_map, set_map: 1; - pub has_arms_barrier, set_arms_barrier: 2; - pub has_turbocharge, set_turbocharge: 3; - pub has_air_tank, set_air_tank: 4; - pub has_booster_2_0, set_booster_2_0: 5; - pub has_mimiga_mask, set_mimiga_mask: 6; - pub has_whimsical_star, set_whimsical_star: 7; - pub has_nikumaru, set_nikumaru: 8; - // 7 bits wasted, thx pixel -} - -bitfield! { - #[derive(Clone)] - pub struct Cond(u16); - impl Debug; - - pub cond_x01, set_cond_x01: 0; - pub hidden, set_hidden: 1; - pub cond_x04, set_cond_x04: 2; - pub cond_x08, set_cond_x08: 3; - pub cond_x10, set_cond_x10: 4; - pub cond_x20, set_cond_x20: 5; - pub cond_x40, set_cond_x40: 6; - pub visible, set_visible: 7; -} - #[derive(Clone)] pub struct Player { pub x: isize, @@ -155,7 +94,7 @@ impl Player { return Ok(()); } - let physics = if self.flags.underwater() { state.constants.my_char.water_physics } else { state.constants.my_char.air_physics }; + let physics = if self.flags.in_water() { state.constants.my_char.water_physics } else { state.constants.my_char.air_physics }; self.question = false; if self.flags.head_bounced() { @@ -172,7 +111,7 @@ impl Player { // todo: split those into separate procedures and refactor (try to not break the logic!) // ground movement - if self.flags.flag_x08() || self.flags.flag_x10() || self.flags.flag_x20() { + if self.flags.hit_bottom_wall() || self.flags.hit_right_slope() || self.flags.hit_left_slope() { self.booster_switch = 0; if self.equip.has_booster_0_8() || self.equip.has_booster_2_0() { @@ -287,9 +226,9 @@ impl Player { // jumping if state.control_flags.control_enabled() { self.up = state.key_state.up(); - self.down = state.key_state.down() && !self.flags.flag_x08(); + self.down = state.key_state.down() && !self.flags.hit_bottom_wall(); - if state.key_trigger.jump() && (self.flags.flag_x08() || self.flags.flag_x10() || self.flags.flag_x20()) && !self.flags.force_up() { + if state.key_trigger.jump() && (self.flags.hit_bottom_wall() || self.flags.hit_right_slope() || self.flags.hit_left_slope()) && !self.flags.force_up() { self.vel_y = -physics.jump; // todo: PlaySoundObject(15, SOUND_MODE_PLAY); } @@ -323,7 +262,7 @@ impl Player { if self.equip.has_booster_2_0() && self.booster_switch != 0 { match self.booster_switch { 1 => { - if self.flags.flag_x01() || self.flags.flag_x04() { + if self.flags.hit_left_wall() || self.flags.hit_right_wall() { self.vel_y = -0x100; // -0.5fix9 } @@ -369,7 +308,7 @@ impl Player { } // bounce off of ceiling - if self.flags.flag_x02() { + if self.flags.hit_top_wall() { self.vel_y = 0x200; // 1.0fix9 } } else if self.vel_y < 0 && state.control_flags.control_enabled() && state.key_state.jump() { @@ -379,22 +318,22 @@ impl Player { } if !state.control_flags.control_enabled() || !state.key_trigger.jump() { - if self.flags.flag_x10() && self.vel_x < 0 { + if self.flags.hit_right_slope() && self.vel_x < 0 { self.vel_y = -self.vel_x; } - if self.flags.flag_x20() && self.vel_x > 0 { + if self.flags.hit_left_slope() && self.vel_x > 0 { self.vel_y = self.vel_x; } - if (self.flags.flag_x08() && self.flags.flag_x80000() && self.vel_x < 0) - || (self.flags.flag_x08() && self.flags.flag_x10000() && self.vel_x > 0) - || (self.flags.flag_x08() && self.flags.flag_x20000() && self.flags.flag_x40000()) { + if (self.flags.hit_bottom_wall() && self.flags.hit_right_bigger_half() && self.vel_x < 0) + || (self.flags.hit_bottom_wall() && self.flags.hit_left_bigger_half() && self.vel_x > 0) + || (self.flags.hit_bottom_wall() && self.flags.hit_left_smaller_half() && self.flags.hit_right_smaller_half()) { self.vel_y = 0x400; // 2.0fix9 } } - let max_move = if self.flags.underwater() && !(self.flags.force_left() || self.flags.force_up() || self.flags.force_right() || self.flags.force_down()) { + let max_move = if self.flags.in_water() && !(self.flags.force_left() || self.flags.force_up() || self.flags.force_right() || self.flags.force_down()) { state.constants.my_char.water_physics.max_move } else { state.constants.my_char.air_physics.max_move @@ -405,12 +344,12 @@ impl Player { // todo: water splashing - if !self.flags.underwater() { + if !self.flags.in_water() { self.sprash = false; } // spike damage - if self.flags.flag_x400() { + if self.flags.hit_by_spike() { self.damage(10); } @@ -468,7 +407,7 @@ impl Player { return; } - if self.flags.flag_x08() { + if self.flags.hit_bottom_wall() { if self.cond.cond_x01() { self.anim_num = 11; } else if state.control_flags.control_enabled() && state.key_state.up() && (state.key_state.left() || state.key_state.right()) { @@ -560,7 +499,7 @@ impl Player { impl GameEntity for Player { fn tick(&mut self, state: &mut SharedGameState, _ctx: &mut Context) -> GameResult { - if !self.cond.visible() { + if !self.cond.alive() { return Ok(()); } @@ -596,7 +535,7 @@ impl GameEntity for Player { } fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<()> { - if !self.cond.visible() || self.cond.hidden() { + if !self.cond.alive() || self.cond.hidden() { return Ok(()); } diff --git a/src/player_hit.rs b/src/player_hit.rs index a650db1..a83214d 100644 --- a/src/player_hit.rs +++ b/src/player_hit.rs @@ -26,7 +26,7 @@ impl Player { self.vel_x = 0; } - self.flags.set_flag_x01(true); + self.flags.set_hit_left_wall(true); } // right wall @@ -44,7 +44,7 @@ impl Player { self.vel_x = 0; } - self.flags.set_flag_x04(true); + self.flags.set_hit_right_wall(true); } // ceiling @@ -62,7 +62,7 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x02(true); + self.flags.set_hit_top_wall(true); } // floor @@ -80,10 +80,11 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x08(true); + self.flags.set_hit_bottom_wall(true); } } + // upper left slope (bigger half) fn judge_hit_triangle_a(&mut self, state: &SharedGameState, x: isize, y: isize) { if self.x < (x * 0x10 + 8) * 0x200 && self.x > (x * 0x10 - 8) * 0x200 @@ -99,10 +100,11 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x02(true); + self.flags.set_hit_top_wall(true); } } + // upper left slope (smaller half) fn judge_hit_triangle_b(&mut self, state: &SharedGameState, x: isize, y: isize) { if self.x < (x * 0x10 + 8) * 0x200 && self.x > (x * 0x10 - 8) * 0x200 @@ -118,10 +120,11 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x02(true); + self.flags.set_hit_top_wall(true); } } + // upper right slope (smaller half) fn judge_hit_triangle_c(&mut self, state: &SharedGameState, x: isize, y: isize) { if self.x < (x * 0x10 + 8) * 0x200 && self.x > (x * 0x10 - 8) * 0x200 @@ -137,10 +140,11 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x02(true); + self.flags.set_hit_top_wall(true); } } + // upper right slope (bigger half) fn judge_hit_triangle_d(&mut self, state: &SharedGameState, x: isize, y: isize) { if (self.x < (x * 0x10 + 8) * 0x200) && (self.x > (x * 0x10 - 8) * 0x200) @@ -156,12 +160,13 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x02(true); + self.flags.set_hit_top_wall(true); } } + // lower left half (bigger) fn judge_hit_triangle_e(&mut self, state: &SharedGameState, x: isize, y: isize) { - self.flags.set_flag_x10000(true); + self.flags.set_hit_left_bigger_half(true); if (self.x < (x * 0x10 + 8) * 0x200) && (self.x > (x * 0x10 - 8) * 0x200) @@ -177,13 +182,14 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x20(true); - self.flags.set_flag_x08(true); + self.flags.set_hit_left_slope(true); + self.flags.set_hit_bottom_wall(true); } } + // lower left half (smaller) fn judge_hit_triangle_f(&mut self, state: &SharedGameState, x: isize, y: isize) { - self.flags.set_flag_x20000(true); + self.flags.set_hit_left_smaller_half(true); if (self.x < (x * 0x10 + 8) * 0x200) && (self.x > (x * 0x10 - 8) * 0x200) @@ -199,13 +205,14 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x20(true); - self.flags.set_flag_x08(true); + self.flags.set_hit_left_slope(true); + self.flags.set_hit_bottom_wall(true); } } + // lower right half (smaller) fn judge_hit_triangle_g(&mut self, state: &SharedGameState, x: isize, y: isize) { - self.flags.set_flag_x40000(true); + self.flags.set_hit_right_smaller_half(true); if (self.x < (x * 0x10 + 8) * 0x200) && (self.x > (x * 0x10 - 8) * 0x200) @@ -221,13 +228,14 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x10(true); - self.flags.set_flag_x08(true); + self.flags.set_hit_right_slope(true); + self.flags.set_hit_bottom_wall(true); } } + // lower right half (bigger) fn judge_hit_triangle_h(&mut self, state: &SharedGameState, x: isize, y: isize) { - self.flags.set_flag_x80000(true); + self.flags.set_hit_right_bigger_half(true); if (self.x < (x * 0x10 + 8) * 0x200) && (self.x > (x * 0x10 - 8) * 0x200) @@ -243,8 +251,8 @@ impl Player { self.vel_y = 0; } - self.flags.set_flag_x10(true); - self.flags.set_flag_x08(true); + self.flags.set_hit_right_slope(true); + self.flags.set_hit_bottom_wall(true); } } @@ -253,7 +261,7 @@ impl Player { && (self.x + self.hit.right as isize) > (x * 0x10 - 5) * 0x200 && (self.y - self.hit.top as isize) < (y * 0x10 + 5) * 0x200 && (self.y + self.hit.bottom as isize) > y * 0x10 * 0x200 { - self.flags.set_underwater(true); + self.flags.set_in_water(true); } }