Crate bit_byte_bit

Crate bit_byte_bit 

Source
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:

 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));

Modules§

bits_as

Macros§

bits
Macro implementing a subset of the Bits constructors

Structs§

Bits
Field
Defines a region of bits.
IntoBits
IntoBytes
Iter
Scheme
Defines a pattern giving meaning to different regions of a bit string.