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.
#![allow(unused)] fn main() { use bit_byte_bit::{Bits, bits_as, Field, Scheme}; 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)); }