Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
# C-Style Bit-Field Access
This trait describes data transfer between a [`BitSlice`] region and an ordinary
integer. It is not intended for use by any other types than the data structures
in this crate.
The methods in this trait always operate on the `bitslice.len()` least
significant bits of an integer, and ignore any remaining high bits. When
loading, any excess high bits not copied out of a bit-slice are cleared to zero.
## Usage
The trait methods all panic if called on a bit-slice that is wider than the
integer type being transferred. As such, the first step is generally to subslice
a larger data structure into exactly the region used for storage, with
`bits[start .. end]`. Then, call the desired method on the narrowed bit-slice.
## Target-Specific Behavior
If you do not care about the details of the memory layout of stored values, you
can use the [`.load()`] and [`.store()`] unadorned methods. These each forward
to their `_le` variant on little-endian targets, and their `_be` variant on
big-endian. These will provide a reasonable default behavior, but do not
guarantee a stable memory layout, and their buffers are not suitable for
de/serialization.
If you require a stable memory layout, you will need to choose a `BitSlice`
with a fixed `O: BitOrder` type parameter (not `LocalBits`), and use a fixed
method suffix (`_le` or `_be`). You should *probably* also use `u8` as your
`T: BitStore` parameter, in order to avoid any byte-ordering issues. `bitvec`
never interferes with processor concepts of wide-integer layout, and always
relies on the target machines behavior for this work.
## Element- and Bit- Ordering Combinations
Remember: the `_le` and `_be` method suffixes are completely independent of the
`Lsb0` and `Msb0` types! `_le` and `_be` refer to the order in which successive
memory elements are considered to gain numerical significance, while `BitOrder`
refers only to the order of successive bits in *one* memory element.
The `BitField` and `BitOrder` traits 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 exchange an integer value
with the segment of the element that its governing `BitSlice` considers live.
Only when a `BitSlice` covers multiple elements does the distinction come into
play.
The `_le` methods consider numerical significance to start low and increase with
increasing memory address, while the `_be` methods consider numerical
significance to start high and *decrease* with increasing memory address. This
distinction affects the order in which memory elements are used to load or store
segments of the exchanged integer value.
Each trait method has detailed visual diagrams in its documentation.
Additionally, each *implementation*s documentation has diagrams that show what
the governed bit-sections of elements are! Be sure to check each, or to run the
demonstration with `cargo run --example bitfield`.
## Bitfield Value Types
When interacting with a bit-slice as a C-style bitfield, it can *only* store the
signed or unsigned integer types. No other type is permitted, as the
implementation relies on the 2s-complement significance behavior of processor
integers. Record types and floating-point numbers do not have this property, and
thus have no sensible default protocol for truncation and un/marshalling that
`bitvec` can use.
If you have such a protocol, you may implement it yourself by providing a
de/serialization transform between your type and the integers. For instance, a
numerically-correct protocol to store floating-point numbers in bitfields might
look like this:
```rust
use bitvec::mem::bits_of;
use funty::Floating;
fn to_storage<F>(num: F, width: usize) -> F::Raw
where F: Floating {
num.to_bits() >> (bits_of::<F>() - width)
}
fn from_storage<F>(val: F::Raw, width: usize) -> F
where F: Floating {
F::from_bits(val << (bits_of::<F>() - width))
}
```
This implements truncation in the least-significant bits, where floating-point
numbers store disposable bits in the mantissa, rather than in the
most-significant bits which contain the sign, exponent, and most significant
portion of the mantissa.
[`BitSlice`]: crate::slice::BitSlice
[`.load()`]: Self::load
[`.store()`]: Self::store
+15
View File
@@ -0,0 +1,15 @@
# `Lsb0` Bit-Field Behavior
`BitField` has no requirements about the in-memory representation or layout of
stored integers within a bit-slice, only that round-tripping an integer through
a store and a load of the same element suffix on the same bit-slice is
idempotent (with respect to sign truncation).
`Lsb0` provides a contiguous translation from bit-index to real memory: for any
given bit index `n` and its position `P(n)`, `P(n + 1)` is `P(n) + 1`. This
allows it to provide batched behavior: since the section of contiguous indices
used within an element translates to a section of contiguous bits in real
memory, the transaction is always a single shift/mask operation.
Each implemented method contains documentation and examples showing exactly how
the abstract integer space is mapped to real memory.
@@ -0,0 +1,77 @@
# `Lsb0` Big-Endian Integer Loading
This implementation uses the `Lsb0` bit-ordering to determine *which* bits in a
partially-occupied memory element contain the contents of an integer to be
loaded, using big-endian element ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Signed-Integer Loading
As described in the trait definition, when loading as a signed integer, the most
significant bit *loaded* from memory is sign-extended to the full width of the
returned type. In this method, that means that the most-significant bit of the
first element.
## Examples
In each memory element, the `Lsb0` ordering counts indices leftward from the
right edge:
```rust
use bitvec::prelude::*;
let raw = 0b00_10110_0u8;
// 76 54321 0
// ^ sign bit
assert_eq!(
raw.view_bits::<Lsb0>()
[1 .. 6]
.load_be::<u8>(),
0b000_10110,
);
assert_eq!(
raw.view_bits::<Lsb0>()
[1 .. 6]
.load_be::<i8>(),
0b111_10110u8 as i8,
);
```
In bit-slices that span multiple elements, the big-endian element ordering means
that the slice index increases while numeric significance decreases:
```rust
use bitvec::prelude::*;
let raw = [
0b0010_1111u8,
// ^ sign bit
// 7 0
0x0_1u8,
// 15 8
0xF_8u8,
// 23 16
];
assert_eq!(
raw.view_bits::<Lsb0>()
[4 .. 20]
.load_be::<u16>(),
0x2018u16,
);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and load functions.
[orig]: crate::field::BitField::load_le
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
@@ -0,0 +1,77 @@
# `Lsb0` Little-Endian Integer Loading
This implementation uses the `Lsb0` bit-ordering to determine *which* bits in a
partially-occupied memory element contain the contents of an integer to be
loaded, using little-endian element ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Signed-Integer Loading
As described in the trait definition, when loading as a signed integer, the most
significant bit *loaded* from memory is sign-extended to the full width of the
returned type. In this method, that means the most-significant loaded bit of the
final element.
## Examples
In each memory element, the `Lsb0` ordering counts indices leftward from the
right edge:
```rust
use bitvec::prelude::*;
let raw = 0b00_10110_0u8;
// 76 54321 0
// ^ sign bit
assert_eq!(
raw.view_bits::<Lsb0>()
[1 .. 6]
.load_le::<u8>(),
0b000_10110,
);
assert_eq!(
raw.view_bits::<Lsb0>()
[1 .. 6]
.load_le::<i8>(),
0b111_10110u8 as i8,
);
```
In bit-slices that span multiple elements, the little-endian element ordering
means that the slice index increases with numerical significance:
```rust
use bitvec::prelude::*;
let raw = [
0x8_Fu8,
// 7 0
0x0_1u8,
// 15 8
0b1111_0010u8,
// ^ sign bit
// 23 16
];
assert_eq!(
raw.view_bits::<Lsb0>()
[4 .. 20]
.load_le::<u16>(),
0x2018u16,
);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and load functions.
[orig]: crate::field::BitField::load_le
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
@@ -0,0 +1,69 @@
# `Lsb0` Big-Endian Integer Storing
This implementation uses the `Lsb0` bit-ordering to determine *which* bits in a
partially-occupied memory element are used for storage, using big-endian element
ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Narrowing Behavior
Integers are truncated from the high end. When storing into a bit-slice of
length `n`, the `n` least numerically significant bits are stored, and any
remaining high bits are ignored.
Be aware of this behavior if you are storing signed integers! The signed integer
`-14i8` (bit pattern `0b1111_0010u8`) will, when stored into and loaded back
from a 4-bit slice, become the value `2i8`.
## Examples
```rust
use bitvec::prelude::*;
let mut raw = 0u8;
raw.view_bits_mut::<Lsb0>()
[1 .. 6]
.store_be(22u8);
assert_eq!(raw, 0b00_10110_0);
// 76 54321 0
raw.view_bits_mut::<Lsb0>()
[1 .. 6]
.store_be(-10i8);
assert_eq!(raw, 0b00_10110_0);
```
In bit-slices that span multiple elements, the big-endian element ordering means
that the slice index increases while numerical significance decreases:
```rust
use bitvec::prelude::*;
let mut raw = [!0u8; 3];
raw.view_bits_mut::<Lsb0>()
[4 .. 20]
.store_be(0x2018u16);
assert_eq!(raw, [
0x2_F,
// 7 0
0x0_1,
// 15 8
0xF_8,
// 23 16
]);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and store functions.
[orig]: crate::field::BitField::store_be
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
@@ -0,0 +1,69 @@
# `Lsb0` Little-Endian Integer Storing
This implementation uses the `Lsb0` bit-ordering to determine *which* bits in a
partially-occupied memory element are used for storage, using little-endian
element ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Narrowing Behavior
Integers are truncated from the high end. When storing into a bit-slice of
length `n`, the `n` least numerically significant bits are stored, and any
remaining high bits are ignored.
Be aware of this behavior if you are storing signed integers! The signed integer
`-14i8` (bit pattern `0b1111_0010u8`) will, when stored into and loaded back
from a 4-bit slice, become the value `2i8`.
## Examples
```rust
use bitvec::prelude::*;
let mut raw = 0u8;
raw.view_bits_mut::<Lsb0>()
[1 .. 6]
.store_le(22u8);
assert_eq!(raw, 0b00_10110_0);
// 76 54321 0
raw.view_bits_mut::<Lsb0>()
[1 .. 6]
.store_le(-10i8);
assert_eq!(raw, 0b00_10110_0);
```
In bit-slices that span multiple elements, the little-endian element ordering
means that the slice index increases with numerical significance:
```rust
use bitvec::prelude::*;
let mut raw = [!0u8; 3];
raw.view_bits_mut::<Lsb0>()
[4 .. 20]
.store_le(0x2018u16);
assert_eq!(raw, [
0x8_F,
// 7 0
0x0_1,
// 15 8
0xF_2,
// 23 16
]);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and store functions.
[orig]: crate::field::BitField::store_le
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
+23
View File
@@ -0,0 +1,23 @@
# `Msb0` Bit-Field Behavior
`BitField` has no requirements about the in-memory representation or layout of
stored integers within a bit-slice, only that round-tripping an integer through
a store and a load of the same element suffix on the same bit-slice is
idempotent (with respect to sign truncation).
`Msb0` provides a contiguous translation from bit-index to real memory: for any
given bit index `n` and its position `P(n)`, `P(n + 1)` is `P(n) - 1`. This
allows it to provide batched behavior: since the section of contiguous indices
used within an element translates to a section of contiguous bits in real
memory, the transaction is always a single shift-mask operation.
Each implemented method contains documentation and examples showing exactly how
the abstract integer space is mapped to real memory.
## Notes
In particular, note that while `Msb0` indexes bits from the most significant
down to the least, and integers index from the least up to the most, this
**does not** reörder any bits of the integer value! This ordering only finds a
region in real memory; it does *not* affect the partial-integer contents stored
in that region.
@@ -0,0 +1,77 @@
# `Msb0` Big-Endian Integer Loading
This implementation uses the `Msb0` bit-ordering to determine *which* bits in a
partially-occupied memory element contain the contents of an integer to be
loaded, using big-endian element ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Signed-Integer Loading
As described in the trait definition, when loading as a signed integer, the most
significant bit *loaded* from memory is sign-extended to the full width of the
returned type. In this method, that means the most-significant loaded bit of the
first element.
## Examples
In each memory element, the `Msb0` ordering counts indices rightward from the
left edge:
```rust
use bitvec::prelude::*;
let raw = 0b00_10110_0u8;
// 01 23456 7
// ^ sign bit
assert_eq!(
raw.view_bits::<Msb0>()
[2 .. 7]
.load_be::<u8>(),
0b000_10110,
);
assert_eq!(
raw.view_bits::<Msb0>()
[2 .. 7]
.load_be::<i8>(),
0b111_10110u8 as i8,
);
```
In bit-slices that span multiple elements, the big-endian element ordering means
that the slice index increases with numerical significance:
```rust
use bitvec::prelude::*;
let raw = [
0b1111_0010u8,
// ^ sign bit
// 0 7
0x0_1u8,
// 8 15
0x8_Fu8,
// 16 23
];
assert_eq!(
raw.view_bits::<Msb0>()
[4 .. 20]
.load_be::<u16>(),
0x2018u16,
);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and load functions.
[orig]: crate::field::BitField::load_le
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
@@ -0,0 +1,77 @@
# `Msb0` Little-Endian Integer Loading
This implementation uses the `Msb0` bit-ordering to determine *which* bits in a
partially-occupied memory element contain the contents of an integer to be
loaded, using little-endian element ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Signed-Integer Loading
As described in the trait definition, when loading as a signed integer, the most
significant bit *loaded* from memory is sign-extended to the full width of the
returned type. In this method, that means the most-significant loaded bit of the
final element.
## Examples
In each memory element, the `Msb0` ordering counts indices rightward from the
left edge:
```rust
use bitvec::prelude::*;
let raw = 0b00_10110_0u8;
// 01 23456 7
// ^ sign bit
assert_eq!(
raw.view_bits::<Msb0>()
[2 .. 7]
.load_le::<u8>(),
0b000_10110,
);
assert_eq!(
raw.view_bits::<Msb0>()
[2 .. 7]
.load_le::<i8>(),
0b111_10110u8 as i8,
);
```
In bit-slices that span multiple elements, the little-endian element ordering
means that the slice index increases with numerical significance:
```rust
use bitvec::prelude::*;
let raw = [
0xF_8u8,
// 0 7
0x0_1u8,
// 8 15
0b0010_1111u8,
// ^ sign bit
// 16 23
];
assert_eq!(
raw.view_bits::<Msb0>()
[4 .. 20]
.load_le::<u16>(),
0x2018u16,
);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and load functions.
[orig]: crate::field::BitField::load_le
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
@@ -0,0 +1,69 @@
# `Msb0` Big-Endian Integer Storing
This implementation uses the `Msb0` bit-ordering to determine *which* bits in a
partially-occupied memory element are used for storage, using big-endian element
ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Narrowing Behavior
Integers are truncated from the high end. When storing into a bit-slice of
length `n`, the `n` least numerically significant bits are stored, and any
remaining high bits are ignored.
Be aware of this behavior if you are storing signed integers! The signed integer
`-14i8` (bit pattern `0b1111_0010u8`) will, when stored into and loaded back
from a 4-bit slice, become the value `2i8`.
## Examples
```rust
use bitvec::prelude::*;
let mut raw = 0u8;
raw.view_bits_mut::<Msb0>()
[2 .. 7]
.store_be(22u8);
assert_eq!(raw, 0b00_10110_0);
// 01 23456 7
raw.view_bits_mut::<Msb0>()
[2 .. 7]
.store_be(-10i8);
assert_eq!(raw, 0b00_10110_0);
```
In bit-slices that span multiple elements, the big-endian element ordering means
that the slice index increases while numerical significance decreases:
```rust
use bitvec::prelude::*;
let mut raw = [!0u8; 3];
raw.view_bits_mut::<Msb0>()
[4 .. 20]
.store_be(0x2018u16);
assert_eq!(raw, [
0xF_2,
// 0 7
0x0_1,
// 8 15
0x8_F,
// 16 23
]);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and store functions.
[orig]: crate::field::BitField::store_be
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
@@ -0,0 +1,69 @@
# `Msb0` Little-Endian Integer Storing
This implementation uses the `Msb0` bit-ordering to determine *which* bits in a
partially-occupied memory element are used for storage, using little-endian
element ordering.
See the [trait method definition][orig] for an overview of what element ordering
means.
## Narrowing Behavior
Integers are truncated from the high end. When storing into a bit-slice of
length `n`, the `n` least numerically significant bits are stored, and any
remaining high bits are ignored.
Be aware of this behavior if you are storing signed integers! The signed integer
`-14i8` (bit pattern `0b1111_0010u8`) will, when stored into and loaded back
from a 4-bit slice, become the value `2i8`.
## Examples
```rust
use bitvec::prelude::*;
let mut raw = 0u8;
raw.view_bits_mut::<Msb0>()
[2 .. 7]
.store_le(22u8);
assert_eq!(raw, 0b00_10110_0);
// 01 23456 7
raw.view_bits_mut::<Msb0>()
[2 .. 7]
.store_le(-10i8);
assert_eq!(raw, 0b00_10110_0);
```
In bit-slices that span multiple elements, the little-endian element ordering
means that the slice index increases with numerical significance:
```rust
use bitvec::prelude::*;
let mut raw = [!0u8; 3];
raw.view_bits_mut::<Msb0>()
[4 .. 20]
.store_le(0x2018u16);
assert_eq!(raw, [
0xF_8,
// 0 7
0x0_1,
// 8 15
0x2_F,
// 16 23
]);
```
Note that while these examples use `u8` storage for convenience in displaying
the literals, `BitField` operates identically with *any* storage type. As most
machines use little-endian *byte ordering* within wider element types, and
`bitvec` exclusively operates on *elements*, the actual bytes of memory may
rapidly start to behave oddly when translating between numeric literals and
in-memory representation.
The [user guide] has a chapter that translates bit indices into memory positions
for each combination of `<T: BitStore, O: BitOrder>`, and may be of additional
use when choosing a combination of type parameters and store functions.
[orig]: crate::field::BitField::store_le
[user guide]: https://bitvecto-rs.github.io/bitvec/memory-layout
+58
View File
@@ -0,0 +1,58 @@
# Integer Loading
This method reads the contents of a bit-slice region as an integer. The region
may be shorter than the destination integer type, in which case the loaded value
will be zero-extended (when `I: Unsigned`) or sign-extended from the most
significant loaded bit (when `I: Signed`).
The region may not be zero bits, nor wider than the destination type. Attempting
to load a `u32` from a bit-slice of length 33 will panic the program.
## Operation and Endianness Handling
Each element in the bit-slice contains a segment of the value to be loaded. If
the bit-slice contains more than one element, then the numerical significance of
each loaded segment is interpreted according to the targets endianness:
- little-endian targets consider each *`T` element* to have increasing numerical
significance, starting with the least-significant segment at the low address
and ending with the most-significant segment at the high address.
- big-endian targets consider each *`T` element* to have decreasing numerical
significance, starting with the most-significant segment at the high address
and ending with the least-significant segment at the low address.
See the documentation for [`.load_le()`] and [`.load_be()`] for more detail on
what this means for how the in-memory representation of bit-slices translates to
loaded values.
You must always use the loading method that exactly corresponds to the storing
method previously used to insert data into the bit-slice: same suffix on the
method name (none, `_le`, `_be`) and same integer type. `bitvec` is not required
to, and will not, guarantee round-trip consistency if you change any of these
parameters.
## Type Parameters
- `I`: The integer type being loaded. This can be any of the signed or unsigned
integers.
## Parameters
- `&self`: A bit-slice region whose length is in the range `1 ..= I::BITS`.
## Returns
The contents of the bit-slice, interpreted as an integer.
## Panics
This panics if `self.len()` is 0, or greater than `I::BITS`.
## Examples
This method is inherently non-portable, and changes behavior depending on the
target characteristics. If your target is little-endian, see [`.load_le()`]; if
your target is big-endian, see [`.load_be()`].
[`.load_be()`]: Self::load_be
[`.load_le()`]: Self::load_le
@@ -0,0 +1,145 @@
# Big-Endian Integer Loading
This method loads an integer value from a bit-slice, using big-endian
significance ordering when the bit-slice spans more than one `T` element in
memory.
Big-endian significance ordering means that if a bit-slice occupies an array
`[A, B, C]`, then the bits stored in `A` are considered to be the most
significant segment of the loaded integer, then `B` contains the middle segment,
then `C` contains the least significant segment.
The segments are combined in order, that is, as the raw bit-pattern
`0b<padding><A><B><C>`. If the destination type is signed, the loaded value is
sign-extended according to the most-significant bit in the `A` segment.
It is important to note that the `O: BitOrder` parameter of the bit-slice from
which the value is loaded **does not** affect the bit-pattern of the stored
segments. They are always stored exactly as they exist in an ordinary integer.
The ordering parameter only affects *which* bits in an element are available for
storage.
## Type Parameters
- `I`: The integer type being loaded. This can be any of the signed or unsigned
integers.
## Parameters
- `&self`: A bit-slice region whose length is in the range `1 ..= I::BITS`.
## Returns
The contents of the bit-slice, interpreted as an integer.
## Panics
This panics if `self.len()` is 0, or greater than `I::BITS`.
## Examples
Let us consider an `i32` value stored in 24 bits of a `BitSlice<u8, Lsb0>`:
```rust
use bitvec::prelude::*;
let mut raw = [0u8; 4];
let bits = raw.view_bits_mut::<Lsb0>();
let integer = 0x00__B4_96_3Cu32 as i32;
bits[4 .. 28].store_be::<i32>(integer);
let loaded = bits[4 .. 28].load_be::<i32>();
assert_eq!(loaded, 0xFF__B4_96_3Cu32 as i32);
```
Observe that, because the lowest 24 bits began with the pattern `0b1101…`, the
value was considered to be negative when interpreted as an `i24` and was
sign-extended through the highest byte.
Let us now look at the memory representation of this value:
```rust
# use bitvec::prelude::*;
# let mut raw = [0u8; 4];
# let bits = raw.view_bits_mut::<Lsb0>();
# bits[4 .. 28].store_be::<u32>(0x00B4963Cu32);
assert_eq!(raw, [
0b1011_0000,
// 0xB dead
0b0100_1001,
// 0x4 0x9
0b0110_0011,
// 0x6 0x3
0b0000_1100,
// dead 0xC
]);
```
Notice how while the `Lsb0` bit-ordering means that indexing within the
bit-slice proceeds right-to-left in each element, the actual bit-patterns stored
in memory are not affected. Element `[0]` is more numerically significant than
element `[1]`, but bit `[4]` is not more numerically significant than bit `[5]`.
In the sequence `B496`, `B` is the most significant, and so it gets placed
lowest in memory. `49` fits in one byte, and is stored directly as written.
Lastly, `6` is the least significant nibble of the four, and is placed highest
in memory.
Now lets look at the way different `BitOrder` parameters interpret the
placement of bit indices within memory:
```rust
use bitvec::prelude::*;
let raw = [
// Bit index 14 ←
// Lsb0: ─┤
0b0100_0000_0000_0011u16,
// Msb0: ├─
// → 14
// Bit index ← 19 16
// Lsb0: ├──┤
0b0001_0000_0000_1110u16,
// Msb0: ├──┤
// 16 19 →
];
assert_eq!(
raw.view_bits::<Lsb0>()
[14 .. 20]
.load_be::<u8>(),
0b00_01_1110,
);
assert_eq!(
raw.view_bits::<Msb0>()
[14 .. 20]
.load_be::<u8>(),
0b00_11_0001,
);
```
Notice how the bit-orderings change which *parts* of the memory are loaded, but
in both cases the segment in `raw[0]` is more significant than the segment in
`raw[1]`, and the ordering of bits *within* each segment are unaffected by the
bit-ordering.
## Notes
Be sure to see the documentation for
[`<BitSlice<_, Lsb0> as BitField>::load_be`][llb] and
[`<BitSlice<_, Msb0> as Bitfield>::load_be`][mlb] for more detailed information
on the memory views!
You can view the mask of all *storage regions* of a bit-slice by using its
[`.domain()`] method to view the breakdown of its memory region, then print the
[`.mask()`] of any [`PartialElement`] the domain contains. Whole elements are
always used in their entirety. You should use the `domain` modules types
whenever you are uncertain of the exact locations in memory that a particular
bit-slice governs.
[llb]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.load_be-3
[mlb]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.load_be-4
[`PartialElement`]: crate::domain::PartialElement
[`.domain()`]: crate::slice::BitSlice::domain
[`.mask()`]: crate::domain::PartialElement::mask
@@ -0,0 +1,145 @@
# Little-Endian Integer Loading
This method loads an integer value from a bit-slice, using little-endian
significance ordering when the bit-slice spans more than one `T` element in
memory.
Little-endian significance ordering means that if a bit-slice occupies an array
`[A, B, C]`, then the bits stored in `A` are considered to contain the least
significant segment of the loaded integer, then `B` contains the middle segment,
and then `C` contains the most significant segment.
The segments are combined in order, that is, as the raw bit-pattern
`0b<padding><C><B><A>`. If the destination type is signed, the loaded value is
sign-extended according to the most-significant bit in the `C` segment.
It is important to note that the `O: BitOrder` parameter of the bit-slice from
which the value is loaded **does not** affect the bit-pattern of the stored
segments. They are always stored exactly as they exist in an ordinary integer.
The ordering parameter only affects *which* bits in an element are available for
storage.
## Type Parameters
- `I`: The integer type being loaded. This can be any of the signed or unsigned
integers.
## Parameters
- `&self`: A bit-slice region whose length is in the range `1 ..= I::BITS`.
## Returns
The contents of the bit-slice, interpreted as an integer.
## Panics
This panics if `self.len()` is 0, or greater than `I::BITS`.
## Examples
Let us consider an `i32` value stored in 24 bits of a `BitSlice<u8, Msb0>`:
```rust
use bitvec::prelude::*;
let mut raw = [0u8; 4];
let bits = raw.view_bits_mut::<Msb0>();
let integer = 0x00__B4_96_3Cu32 as i32;
bits[4 .. 28].store_le::<i32>(integer);
let loaded = bits[4 .. 28].load_le::<i32>();
assert_eq!(loaded, 0xFF__B4_96_3Cu32 as i32);
```
Observe that, because the lowest 24 bits began with the pattern `0b1101…`, the
value was considered to be negative when interpreted as an `i24` and was
sign-extended through the highest byte.
Let us now look at the memory representation of this value:
```rust
# use bitvec::prelude::*;
# let mut raw = [0u8; 4];
# let bits = raw.view_bits_mut::<Msb0>();
# bits[4 .. 28].store_le::<u32>(0x00B4963Cu32);
assert_eq!(raw, [
0b0000_1100,
// dead 0xC
0b0110_0011,
// 0x6 0x3
0b0100_1001,
// 0x4 0x9
0b1011_0000,
// 0xB dead
]);
```
Notice how while the `Msb0` bit-ordering means that indexing within the
bit-slice proceeds left-to-right in each element, and the bit-patterns in each
element proceed left-to-right in the aggregate and the decomposed literals, the
ordering of the elements is reversed from how the literal was written.
In the sequence `B496`, `B` is the most significant, and so it gets placed
highest in memory. `49` fits in one byte, and is stored directly as written.
Lastly, `6` is the least significant nibble of the four, and is placed lowest
in memory.
Now lets look at the way different `BitOrder` parameters interpret the
placement of bit indices within memory:
```rust
use bitvec::prelude::*;
let raw = [
// Bit index 14 ←
// Lsb0: ─┤
0b0100_0000_0000_0011u16,
// Msb0: ├─
// → 14
// Bit index ← 19 16
// Lsb0: ├──┤
0b0001_0000_0000_1110u16,
// Msb0: ├──┤
// 16 19 →
];
assert_eq!(
raw.view_bits::<Lsb0>()
[14 .. 20]
.load_le::<u8>(),
0b00_1110_01,
);
assert_eq!(
raw.view_bits::<Msb0>()
[14 .. 20]
.load_le::<u8>(),
0b00_0001_11,
);
```
Notice how the bit-orderings change which *parts* of the memory are loaded, but
in both cases the segment in `raw[0]` is less significant than the segment in
`raw[1]`, and the ordering of bits *within* each segment are unaffected by the
bit-ordering.
## Notes
Be sure to see the documentation for
[`<BitSlice<_, Lsb0> as BitField>::load_le`][lll] and
[`<BitSlice<_, Msb0> as Bitfield>::load_le`][mll] for more detailed information
on the memory views!
You can view the mask of all *storage regions* of a bit-slice by using its
[`.domain()`] method to view the breakdown of its memory region, then print the
[`.mask()`] of any [`PartialElement`] the domain contains. Whole elements are
always used in their entirety. You should use the `domain` modules types
whenever you are uncertain of the exact locations in memory that a particular
bit-slice governs.
[lll]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.load_le-3
[mll]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.load_le-4
[`PartialElement`]: crate::domain::PartialElement
[`.domain()`]: crate::slice::BitSlice::domain
[`.mask()`]: crate::domain::PartialElement::mask
+57
View File
@@ -0,0 +1,57 @@
# Integer Storing
This method writes an integer into the contents of a bit-slice region. The
region may be shorter than the source integer type, in which case the stored
value will be truncated. On load, it may be zero-extended (unsigned destination)
or sign-extended from the most significant **stored** bit (signed destination).
The region may not be zero bits, nor wider than the source type. Attempting
to store a `u32` into a bit-slice of length 33 will panic the program.
## Operation and Endianness Handling
The value to be stored is broken into segments according to the elements of the
bit-slice receiving it. If the bit-slice contains more than one element, then
the numerical significance of each segment routes to a storage element according
to the targets endianness:
- little-endian targets consider each *`T` element* to have increasing numerical
significance, starting with the least-significant segment at the low address
and ending with the most-significant segment at the high address.
- big-endian targets consider each *`T` element* to have decreasing numerical
significance, starting with the most-significant segment at the high address
and ending with the least-significant segment at the low address.
See the documentation for [`.store_le()`] and [`.store_be()`] for more detail on
what this means for how the in-memory representation of bit-slices translates to
stored values.
You must always use the loading method that exactly corresponds to the storing
method previously used to insert data into the bit-slice: same suffix on the
method name (none, `_le`, `_be`) and same integer type. `bitvec` is not required
to, and will not, guarantee round-trip consistency if you change any of these
parameters.
## Type Parameters
- `I`: The integer type being stored. This can be any of the signed or unsigned
integers.
## Parameters
- `&self`: A bit-slice region whose length is in the range `1 ..= I::BITS`.
- `value`: An integer value whose `self.len()` least numerically significant
bits will be written into `self`.
## Panics
This panics if `self.len()` is 0, or greater than `I::BITS`.
## Examples
This method is inherently non-portable, and changes behavior depending on the
target characteristics. If your target is little-endian, see [`.store_le()`]; if
your target is big-endian, see [`.store_be()`].
[`.store_be()`]: Self::store_be
[`.store_le()`]: Self::store_le
@@ -0,0 +1,143 @@
# Big-Endian Integer Storing
This method stores an integer value into a bit-slice, using big-endian
significance ordering when the bit-slice spans more than one `T` element in
memory.
Big-endian significance ordering means that if a bit-slice occupies an array
`[A, B, C]`, then the bits stored in `A` are considered to contain the most
significant segment of the stored integer, then `B` contains the middle segment,
and then `C` contains the least significant segment.
An integer is broken into segments in order, that is, the raw bit-pattern is
fractured into `0b<padding><A><B><C>`. High bits beyond the length of the
bit-slice into which the integer is stored are truncated.
It is important to note that the `O: BitOrder` parameter of the bit-slice into
which the value is stored **does not** affect the bit-pattern of the stored
segments. They are always stored exactly as they exist in an ordinary integer.
The ordering parameter only affects *which* bits in an element are available for
storage.
## Type Parameters
- `I`: The integer type being stored. This can be any of the signed or unsigned
integers.
## Parameters
- `&mut self`: A bit-slice region whose length is in the range `1 ..= I::BITS`.
- `value`: An integer value whose `self.len()` least numerically significant
bits will be written into `self`.
## Panics
This panics if `self.len()` is 0, or greater than `I::BITS`.
## Examples
Let us consider an `i32` value stored in 24 bits of a `BitSlice<u8, Lsb0>`:
```rust
use bitvec::prelude::*;
let mut raw = [0u8; 4];
let bits = raw.view_bits_mut::<Lsb0>();
let integer = 0x00__B4_96_3Cu32 as i32;
bits[4 .. 28].store_be::<i32>(integer);
let loaded = bits[4 .. 28].load_be::<i32>();
assert_eq!(loaded, 0xFF__B4_96_3Cu32 as i32);
```
Observe that, because the lowest 24 bits began with the pattern `0b1101…`, the
value was considered to be negative when interpreted as an `i24` and was
sign-extended through the highest byte.
Let us now look at the memory representation of this value:
```rust
# use bitvec::prelude::*;
# let mut raw = [0u8; 4];
# let bits = raw.view_bits_mut::<Lsb0>();
# bits[4 .. 28].store_be::<u32>(0x00B4963Cu32);
assert_eq!(raw, [
0b1011_0000,
// 0xB dead
0b0100_1001,
// 0x4 0x9
0b0110_0011,
// 0x6 0x3
0b0000_1100,
// dead 0xC
]);
```
Notice how while the `Lsb0` bit-ordering means that indexing within the
bit-slice proceeds right-to-left in each element, the actual bit-patterns stored
in memory are not affected. Element `[0]` is more numerically significant than
element `[1]`, but bit `[4]` is not more numerically significant than bit `[5]`.
In the sequence `B496`, `B` is the most significant, and so it gets placed
lowest in memory. `49` fits in one byte, and is stored directly as written.
Lastly, `6` is the least significant nibble of the four, and is placed highest
in memory.
Now lets look at the way different `BitOrder` parameters interpret the
placement of bit indices within memory:
```rust
use bitvec::prelude::*;
let raw = [
// Bit index 14 ←
// Lsb0: ─┤
0b0100_0000_0000_0011u16,
// Msb0: ├─
// → 14
// Bit index ← 19 16
// Lsb0: ├──┤
0b0001_0000_0000_1110u16,
// Msb0: ├──┤
// 16 19 →
];
assert_eq!(
raw.view_bits::<Lsb0>()
[14 .. 20]
.load_be::<u8>(),
0b00_01_1110,
);
assert_eq!(
raw.view_bits::<Msb0>()
[14 .. 20]
.load_be::<u8>(),
0b00_11_0001,
);
```
Notice how the bit-orderings change which *parts* of the memory are loaded, but
in both cases the segment in `raw[0]` is more significant than the segment in
`raw[1]`, and the ordering of bits *within* each segment are unaffected by the
bit-ordering.
## Notes
Be sure to see the documentation for
[`<BitSlice<_, Lsb0> as BitField>::store_be`][lsb] and
[`<BitSlice<_, Msb0> as Bitfield>::store_be`][msb] for more detailed information
on the memory views!
You can view the mask of all *storage regions* of a bit-slice by using its
[`.domain()`] method to view the breakdown of its memory region, then print the
[`.mask()`] of any [`PartialElement`] the domain contains. Whole elements are
always used in their entirety. You should use the `domain` modules types
whenever you are uncertain of the exact locations in memory that a particular
bit-slice governs.
[lsb]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.store_be-3
[msb]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.store_be-4
[`PartialElement`]: crate::domain::PartialElement
[`.domain()`]: crate::slice::BitSlice::domain
[`.mask()`]: crate::domain::PartialElement::mask
@@ -0,0 +1,143 @@
# Little-Endian Integer Storing
This method stores an integer value into a bit-slice, using little-endian
significance ordering when the bit-slice spans more than one `T` element in
memory.
Little-endian significance ordering means that if a bit-slice occupies an array
`[A, B, C]`, then the bits stored in `A` are considered to contain the least
significant segment of the stored integer, then `B` contains the middle segment,
and then `C` contains the most significant segment.
An integer is broken into segments in order, that is, the raw bit-pattern is
fractured into `0b<padding><C><B><A>`. High bits beyond the length of the
bit-slice into which the integer is stored are truncated.
It is important to note that the `O: BitOrder` parameter of the bit-slice into
which the value is stored **does not** affect the bit-pattern of the stored
segments. They are always stored exactly as they exist in an ordinary integer.
The ordering parameter only affects *which* bits in an element are available for
storage.
## Type Parameters
- `I`: The integer type being stored. This can be any of the signed or unsigned
integers.
## Parameters
- `&mut self`: A bit-slice region whose length is in the range `1 ..= I::BITS`.
- `value`: An integer value whose `self.len()` least numerically significant
bits will be written into `self`.
## Panics
This panics if `self.len()` is 0, or greater than `I::BITS`.
## Examples
Let us consider an `i32` value stored in 24 bits of a `BitSlice<u8, Msb0>`:
```rust
use bitvec::prelude::*;
let mut raw = [0u8; 4];
let bits = raw.view_bits_mut::<Msb0>();
let integer = 0x00__B4_96_3Cu32 as i32;
bits[4 .. 28].store_le::<i32>(integer);
let loaded = bits[4 .. 28].load_le::<i32>();
assert_eq!(loaded, 0xFF__B4_96_3Cu32 as i32);
```
Observe that, because the lowest 24 bits began with the pattern `0b1101…`, the
value was considered to be negative when interpreted as an `i24` and was
sign-extended through the highest byte.
Let us now look at the memory representation of this value:
```rust
# use bitvec::prelude::*;
# let mut raw = [0u8; 4];
# let bits = raw.view_bits_mut::<Msb0>();
# bits[4 .. 28].store_le::<u32>(0x00B4963Cu32);
assert_eq!(raw, [
0b0000_1100,
// dead 0xC
0b0110_0011,
// 0x6 0x3
0b0100_1001,
// 0x4 0x9
0b1011_0000,
// 0xB dead
]);
```
Notice how while the `Msb0` bit-ordering means that indexing within the
bit-slice proceeds left-to-right in each element, and the bit-patterns in each
element proceed left-to-right in the aggregate and the decomposed literals, the
ordering of the elements is reversed from how the literal was written.
In the sequence `B496`, `B` is the most significant, and so it gets placed
highest in memory. `49` fits in one byte, and is stored directly as written.
Lastly, `6` is the least significant nibble of the four, and is placed lowest
in memory.
Now lets look at the way different `BitOrder` parameters interpret the
placement of bit indices within memory:
```rust
use bitvec::prelude::*;
let raw = [
// Bit index 14 ←
// Lsb0: ─┤
0b0100_0000_0000_0011u16,
// Msb0: ├─
// → 14
// Bit index ← 19 16
// Lsb0: ├──┤
0b0001_0000_0000_1110u16,
// Msb0: ├──┤
// 16 19 →
];
assert_eq!(
raw.view_bits::<Lsb0>()
[14 .. 20]
.load_le::<u8>(),
0b00_1110_01,
);
assert_eq!(
raw.view_bits::<Msb0>()
[14 .. 20]
.load_le::<u8>(),
0b00_0001_11,
);
```
Notice how the bit-orderings change which *parts* of the memory are loaded, but
in both cases the segment in `raw[0]` is less significant than the segment in
`raw[1]`, and the ordering of bits *within* each segment are unaffected by the
bit-ordering.
## Notes
Be sure to see the documentation for
[`<BitSlice<_, Lsb0> as BitField>::store_le`][lsl] and
[`<BitSlice<_, Msb0> as Bitfield>::store_le`][msl] for more detailed information
on the memory views!
You can view the mask of all *storage regions* of a bit-slice by using its
[`.domain()`] method to view the breakdown of its memory region, then print the
[`.mask()`] of any [`PartialElement`] the domain contains. Whole elements are
always used in their entirety. You should use the `domain` modules types
whenever you are uncertain of the exact locations in memory that a particular
bit-slice governs.
[lsl]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.store_le-3
[msl]: https://docs.rs/bitvec/latest/bitvec/field/trait.BitField.html#method.store_le-4
[`PartialElement`]: crate::domain::PartialElement
[`.domain()`]: crate::slice::BitSlice::domain
[`.mask()`]: crate::domain::PartialElement::mask
+26
View File
@@ -0,0 +1,26 @@
# Partial-Element Getter
This function extracts a portion of an integer value from a [`PartialElement`].
The `BitField` implementations call it as they assemble a complete integer. It
performs the following steps:
1. the `PartialElement` is loaded (and masked to discard unused bits),
1. the loaded value is then shifted to abut the LSedge of the stack local,
1. and then `resize`d into a `U` value.
## Type Parameters
- `O` and `T` are the type parameters of the `PartialElement` argument.
- `U` is the destination integer type.
## Parameters
- `elem`: A `PartialElement` containing a value segment.
- `shamt`: The distance by which to right-shift the value loaded from `elem` so
that it abuts the LSedge.
## Returns
The segment of an integer stored in `elem`.
[`PartialElement`]: crate::domain::PartialElement
@@ -0,0 +1,9 @@
# Bit-Array Implementation of `BitField`
The `BitArray` implementation is only ever called when the entire bit-array is
available for use, which means it can skip the bit-slice memory detection and
instead use the underlying storage elements directly.
The implementation still performs the segmentation for each element contained in
the array, in order to maintain value consistency so that viewing the array as a
bit-slice is still able to correctly interact with data contained in it.
+10
View File
@@ -0,0 +1,10 @@
# Bit-Field I/O Protocols
This module defines the standard-library `io::{Read, Write}` byte-oriented
protocols on `bitvec` structures that are capable of operating on bytes through
the `BitField` trait.
Note that calling [`BitField`] methods in a loop imposes a non-trivial, and
irremovable, performance penalty on each invocation. The `.read()` and
`.write()` methods implemented in this module are going to suffer this cost, and
you should prefer to operate directly on the underlying buffer if possible.
@@ -0,0 +1,20 @@
# Reading From a Bit-Slice
The implementation loads bytes out of the referenced bit-slice until either the
destination buffer is filled or the source has no more bytes to provide. When
`.read()` returns, the provided bit-slice handle will have been updated to no
longer include the leading segment copied out as bytes into `buf`.
Note that the return value of `.read()` is always the number of *bytes* of `buf`
filled!
The implementation uses [`BitField::load_be`] to collect bytes. Note that unlike
the standard library, it is implemented on bit-slices of *any* underlying
element type. However, using a `BitSlice<_, u8>` is still likely to be fastest.
## Original
[`impl Read for [u8]`][orig]
[orig]: https://doc.rust-lang.org/std/primitive.slice.html#impl-Read
[`BitField::load_be`]: crate::field::BitField::load_be
+14
View File
@@ -0,0 +1,14 @@
# Reading From a Bit-Vector
The implementation loads bytes out of the reference bit-vector until either the
destination buffer is filled or the source has no more bytes to provide. When
`.read()` returns, the provided bit-vector will have its contents shifted down
so that it begins at the first bit *after* the last byte copied out into `buf`.
Note that the return value of `.read()` is always the number of *bytes* of `buf`
filled!
## API Differences
The standard library does not `impl Read for Vec<u8>`. It is provided here as a
courtesy.
@@ -0,0 +1,20 @@
# Writing Into a Bit-Slice
The implementation stores bytes into the referenced bit-slice until either the
source buffer is exhausted or the destination has no more slots to fill. When
`.write()` returns, the provided bit-slice handle will have been updated to no
longer include the leading segment filled with bytes from `buf`.
Note that the return value of `.write()` is always the number of *bytes* of
`buf` consumed!
The implementation uses [`BitField::store_be`] to fill bytes. Note that unlike
the standard library, it is implemented on bit-slices of *any* underlying
element type. However, using a `BitSlice<_, u8>` is still likely to be fastest.
## Original
[`impl Write for [u8]`][orig]
[orig]: https://doc.rust-lang.org/std/primitive.slice.html#impl-Write
[`BitField::store_be`]: crate::field::BitField::store_be
@@ -0,0 +1,18 @@
# Writing Into a Bit-Vector
The implementation appends bytes to the referenced bit-vector until the source
buffer is exhausted.
Note that the return value of `.write()` is always the number of *bytes* of
`buf` consumed!
The implementation uses [`BitField::store_be`] to fill bytes. Note that unlike
the standard library, it is implemented on bit-vectors of *any* underlying
element type. However, using a `BitVec<_, u8>` is still likely to be fastest.
## Original
[`impl Write for Vec<u8>`][orig]
[orig]: https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-Write
[`BitField::store_be`]: crate::field::BitField::store_be
+18
View File
@@ -0,0 +1,18 @@
# Value Resizing
This zero-extends or truncates a source value to fit into a target type.
## Type Parameters
- `T`: The initial integer type of the value being resized.
- `U`: The destination type of the value after resizing.
## Parameters
- `value`: Any (unsigned) integer.
## Returns
`value`, either zero-extended in the most-significant bits (if `U` is wider than
`T`) or truncated retaining the least-significant bits (if `U` is narrower than
`T`).
+25
View File
@@ -0,0 +1,25 @@
# Partial-Element Setter
This function inserts a portion of an integer value into a [`PartialElement`].
The `BitField` implementations call it as they disassemble a complete integer.
It performs the following steps:
1. the value is `resize`d into a `T::Mem`,
1. shifted up from LSedge as needed to fit in the governed region of the partial
element,
1. and then stored (after masking away excess bits) through the `PartialElement`
into memory.
## Type Parameters
- `O` and `T` are the type parameters of the `PartialElement` argument.
- `U` is the source integer type.
## Parameters
- `elem`: A `PartialElement` into which a value segment will be written.
- `value`: A value, whose least-significant bits will be written into `elem`.
- `shamt`: The shift distance from the storage locations LSedge to its live
bits.
[`PartialElement`]: crate::domain::PartialElement
+30
View File
@@ -0,0 +1,30 @@
# Sign Extension
When a bit-slice loads a value whose destination type is wider than the
bit-slice itself, and the destination type is a signed integer, the loaded value
must be sign-extended. The load accumulator always begins as the zero pattern,
and the loaders do not attempt to detect a sign bit before they begin.
As such, this function takes a value loaded out of a bit-slice, which has been
zero-extended from the storage length to the destination type, and the length of
the bit-slice that contained it. If the destination type is unsigned, then the
value is returned as-is; if the destination type is signed, then the value is
sign-extended according to the bit at `1 << (width - 1)`.
## Type Parameters
- `I`: The integer type of the loaded element. When this is one of
`u{8,16,32,64,size}`, no sign extension takes place.
## Parameters
- `elem`: The value loaded out of a bit-slice.
- `width`: The width in bits of the source bit-slice. This is always known to be
in the domain `1 ..= I::BITS`.
## Returns
A correctly-signed copy of `elem`. Unsigned integers, and signed integers whose
most significant loaded bit was `0`, are untouched. Signed integers whose most
significant loaded bit was `1` have their remaining high bits set to `1` for
sign extension.