pub trait BitField {
fn load_le<M>(&self) -> M
where
M: BitMemory;
fn load_be<M>(&self) -> M
where
M: BitMemory;
fn store_le<M>(&mut self, value: M)
where
M: BitMemory;
fn store_be<M>(&mut self, value: M)
where
M: BitMemory;
fn load<M>(&self) -> M
where
M: BitMemory,
{ ... }
fn store<M>(&mut self, value: M)
where
M: BitMemory,
{ ... }
}
Expand description
Performs C-style bitfield access through a BitSlice
.
This trait transfers data between a BitSlice
region and a local integer. The
trait functions always place the live bits of the value against the least
significant bit edge of the local integer (the return value of the load methods,
and the argument value of the store methods).
Methods should be called as bits[start .. end].load_or_store()
, where the
range subslice selects no more than the M::BITS
element width.
Target-Specific Behavior
When you are using this trait to manage memory that never leaves your machine,
you can use the load
and store
methods. However, if you are using this
trait to operate on a de/serialization buffer, where the exact bit pattern in
memory is important to your work and/or you need to be aware of the processor
byte endianness, you must not use these methods.
Instead, use load_le
, load_be
, store_le
, orstore_be
directly.
The un-suffixed methods choose their implementation based on the target processor byte endianness; the suffixed methods have a consistent and fixed behavior.
Element- and Bit- Ordering Combinations
The _le
and _be
method suffices refer to the significance of successive
elements T
in memory, while the BitOrder
trait refers to the order that bits
within a single element T
are traversed. The BitField
methods and the
BitOrder
implementors are not related.
When a load or store operation is contained in only one memory element, then the
_le
and _be
methods have the same behavior. They differ when the operation
must touch more than one element.
The module documentation contains a more detailed explanation, and examples, for this behavior.
Required methods
Loads from self
, using little-endian element T
ordering.
This function interprets a multi-element slice as having its least
significant chunk in the low memory address, and its most significant
chunk in the high memory address. Each element T
is still interpreted
from individual bytes according to the local CPU ordering.
Parameters
&self
: A read reference to some bits in memory. This slice must be trimmed to have a width no more than theM::BITS
width of the type being loaded. This can be accomplished with range indexing on a larger slice.
Returns
A value M
whose least self.len()
significant bits are filled with
the bits of self
. If self
spans multiple elements T
, then the
lowest-address T
is interpreted as containing the least significant
bits of the return value M
, and the highest-address T
is interpreted
as containing its most significant bits.
Panics
This method is encouraged to panic if self
is empty, or wider than a
single element M
.
Examples
This example shows how a value is segmented across multiple storage elements:
use bitvec::prelude::*;
let mut data = [0u8; 3];
data.view_bits_mut::<Msb0>()
[5 .. 17]
.store_le(0b0000_1_1011_1000_110u16);
// O PQRS TUVW XYZ
assert_eq!(data, [
0b00000_110, 0b1011_1000, 0b1_0000000
// XYZ PQRS TUVW O
]);
let val = data.view_bits::<Msb0>()
[5 .. 17]
.load_le::<u16>();
assert_eq!(
val,
0b0000_1_1011_1000_110,
// O PQRS TUVW XYZ
);
And this example shows how the same memory region will be read by
different BitOrder
implementors:
use bitvec::prelude::*;
// Bit pos: 14 19 16
// Lsb0: ─┤ ├──┤
let arr = [0b0100_0000_0000_0011u16, 0b0001_0000_0000_1110u16];
// Msb0: ├─ ├──┤
// Bit pos: 14 16 19
assert_eq!(
arr.view_bits::<Lsb0>()[14 .. 20].load_le::<u8>(),
0b111001,
);
assert_eq!(
arr.view_bits::<Msb0>()[14 .. 20].load_le::<u8>(),
0b000111,
);
Loads from self
, using big-endian element T
ordering.
This function interprets a multi-element slice as having its most
significant chunk in the low memory address, and its least significant
chunk in the high memory address. Each element T
is still interpreted
from individual bytes according to the local CPU ordering.
Parameters
&self
: A read reference to some bits in memory. This slice must be trimmed to have a width no more than theM::BITS
width of the type being loaded. This can be accomplished with range indexing on a larger slice.
Returns
A value M
whose least self.len()
significant bits are filled with
the bits of self
. If self
spans multiple elements T
, then the
lowest-address T
is interpreted as containing the most significant
bits of the return value M
, and the highest-address T
is interpreted
as containing its least significant bits.
Panics
This method is encouraged to panic if self
is empty, or wider than a
single element M
.
Examples
This example shows how a value is segmented across multiple storage elements:
use bitvec::prelude::*;
let mut data = [0u8; 3];
data.view_bits_mut::<Msb0>()
[5 .. 17]
.store_be(0b0000_110_1000_1011_1u16);
// OPQ RSTU VWXY Z
assert_eq!(data, [
0b00000_110, 0b1000_1011, 0b1_0000000
// OPQ RSTU VWXY Z
]);
let val = data.view_bits::<Msb0>()
[5 .. 17]
.load_be::<u16>();
assert_eq!(
val,
0b0000_110_1000_1011_1,
// OPQ RSTU VWXY Z
);
And this example shows how the same memory region will be read by
different BitOrder
implementations:
use bitvec::prelude::*;
// Bit pos: 14 19 16
// Lsb0: ─┤ ├──┤
let arr = [0b0100_0000_0000_0011u16, 0b0001_0000_0000_1110u16];
// Msb0: ├─ ├──┤
// Bit pos: 14 15 19
assert_eq!(
arr.view_bits::<Lsb0>()[14 .. 20].load_be::<u8>(),
0b011110,
);
assert_eq!(
arr.view_bits::<Msb0>()[14 .. 20].load_be::<u8>(),
0b110001,
);
Stores into self
, using little-endian element ordering.
This function interprets a multi-element slice as having its least
significant chunk in the low memory address, and its most significant
chunk in the high memory address. Each element T
is still interpreted
from individual bytes according to the local CPU ordering.
Parameters
&mut self
: A write reference to some bits in memory. This slice must be trimmed to have a width no more than theM::BITS
width of the type being stored. This can be accomplished with range indexing on a larger slice.value
: A value, whoseself.len()
least significant bits will be stored intoself
.
Behavior
The self.len()
least significant bits of value
are written into
the domain of self
. If self
spans multiple elements T
, then the
lowest-address T
is interpreted as containing the least significant
bits of the M
return value, and the highest-address T
is interpreted
as containing its most significant bits.
Panics
This method is encouraged to panic if self
is empty, or wider than a
single element M
.
Examples
This example shows how a value is segmented across multiple storage elements:
use bitvec::prelude::*;
let mut data = [0u8; 3];
data.view_bits_mut::<Lsb0>()
[5 .. 17]
.store_le(0b0000_1_1011_1000_110u16);
// O PQRS TUVW XYZ
assert_eq!(data, [
0b110_00000, 0b1011_1000, 0b0000000_1
// XYZ PQRS TUVW O
]);
let val = data.view_bits::<Lsb0>()
[5 .. 17]
.load_le::<u16>();
assert_eq!(
val,
0b0000_1_1011_1000_110u16,
// O PQRS TUVW XYZ
);
And this example shows how the same memory region is written by
different BitOrder
implementations:
use bitvec::prelude::*;
let mut lsb0 = bitarr![Lsb0, u16; 0; 32];
let mut msb0 = bitarr![Msb0, u16; 0; 32];
// Bit pos: 14 19 16
// Lsb0: ─┤ ├──┤
let exp_lsb0 = [0b0100_0000_0000_0000u16, 0b0000_0000_0000_1110u16];
let exp_msb0 = [0b0000_0000_0000_0011u16, 0b0001_0000_0000_0000u16];
// Msb0: ├─ ├──┤
// Bit pos: 14 15 19
lsb0[14 ..= 19].store_le(0b111001u8);
msb0[14 ..= 19].store_le(0b000111u8);
assert_eq!(lsb0.as_raw_slice(), exp_lsb0);
assert_eq!(msb0.as_raw_slice(), exp_msb0);
Stores into self
, using big-endian element ordering.
This function interprets a multi-element slice as having its most
significant chunk in the low memory address, and its least significant
chunk in the high memory address. Each element T
is still interpreted
from individual bytes according to the local CPU ordering.
Parameters
&mut self
: A write reference to some bits in memory. This slice must be trimmed to have a width no more than theM::BITS
width of the type being stored. This can be accomplished with range indexing on a larger slice.value
: A value, whoseself.len()
least significant bits will be stored intoself
.
Behavior
The self.len()
least significant bits of value
are written into
the domain of self
. If self
spans multiple elements T
, then the
lowest-address T
is interpreted as containing the most significant
bits of the M
return value, and the highest-address T
is interpreted
as containing its least significant bits.
Panics
This method is encouraged to panic if self
is empty, or wider than a
single element M
.
Examples
This example shows how a value is segmented across multiple storage elements:
use bitvec::prelude::*;
let mut data = [0u8; 3];
data.view_bits_mut::<Lsb0>()
[5 .. 17]
.store_be(0b0000_110_1000_1011_1u16);
// OPQ RSTU VWXY Z
assert_eq!(data, [
0b110_00000, 0b1000_1011, 0b0000000_1
// OPQ RSTU VWXY Z
]);
let val = data.view_bits::<Lsb0>()
[5 .. 17]
.load_be::<u16>();
assert_eq!(
val,
0b0000_110_1000_1011_1u16,
// OPQ RSTU VWXY Z
);
And this example shows how the same memory region is written by
different BitOrder
implementations:
use bitvec::prelude::*;
let mut lsb0 = bitarr![Lsb0, u16; 0; 32];
let mut msb0 = bitarr![Msb0, u16; 0; 32];
// Bit pos: 14 19 16
// Lsb0: ─┤ ├──┤
let exp_lsb0 = [0b0100_0000_0000_0000u16, 0b0000_0000_0000_1110u16];
let exp_msb0 = [0b0000_0000_0000_0011u16, 0b0001_0000_0000_0000u16];
// Msb0: ├─ ├──┤
// Bit pos: 14 15 19
lsb0[14 ..= 19].store_be(0b011110u8);
msb0[14 ..= 19].store_be(0b110001u8);
assert_eq!(lsb0.as_raw_slice(), exp_lsb0);
assert_eq!(msb0.as_raw_slice(), exp_msb0);
Provided methods
Loads the bits in the self
region into a local value.
This can load into any of the unsigned integers which implement
BitMemory
. Any further transformation must be done by the user.
Target-Specific Behavior
THIS FUNCTION CHANGES BEHAVIOR FOR DIFFERENT TARGETS.
The default implementation of this function calls load_le
on
little-endian byte-ordered CPUs, and load_be
on big-endian
byte-ordered CPUs.
If you are using this function from a region that crosses multiple elements in memory, be aware that it will behave differently on big-endian and little-endian target architectures.
Parameters
&self
: A read reference to some bits in memory. This slice must be trimmed to have a width no more than theM::BITS
width of the type being loaded. This can be accomplished with range indexing on a larger slice.
Returns
A value M
whose least self.len()
significant bits are filled with
the bits of self
.
Panics
This method is encouraged to panic if self
is empty, or wider than a
single element M
.
Stores a sequence of bits from the user into the domain of self
.
This can store any of the unsigned integers which implement
BitMemory
. Any other types must first be transformed by the user.
Target-Specific Behavior
THIS FUNCTION CHANGES BEHAVIOR FOR DIFFERENT TARGETS.
The default implementation of this function calls store_le
on
little-endian byte-ordered CPUs, and store_be
on big-endian
byte-ordered CPUs.
If you are using this function to store into a region that crosses multiple elements in memory, be aware that it will behave differently on big-endian and little-endian target architectures.
Parameters
&mut self
: A write reference to some bits in memory. This slice must be trimmed to have a width no more than theM::BITS
width of the type being stored. This can be accomplished with range indexing on a larger slice.value
: A value, whoseself.len()
least significant bits will be stored intoself
.
Behavior
The self.len()
least significant bits of value
are written into
the domain of self
.
Panics
This method is encouraged to panic if self
is empty, or wider than a
single element M
.