Expand description
An n-bit string represented as ⌈ n/8 ⌉ bytes.
§Instantiation
Constructors defined in the Bits implementation generate bit strings
with a length that is either input-defined, or in the case of Bits::new,
8 times the length of the iterator.
Constructors defined by the From or
FromIterator traits generate bit strings with a length
based on the input. If a collection of bool, the length will be equal to
that of the input. If the input is a collection of u8, the length counts
all bits up to and including the most significant one bit.
let bits = Bits::new([0x0A, 0x0B, 0x0C]);
assert_eq!(bits.len(), 24);
let bits_no_lz = Bits::from([0x0A, 0x0B, 0x0C]);
assert_eq!(bits_no_lz.len(), 20);
let aligned_bits = Bits::aligned(16, [0x0A, 0x0B, 0x0C]);
assert_eq!(aligned_bits.len(), 32);
let packed_bits = Bits::packed([0x0A, 0x0B, 0x0C]);
assert_eq!(packed_bits, Bits::from([0xBA, 0x0C]));
let bools = Bits::from([true, false, true, false, false, true]);
assert_eq!(bools, Bits::slice(&[0x25], 6));
let slice = Bits::take(&[0x0A, 0x0B, 0x0C], 3, 9);
assert_eq!(slice, Bits::from([0x61, 0x01]));The bits! macro is also provided for convenience, wrapping the constructors:
let bits = bits![0x0A, 0x0B, 0x0C];
assert_eq!(bits, Bits::new([0x0A, 0x0B, 0x0C]));
let repeated_bytes = bits![8; 0x0F; 20];
assert_eq!(repeated_bytes, Bits::new([0x0F; 20]));
let aligned_bits = bits![0x0A, 0x0B, 0x0C; => 16];
assert_eq!(aligned_bits.len(), 32);
let ones = bits![1; 20];
assert_eq!(ones, Bits::ones(20));
let packed_bits = bits![0x0A, 0x0B, 0x0C; %];
assert_eq!(packed_bits, Bits::from([0xBA, 0x0C]));
let zeros = bits![0; 20];
assert_eq!(zeros, Bits::zeros(20));
§Indexing
Bits::i can be used to access an individual bit. Bits can be set to one, reset to zero, or toggled.
let mut bits = Bits::new([0x0A, 0x0B, 0x0C]);
assert_eq!(bits.i(0), 0);
assert_eq!(bits.i(1), 1);
bits.set(0);
bits.reset(1);
assert_eq!(bits.i(0), 1);
assert_eq!(bits.i(1), 0);
bits.toggle(0);
bits.toggle(1);
assert_eq!(bits.i(0), 0);
assert_eq!(bits.i(1), 1);§Bitwise Operations
Bit strings support and, or, not, xor, left and right shifting, as well as, left, and right rotation.
let x = Bits::new([0x20, 0x30, 0x40]);
let y = Bits::new([0xA0, 0xB0, 0xC0]);
assert_eq!(x.and(&y), Bits::new([0x20, 0x30, 0x40]));
assert_eq!(x.complement(), Bits::new([0xDF, 0xCF, 0xBF]));
assert_eq!(x.or(&y), Bits::new([0xA0, 0xB0, 0xC0]));
assert_eq!(x ^ &y, Bits::new([0x80, 0x80, 0x80]));
let bits = Bits::from([0x0A, 0x0B, 0x0C]);
assert_eq!(bits.len(), 20);
assert_eq!(bits.shifted_left(17), Bits::slice(&[0x00, 0x00, 0x04], 20));
assert_eq!(bits.shifted_right(17), Bits::slice(&[0x06, 0x00, 0x00], 20));
assert_eq!(bits.rotated_left(4), Bits::slice(&[0xAC, 0xB0, 0x00], 20));
assert_eq!(bits.rotated_right(4), Bits::slice(&[0xB0, 0xC0, 0x0A], 20));§Iteration
Iteration can be done bit-by-bit, or byte-by-byte using:
- Bits::iter
- Bits::iter_from
- Bits::into_iter
- Bits::bytes (via
&[u8]::iter) - Bits::into_bytes
let x = Bits::new([0xAB, 0xCD, 0xEF]);
let mut ones = 0;
for bit in x.iter() { if bit == 1 { ones += 1; } }
assert_eq!(ones, 17);
ones = 0;
for bit in x.iter_from(13) { if bit == 1 { ones += 1; } }
assert_eq!(ones, 9);
let mut y = x.bytes().iter();
assert_eq!(y.next(), Some(&0xAB));
let bits = Bits::new([0xBA, 0xDC, 0xFE]);
let shorts = bits_as::vec_i16(&bits);
let mut shorts_iter = shorts.into_iter();
assert_eq!(shorts_iter.next(), Some(0xDCBAu16 as i16));
assert_eq!(shorts_iter.next(), Some(0xFFFEu16 as i16));
let ushorts = Vec::<u16>::from(bits);
let mut ushorts_iter = ushorts.into_iter();
assert_eq!(ushorts_iter.next(), Some(0xDCBA));
assert_eq!(ushorts_iter.next(), Some(0x00FE));§Bit Schemes
Scheme implements a simple bit string pattern matcher inspired by Erlang’s bit syntax. Schemes are used to give meaning to different regions of a bit string.
§Example
ipv4_header_scheme will define the part of the IPv4 datagram header that does not include the options.
This scheme will then be used to process more bits from the bit string. Scheme::split_* methods return a vector
of Bits corresponding to each field. Scheme::extract_from_* methods return a hashmap, corresponding each
field with a key.
const IPV4_HEADER_BIT_LEN: usize = 160;
const IPV4_HEADER_BYTE_LEN: usize = 20;
const IPV4_HEADER_KEYS: [&str; 13] = [
"Version",
"IHL",
"DSCP",
"ECN",
"Total Length",
"Identification",
"Flags",
"Fragment Offset",
"TTL",
"Protocol",
"Header Checksum",
"Source Address",
"Destination Address"
];
let ipv4_header_scheme: Scheme = Scheme::new([
Field::UNSIGNED_4, // Version
Field::UNSIGNED_4, // Internet Header Length
Field::unsigned(6), // Differentiated Services Code Point
Field::UNSIGNED_2, // Explicit Congestion Notification
Field::UNSIGNED_16, // Total length
Field::UNSIGNED_16, // Identification
Field::unsigned(3), // Flags
Field::unsigned(13), // Fragment Offset
Field::UNSIGNED_8, // Time To Live
Field::UNSIGNED_8, // Protocol
Field::UNSIGNED_16, // Header Checksum
Field::UNSIGNED_32, // Source Address
Field::UNSIGNED_32 // Destination Address
]);
let bits = Bits::new([
0x54, 0x00, 0x34, 0x00, 0x16, 0x41, 0x02, 0x00,
128, 6, 0, 0, 192, 168, 5, 45, 91, 198, 174, 192
]);
let mut data = ipv4_header_scheme.extract_from_bits(&bits, &IPV4_HEADER_KEYS);
let total_length = bits_as::unsigned(&data[&"Total Length"]);
let header_32_bit_len = bits_as::unsigned(&data[&"IHL"]);
let options_byte_len = (header_32_bit_len - 5) * 4;
let options_bit_len = options_byte_len * 8;
let options = Bits::take(bits.bytes(), IPV4_HEADER_BIT_LEN, options_bit_len);
let payload_start = IPV4_HEADER_BIT_LEN + options_bit_len;
let payload_bit_len = (total_length - IPV4_HEADER_BYTE_LEN - options_byte_len) * 8;
let payload = Bits::take(bits.bytes(), IPV4_HEADER_BIT_LEN + options_bit_len, payload_bit_len);
assert_eq!(bits_as::uint8(&data[&"Version"]), 4);
assert_eq!(bits_as::uint8(&data[&"IHL"]), 5);
assert_eq!(bits_as::uint8(&data[&"DSCP"]), 0);
assert_eq!(bits_as::uint8(&data[&"ECN"]), 0);
assert_eq!(bits_as::uint16(&data[&"Total Length"]), 52);
assert_eq!(bits_as::uint16(&data[&"Identification"]), 0x4116);
assert_eq!(bits_as::uint8(&data[&"Flags"]), 2);
assert_eq!(bits_as::uint16(&data[&"Fragment Offset"]), 0);
assert_eq!(bits_as::uint8(&data[&"TTL"]), 128);
assert_eq!(bits_as::uint8(&data[&"Protocol"]), 6);
assert_eq!(bits_as::uint16(&data[&"Header Checksum"]), 0);
assert_eq!(bits_as::vec_u8(&data[&"Source Address"]), vec![192, 168, 5, 45]);
assert_eq!(bits_as::vec_u8(&data[&"Destination Address"]), vec![91, 198, 174, 192]);
assert_eq!(options, Bits::empty());
assert_eq!(payload, Bits::zeros(8 * 32));