Best way to use bitvec to read individual bits from this set of integers

So, I'm trying to get around the fact that Rust (still) doesn't have anything like a bitfield construct in the language yet.

I'm writing a small module that parses bits for the real-time clock in older x86 systems (and sometimes newer ones). The RTC has four "status" registers laid out as follows:

Status A:

Bit Description
0:6 Unspecified
7 Update-in-progress (UIP)

Status B:

Bit Description
0 Enable daylight savings time
1 Time mode (12 hour or 24 hour)
2 Data mode (1 = binary, 0 = BCD)
3 Enable square-wave output
4 Enable update-ended interrupt
5 Enable alarm interrupt
6 Enable periodic interrupt
7 Enable setting of the clock by freezing updates

Status C:

Bit Description
0:3 Unspecified
4 Update has ended
5 Alarm interrupt has triggered
6 Periodic interrupt has triggered
7 General interrupt has triggered, is set if any of bits 4-6 are set

Status D:

Bit Description
0:6 Unspecified
7 Valid RAM for CMOS

Currently I specify these using modular-bitfield. However, the bitfield proc-macro does not appear to be respecting my visibility modifiers, and that is causing the unreachable_pub lint to wine. Its also emitting dead code, and even explicitly tries to allow it, despite the fact that I have it set to forbid. I cannot seem to find any way to change this behavior, and I'm completely unexperienced with modifying or understanding the internals of proc-macros. I describe the bitfields, however, using this code:

#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, BitfieldSpecifier)]
pub(crate) enum DataMode {
    Bcd,
    Binary,
}

#[bitfield(bits = 8)]
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct StatusA {
    #[skip]
    #[bits = 7]
    _rsvd: B7,
    /// Update in progress
    #[skip(setters)]
    #[bits = 1]
    pub(crate) update_in_progress: bool,
}

#[bitfield(bits = 8)]
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct StatusB {
    /// Daylight Savings Enable
    #[bits = 1]
    pub(crate) enable_dst: bool,
    /// 24-hour time
    #[bits = 1]
    pub(crate) hr24: bool,
    /// Data Mode - 0: BCD, 1: Binary
    #[bits = 1]
    pub(crate) data_mode: DataMode,
    /// enable square wave output
    #[bits = 1]
    pub(crate) enable_square_wave_output: bool,
    /// enable update-ended interrupt
    #[bits = 1]
    pub(crate) enable_update_ended_interrupt: bool,
    /// enable alarm interrupt
    #[bits = 1]
    pub(crate) enable_alarm_interrupt: bool,
    /// enable periodic interrupt
    #[bits = 1]
    pub(crate) enable_periodic_interrupt: bool,
    /// enable clock setting by freezing updates
    #[bits = 1]
    pub(crate) enable_clock_setting: bool,
}

#[bitfield(bits = 8)]
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct StatusC {
    #[skip]
    #[bits = 4]
    _rsvd: B4,
    /// Update-Ended Interrupt Flag
    #[skip(setters)]
    #[bits = 1]
    pub(crate) update_ended: bool,
    /// Alarm Interrupt flag
    #[skip(setters)]
    #[bits = 1]
    pub(crate) alarm_interrupt: bool,
    /// Periodic Interrupt flag
    #[skip(setters)]
    #[bits = 1]
    pub(crate) periodic_interrupt: bool,
    /// Interrupt request flag =1 when any or all of bits 6-4 are 1 and appropriate enables
    /// (Register B) are set to 1. Generates IRQ 8 when triggered.
    #[skip(setters)]
    #[bits = 1]
    pub(crate) irq: bool,
}

#[bitfield(bits = 8)]
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub(crate) struct StatusD {
    #[skip]
    #[bits = 7]
    _rsvd: B7,
    /// Valid RAM - 1 indicates battery power good, 0 if dead or disconnected.
    #[skip(setters)]
    #[bits = 1]
    pub(crate) valid_ram: bool,
}

How can I make this work with bitvec? I could always just read the bits manually, too, but I'd like to use something like Bitvec if at all possible. (Or somebody might know a way around this problem -- other than disabling unreachable_pub -- unless there's a good reason for doing so, that is.)

You can use #[deny(...)] rather than #[forbid(...)] to allow the macro to locally silence the lint.

I could do that for unreachable_pub, but I forbid warnings, and #[allow(dead_code)] wouldn't work, and I don't like denying warnings because I like to minimize the warnings that my code generates.

You probably can't use the macro then. You could define a struct that has getters that use bit manipulation.

Yeah, I could do that. Can I not just load the byte into bitvec and then scan it that way?

Using the bitvec crate would allocate memory, which is usually preferable to avoid, which using a struct that wraps the integer and using bit manipulation in the getters and setters would do.

To answer the question, I don't know how to do it with the bitvec crate.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.