Skip to main content

bitrs/
lib.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![cfg_attr(not(test), no_std)]
6
7// So that layout!å works in the test submodule.
8#[cfg(test)]
9extern crate self as bitrs;
10
11use core::fmt;
12
13// Re-exported for use by code generated by `layout!`, `multilayout!`, and
14// `bitfield_repr` so downstream crates don't have to depend on `zerocopy`
15// directly. This also allows `bitrs` to control the version of `zerocopy` that
16// is used.
17#[doc(hidden)]
18pub use ::zerocopy as __zerocopy;
19
20/// Specifies a layout of bitfields.
21///
22/// See the crate's `README.md` for details on syntax and behavior.
23pub use bitrs_macro::layout;
24
25/// Syntax sugar for defining a layout representation that also auto-derives the
26/// traits required of a custom bitfield representation.
27///
28/// In particular, `#[bitfield_repr(...)]` translates to
29/// ```text
30/// #[repr(...)]
31/// #[derive(
32///     Debug,
33///     Eq,
34///     PartialEq,
35///     zerocopy::Immutable,
36///     zerocopy::IntoBytes,
37///     zerocopy::TryFromBytes,
38/// )]
39/// ```
40pub use bitrs_macro::bitfield_repr;
41
42//
43// The following macros are convenient routines for use in the proc macros.
44//
45// TODO(https://github.com/rust-lang/rust-project-goals/issues/106): Ideally
46// these would be const functions generic over the base type, but that can't be
47// properly done until we have const traits.
48//
49
50#[doc(hidden)]
51#[macro_export]
52macro_rules! get_bit {
53    ($int:expr, $low_bit:literal) => {
54        (($int) & (1 << $low_bit)) != 0
55    };
56}
57
58#[doc(hidden)]
59#[macro_export]
60macro_rules! set_bit {
61    ($int:expr, $low_bit:literal, $value:ident) => {
62        if $value {
63            $int |= (1 << $low_bit);
64        } else {
65            $int &= !(1 << $low_bit);
66        }
67    };
68}
69
70#[doc(hidden)]
71#[macro_export]
72macro_rules! shifted_mask {
73    ($base:ty, $high_bit:literal, $low_bit:literal) => {{
74        const WIDTH: usize = $high_bit - $low_bit + 1;
75        if (<$base>::BITS as usize) == WIDTH { <$base>::MAX } else { (1 << WIDTH) - 1 }
76    }};
77}
78
79#[doc(hidden)]
80#[macro_export]
81macro_rules! get_field {
82    ($base:ty, $clamped:ty, $high_bit:literal, $low_bit:literal, $shifted:literal, $int:expr) => {{
83        const SHIFTED_MASK: $base = $crate::shifted_mask!($base, $high_bit, $low_bit);
84        let value = if $shifted {
85            ($int >> $low_bit) & SHIFTED_MASK
86        } else {
87            const UNSHIFTED_MASK: $base = SHIFTED_MASK << $low_bit;
88            $int & UNSHIFTED_MASK
89        };
90        value as $clamped
91    }};
92}
93
94#[doc(hidden)]
95#[macro_export]
96macro_rules! set_field {
97    ($base:ty, $high_bit:literal, $low_bit:literal, $shifted:literal, $int:expr, $value:ident) => {
98        const SHIFTED_MASK: $base = $crate::shifted_mask!($base, $high_bit, $low_bit);
99        const UNSHIFTED_MASK: $base = SHIFTED_MASK << $low_bit;
100
101        $int &= !UNSHIFTED_MASK;
102        if $shifted {
103            debug_assert!(($value & !SHIFTED_MASK) == 0);
104            $int |= ($value & SHIFTED_MASK) << $low_bit;
105        } else {
106            debug_assert!(($value & !UNSHIFTED_MASK) == 0);
107            $int |= $value & UNSHIFTED_MASK;
108        }
109    };
110}
111
112/// Implemented by unsigned integral type, this trait represents a valid base
113/// type for a bitfield layout.
114pub trait Unsigned: fmt::Debug + private::Sealed {}
115impl Unsigned for u8 {}
116impl Unsigned for u16 {}
117impl Unsigned for u32 {}
118impl Unsigned for u64 {}
119impl Unsigned for u128 {}
120
121// Ensures that no type outside of bitrs can implement this type.
122mod private {
123    pub trait Sealed {}
124    impl Sealed for u8 {}
125    impl Sealed for u16 {}
126    impl Sealed for u32 {}
127    impl Sealed for u64 {}
128    impl Sealed for u128 {}
129}
130
131/// Represents an invalid bit pattern for a field with a custom representation.
132///
133/// This is returned as the error type for the getters of such fields.
134#[derive(Debug)]
135pub struct InvalidBits<Base: Unsigned>(pub Base);
136
137/// The metadata of a (non-reserved) bitfield.
138///
139/// The iterator of a [`layout!`] type will have an associated item type of
140/// `(&'static FieldMetadata<Base>, Base)`.
141#[derive(Debug)]
142pub struct FieldMetadata<Base: Unsigned> {
143    /// The name of the bitfield.
144    pub name: &'static str,
145    /// The high bit of the bitfield.
146    pub high_bit: u32,
147    /// The low bit of the bitfield.
148    pub low_bit: u32,
149    /// The default value of the bitfield.
150    pub default: Base,
151}
152
153#[cfg(test)]
154mod tests {
155    use super::{FieldMetadata, bitfield_repr, layout};
156
157    layout!({
158        struct EmptyU8(u8);
159        {}
160    });
161
162    layout!({
163        struct OneFieldU16(u16);
164        {
165            let a @ 15..0;
166        }
167    });
168
169    layout!({
170        struct TwoFieldsU32(u32);
171        {
172            let a @ 31..16;
173            let b @ 15..0;
174        }
175    });
176
177    layout!({
178        struct ThreeFieldsU64(u64);
179        {
180            let a @ 63..32;
181            let b @ 31..16;
182            let c @ 15..0;
183        }
184    });
185
186    layout!({
187        struct FourFieldsU128(u128);
188        {
189            let a @ 127..96;
190            let b @ 95..64;
191            let c @ 63..32;
192            let d @ 31..0;
193        }
194    });
195
196    #[test]
197    fn size_and_alignment() {
198        assert_eq!(size_of::<EmptyU8>(), size_of::<u8>());
199        assert_eq!(align_of::<EmptyU8>(), align_of::<u8>());
200
201        assert_eq!(size_of::<OneFieldU16>(), size_of::<u16>());
202        assert_eq!(align_of::<OneFieldU16>(), align_of::<u16>());
203
204        assert_eq!(size_of::<TwoFieldsU32>(), size_of::<u32>());
205        assert_eq!(align_of::<TwoFieldsU32>(), align_of::<u32>());
206
207        assert_eq!(size_of::<ThreeFieldsU64>(), size_of::<u64>());
208        assert_eq!(align_of::<ThreeFieldsU64>(), align_of::<u64>());
209
210        assert_eq!(size_of::<FourFieldsU128>(), size_of::<u128>());
211        assert_eq!(align_of::<FourFieldsU128>(), align_of::<u128>());
212    }
213
214    #[bitfield_repr(u8)]
215    pub enum CustomFieldRepr {
216        Option1 = 0xa,
217        Option2 = 0xf,
218    }
219
220    layout!({
221        pub struct Example(u64);
222        {
223            let u32_repr @ 44..27;
224            let custom @ 26..23: CustomFieldRepr;
225            let custom_with_default @ 22..19: CustomFieldRepr = CustomFieldRepr::Option1;
226            let __ @ 18..11 = 0xef;
227            let with_default @ 10..9 = 0b11;
228            let bit @ 8;
229            let u8_repr @ 7..4;
230            let __ @ 3..2 = 1;
231            let __ @ 1..0;
232        }
233    });
234
235    #[test]
236    fn constants() {
237        assert_eq!(Example::RSVD1_MASK, (0xef << 11) | (0b01 << 2));
238        assert_eq!(Example::RSVD0_MASK, (0x10 << 11) | (0b10 << 2));
239
240        assert_eq!(
241            Example::DEFAULT,
242            (0xef << 11) | (0b01 << 2) | ((CustomFieldRepr::Option1 as u64) << 19) | (0b11 << 9)
243        );
244
245        assert_eq!(Example::U32_REPR_MASK, 0x1fff_f800_0000);
246        assert_eq!(Example::U32_REPR_SHIFT, 27usize,);
247
248        assert_eq!(Example::CUSTOM_MASK, 0x780_0000);
249        assert_eq!(Example::CUSTOM_SHIFT, 23usize);
250
251        assert_eq!(Example::CUSTOM_WITH_DEFAULT_MASK, 0x78_0000);
252        assert_eq!(Example::CUSTOM_WITH_DEFAULT_SHIFT, 19usize);
253
254        assert_eq!(Example::RSVD_18_11, 0xef << 11);
255
256        assert_eq!(Example::WITH_DEFAULT_MASK, 0x600);
257        assert_eq!(Example::WITH_DEFAULT_SHIFT, 9usize);
258
259        assert_eq!(Example::BIT_SHIFT, 8usize);
260
261        assert_eq!(Example::U8_REPR_MASK, 0xf0);
262        assert_eq!(Example::U8_REPR_SHIFT, 4usize);
263
264        assert_eq!(Example::RSVD_3_2, 1 << 2);
265    }
266
267    // new() should return a value with only reserved-as values set.
268    #[test]
269    fn new() {
270        assert_eq!(Example::new().bits(), Example::RSVD1_MASK);
271    }
272
273    // default() should return a value with only defaults and reserved-as
274    // values set.
275    #[test]
276    fn default() {
277        assert_eq!(Example::default().bits(), Example::DEFAULT);
278    }
279
280    #[test]
281    fn from() {
282        assert_eq!(Example::from(Example::RSVD1_MASK).bits(), Example::RSVD1_MASK);
283        assert_eq!(Example::from(1 | Example::RSVD1_MASK).bits(), 1 | Example::RSVD1_MASK);
284        assert_eq!(
285            Example::from(0xffff_0000_0000_0000 | Example::RSVD1_MASK).bits(),
286            0xffff_0000_0000_0000 | Example::RSVD1_MASK
287        );
288    }
289
290    #[test]
291    fn from_then_get() {
292        let example = Example::from(
293            0xabcd << 27
294                | (CustomFieldRepr::Option1 as u64) << 23
295                | (CustomFieldRepr::Option2 as u64) << 19
296                | 0b10 << 9
297                | 1 << 8
298                | 0xc << 4
299                | Example::RSVD1_MASK,
300        );
301        assert_eq!(example.u32_repr(), 0xabcd);
302        assert_eq!(example.custom(), CustomFieldRepr::Option1);
303        assert_eq!(example.custom_with_default(), CustomFieldRepr::Option2);
304        assert_eq!(example.with_default(), 0b10);
305        assert!(example.bit());
306        assert_eq!(example.u8_repr(), 0xc);
307    }
308
309    #[test]
310    fn set_then_get() {
311        let example = *Example::new()
312            .set_u32_repr(0xabcd)
313            .set_custom(CustomFieldRepr::Option1)
314            .set_custom_with_default(CustomFieldRepr::Option2)
315            .set_with_default(0b10)
316            .set_bit(true)
317            .set_u8_repr(0xc);
318        assert_eq!(example.u32_repr(), 0xabcd);
319        assert_eq!(example.custom(), CustomFieldRepr::Option1);
320        assert_eq!(example.custom_with_default(), CustomFieldRepr::Option2);
321        assert_eq!(example.with_default(), 0b10);
322        assert!(example.bit());
323        assert_eq!(example.u8_repr(), 0xc);
324    }
325
326    #[test]
327    fn iter() {
328        type Metadata = FieldMetadata<u64>;
329
330        const EXPECTED: [(u64, Metadata); 6] = [
331            (0xabcd, Metadata { name: "u32_repr", high_bit: 44, low_bit: 27, default: 0 }),
332            (0xa, Metadata { name: "custom", high_bit: 26, low_bit: 23, default: 0 }),
333            (
334                0xf,
335                Metadata { name: "custom_with_default", high_bit: 22, low_bit: 19, default: 0xa },
336            ),
337            (0b10, Metadata { name: "with_default", high_bit: 10, low_bit: 9, default: 0b11 }),
338            (0b1, Metadata { name: "bit", high_bit: 8, low_bit: 8, default: 0 }),
339            (0xc, Metadata { name: "u8_repr", high_bit: 7, low_bit: 4, default: 0 }),
340        ];
341
342        let example = *Example::new()
343            .set_u32_repr(0xabcd)
344            .set_custom(CustomFieldRepr::Option1)
345            .set_custom_with_default(CustomFieldRepr::Option2)
346            .set_with_default(0b10)
347            .set_bit(true)
348            .set_u8_repr(0xc);
349
350        let actual: Vec<(&'static Metadata, u64)> = example.into_iter().collect();
351        let rev_actual: Vec<(&'static Metadata, u64)> = example.into_iter().rev().collect();
352
353        assert_eq!(actual.len(), EXPECTED.len());
354        assert_eq!(rev_actual.len(), EXPECTED.len());
355        for i in 0..EXPECTED.len() {
356            let (expected_val, expected_metadata) = &EXPECTED[i];
357            for (label, (actual_metadata, actual_val)) in
358                [("fwd", &actual[i]), ("rev", &rev_actual[EXPECTED.len() - 1 - i])]
359            {
360                assert_eq!(actual_val, expected_val, "{label}:{i}");
361                assert_eq!(actual_metadata.name, expected_metadata.name, "{label}:{i}");
362                assert_eq!(actual_metadata.high_bit, expected_metadata.high_bit, "{label}:{i}");
363                assert_eq!(actual_metadata.low_bit, expected_metadata.low_bit, "{label}:{i}");
364                assert_eq!(actual_metadata.default, expected_metadata.default, "{label}:{i}");
365            }
366        }
367    }
368
369    layout!({
370        struct Unshifted(u32);
371        {
372            let field @ 19..16;
373            #[unshifted]
374            let unshifted_field @ 15..12;
375            let __ @ 11..9;
376            #[unshifted]
377            let unshifted_bit @ 8;
378            let normal_bit @ 7;
379            let __ @ 6..0;
380        }
381    });
382
383    #[test]
384    fn unshifted_multi_bit_getter() {
385        let val = Unshifted::from(0x5 << 12);
386        assert_eq!(val.unshifted_field(), 0x5000);
387    }
388
389    #[test]
390    fn unshifted_multi_bit_setter() {
391        let mut val = Unshifted::new();
392        val.set_unshifted_field(0xa000);
393        assert_eq!(val.unshifted_field(), 0xa000);
394        assert_eq!(val.bits() & (0xf << 12), 0xa000);
395    }
396
397    #[test]
398    fn unshifted_single_bit_getter() {
399        let val = Unshifted::from(1 << 8);
400        assert_eq!(val.unshifted_bit(), 1 << 8);
401
402        let val = Unshifted::from(0);
403        assert_eq!(val.unshifted_bit(), 0);
404    }
405
406    #[test]
407    fn unshifted_single_bit_setter() {
408        let mut val = Unshifted::new();
409        val.set_unshifted_bit(1 << 8);
410        assert_eq!(val.unshifted_bit(), 1 << 8);
411
412        val.set_unshifted_bit(0);
413        assert_eq!(val.unshifted_bit(), 0);
414    }
415
416    #[test]
417    fn unshifted_round_trip() {
418        let val = *Unshifted::new()
419            .set_unshifted_field(0x7000)
420            .set_unshifted_bit(1 << 8)
421            .set_field(0xa)
422            .set_normal_bit(true);
423        assert_eq!(val.unshifted_field(), 0x7000);
424        assert_eq!(val.unshifted_bit(), 1 << 8);
425        assert_eq!(val.field(), 0xa);
426        assert!(val.normal_bit());
427    }
428
429    #[test]
430    fn unshifted_ignores_other_bits() {
431        let val = Unshifted::from(0xffff_ffff);
432        assert_eq!(val.unshifted_field(), 0xf000);
433        assert_eq!(val.unshifted_bit(), 1 << 8);
434    }
435}