Very simple library for binary printer/parser (encoding/decoding). That is, this library allows you to write/read, by offset, individual bit sequences.
Example simple printer:
structSample{// offset: 0, bis_size: 6field1:u64,// offset: 6, bis_size: 32field2:u64,// offset: 38, bis_size: 4field3:u64,// offset: 42, bis_size: 64field4:u64,// offset: 108, bis_size: 6field5:u64,}#[derive(Debug)]structSamplePrinterError{field_name:String,value:u64,max_value:u64,}impl fmt::DisplayforSamplePrinterError{fnfmt(&self,f:&mut fmt::Formatter<'_>) -> fmt::Result{write!(
f,"Error: field '{}' has value {}, which exceeds the maximum value {}.",self.field_name,self.value,self.max_value
)}}implErrorforSamplePrinterError{}implTryInto<[u8;14]>forSample{typeError = Vec<&'staticstr>;fntry_into(self) -> Result<[u8;14],Self::Error>{/* CONVERT values to bytes for passing to the verification function */let b_field1 = self.field1.to_be_bytes();let b_field2 = self.field2.to_be_bytes();let b_field3 = self.field3.to_be_bytes();let b_field4 = self.field4.to_be_bytes();let b_field5 = self.field5.to_be_bytes();/* CONVERT END *//* CHECK that stored values do not go beyond the storage (there are enough bits for encoding) */letmut errors = vec![];if !is_in_range(6,&b_field1, b_field1.len()){
errors.push(SamplePrinterError{field_name:"field1".to_string(),value: field1,max_value:bits_to_max_hold(6)asu64,});}if !is_in_range(32,&b_field2, b_field2.len()){
errors.push(SamplePrinterError{field_name:"field2".to_string(),value: field2,max_value:bits_to_max_hold(32)asu64,});}if !is_in_range(4,&b_field3, b_field3.len()){
errors.push(SamplePrinterError{field_name:"field3".to_string(),value: field3,max_value:bits_to_max_hold(4)asu64,});}if !is_in_range(64,&b_field4, b_field4.len()){
errors.push(SamplePrinterError{field_name:"field4".to_string(),value: field4,max_value:bits_to_max_hold(64)asu64,});}if !is_in_range(6,&b_field5, b_field5.len()){
errors.push(SamplePrinterError{field_name:"field5".to_string(),value: field5,max_value:bits_to_max_hold(6)asu64,});}if !errors.is_empty(){returnErr(errors);}/* CHECK END *//* WRITE to a byte array */letmut target = [0u8;14];letmut offset = 0;bit_write(&mut target, offset,6,&b_field1, b_field1.len());
offset += 6;bit_write(&mut target, offset,32,&b_field2, b_field2.len());
offset += 32;bit_write(&mut target, offset,4,&b_field3, b_field3.len());
offset += 4;bit_write(&mut target, offset,64,&b_field4, b_field4.len());
offset += 64;bit_write(&mut target, offset,6,&b_field5, b_field5.len());/* WRITE END */Ok(target)}}Example simple parser:
structSample{// offset: 0, bis_size: 6field1:u64,// offset: 6, bis_size: 32field2:u64,// offset: 38, bis_size: 4field3:u64,// offset: 42, bis_size: 64field4:u64,// offset: 108, bis_size: 6field5:u64,}implTryFrom<[u8;14]>forSample{typeError = ();fntry_from(bytes:[u8;14]) -> Result<Self,Self::Error>{letmut offset = 0;letmut field1 = [0u8;8];let b_field1_len = field1.len();letmut field2 = [0u8;8];let b_field2_len = field2.len();letmut field3 = [0u8;8];let b_field3_len = field3.len();letmut field4 = [0u8;8];let b_field4_len = field4.len();letmut field5 = [0u8;8];let b_field5_len = field5.len();bit_read(&bytes, offset,6,&mut field1, field1_len);
offset += 6;bit_read(&bytes, offset,32,&mut field2, b_field2_len);
offset += 32;bit_read(&bytes, offset,4,&mut field3, b_field3_len);
offset += 4;bit_read(&bytes, offset,64,&mut field4, b_field4_len);
offset += 64;bit_read(&bytes, offset,6,&mut field5, b_field5_len);Ok(Sample{field1: u64::from_be_bytes(field1),field2: u64::from_be_bytes(field2),field3: u64::from_be_bytes(field3),field4: u64::from_be_bytes(field4),field5: u64::from_be_bytes(field5),})}}Interesting membitcpy function. This function uses offset for the source as well. In essence, this function can be view as bidirectional lens, since only with it can both a parser and a printer be implemented:
// lets parse somethingletmut target = [0u8;2];let source = u64::from_be_bytes([0b00000000,0b00000000,0b10011111,0b11100000,0b00000000,0b00000000,0b00000000,0b00000000,]);let b_source = source.to_be_bytes();let source_bit_offset = 16;membitcpy(&mut target,4,11,&b_source, source_bit_offset,);assert_eq!(target,[0b00001001,0b11111110]);// now lets print what we parseletmut new_target = [0u8;8];membitcpy(&mut new_target,8*2,11,&target,4,);// here we can see that our new target equivalent // our primary source assert_eq!(new_target, b_source);Similar libraries:
