Robbepop / modular-bitfield

Macro to generate bitfields for structs that allow for modular use of enums.
Apache License 2.0
159 stars 41 forks source link

Setting field alters other field #11

Closed crzysdrs closed 4 years ago

crzysdrs commented 4 years ago

Modifying almost any field changes the mode field back to the zero valued form of StatMode, HBlank.

src/main.rs

use modular_bitfield::prelude::*;
#[derive(BitfieldSpecifier, Debug, PartialEq, Copy, Clone)]
pub enum StatMode {
    HBlank = 0b00,
    VBlank = 0b01,
    OAM = 0b10,
    PixelTransfer = 0b11,
}

#[bitfield]
#[derive(Debug)]
pub struct StatFlag {  
    unused : B1,
    coincidence : bool,
    oam: bool,
    vblank : bool,        
    hblank : bool,
    coincidence_flag : bool,
    #[bits = 2]
    mode : StatMode,    
}

fn main() {
    let x = StatMode::VBlank;
    let mut flag = StatFlag::new();
    flag.set_mode(x);
    println!("{:?}", flag);
    assert_eq!(flag.get_mode(), x);
    flag.set_coincidence_flag(true); /* this alters the mode field */

    println!("{:?}", flag);
    assert_eq!(flag.get_mode(), x); // FAILS
}

Cargo.toml

[package]
name = "repr"
version = "0.1.0"
edition = "2018"

[dependencies]
modular-bitfield = "0.6.0"
> $ cargo run
>     Finished dev [unoptimized + debuginfo] target(s) in 0.00s
>      Running `target/debug/repr`
> StatFlag { data: [64] }
> StatFlag { data: [32] }
> thread 'main' panicked at 'assertion failed: `(left == right)`
>   left: `HBlank`,
>  right: `VBlank`', src/main.rs:32:5
> note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Robbepop commented 4 years ago

Hi! Thank you for the bug report and the test case - that helps a lot. I ll look into it. :)

Robbepop commented 4 years ago

I slightly modified the test case to:

use modular_bitfield::prelude::*;

#[derive(BitfieldSpecifier, Debug, PartialEq, Copy, Clone)]
pub enum Mode {
    A = 0b00,
    B = 0b01,
    C = 0b10,
    D = 0b11,
}

#[bitfield]
#[derive(Debug)]
pub struct StatFlag {
    x: bool,
    y: bool,
    z: B4,
    #[bits = 2]
    mode: Mode,
}

fn main() {
    let mut flag = StatFlag::new();

    assert_eq!(flag.get_x(), false);
    assert_eq!(flag.get_y(), false);
    assert_eq!(flag.get_z(), 0);
    assert_eq!(flag.get_mode(), Mode::A);

    let new_mode = Mode::B;

    flag.set_mode(new_mode);
    assert_eq!(flag.get_mode(), new_mode);

    flag.set_x(true);
    assert_eq!(flag.get_x(), true);
    assert_eq!(flag.get_mode(), new_mode);

    flag.set_y(true);
    assert_eq!(flag.get_y(), true);
    assert_eq!(flag.get_mode(), new_mode);

    flag.set_z(0b11);
    assert_eq!(flag.get_z(), 0b11);
    assert_eq!(flag.get_mode(), new_mode);
}

The problem seems to be that the mode field is always reset to 0.