1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-03-24 02:49:21 +00:00

some flag naming and refactoring

This commit is contained in:
Alula 2020-08-31 20:33:01 +02:00
parent 1cb6b1bf07
commit 8f7eb2e025
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
5 changed files with 738 additions and 752 deletions

View file

@ -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<S: Num + Copy> Rect<S> {
}
}
}
#[derive(Debug)]
pub struct CursorIterator<'a> {
cursor: RefCell<Cursor<&'a Vec<u8>>>,
}
impl<'a> CursorIterator<'a> {
pub fn new(cursor: RefCell<Cursor<&'a Vec<u8>>>) -> CursorIterator<'a> {
CursorIterator { cursor }
}
}
impl<'a> Iterator for CursorIterator<'a> {
type Item = u8;
#[inline]
fn next(&mut self) -> Option<u8> {
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 [<only_ $getter>](&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>(T);
/// bitfield_bitrange!{struct BitField2([u8])}
///
/// struct BitField3<T>(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<T: AsMut<[$slice_ty]> + AsRef<[$slice_ty]>> crate::common::BitRange<$bitrange_ty>
for $name<T> {
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<T: AsMut<[$slice_ty]> + AsRef<[$slice_ty]>> crate::common::BitRange<$bitrange_ty>
for $name<T> {
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<T> crate::common::BitRange<T> for $name where $t: crate::common::BitRange<T> {
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<u8> 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<T: AsMut<[$t]> + AsRef<[$t]> + crate::common::fmt::Debug> crate::common::fmt::Debug for $name<T> {
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<T>(pub T);
impl<T: AsMut<[$t]> + AsRef<[$t]>> $name<T> {
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<T> {
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<u8>`.
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<T: BitRange<u8>> 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)
};
}

622
src/macros.rs Normal file
View file

@ -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 [<only_ $getter>](&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>(T);
/// bitfield_bitrange!{struct BitField2([u8])}
///
/// struct BitField3<T>(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<T: AsMut<[$slice_ty]> + AsRef<[$slice_ty]>> crate::macros::BitRange<$bitrange_ty>
for $name<T> {
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<T: AsMut<[$slice_ty]> + AsRef<[$slice_ty]>> crate::macros::BitRange<$bitrange_ty>
for $name<T> {
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<T> crate::macros::BitRange<T> for $name where $t: crate::macros::BitRange<T> {
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<u8> 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<T: AsMut<[$t]> + AsRef<[$t]> + crate::macros::fmt::Debug> crate::macros::fmt::Debug for $name<T> {
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<T>(pub T);
impl<T: AsMut<[$t]> + AsRef<[$t]>> $name<T> {
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<T> {
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<u8>`.
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<T: BitRange<u8>> 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)
};
}

View file

@ -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,

View file

@ -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(());
}

View file

@ -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);
}
}