Added floating point formatting
+ Supports single and double precession formatting + Added Error handling from the formatting functions
This commit is contained in:
		
							parent
							
								
									9e5b0aafbd
								
							
						
					
					
						commit
						652682cb19
					
				| @ -1,8 +1,18 @@ | ||||
| use std::fmt::{Display, Formatter}; | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum ByteStreamError { | ||||
|     OutOfRange, | ||||
| } | ||||
| 
 | ||||
| impl Display for ByteStreamError { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             ByteStreamError::OutOfRange => write!(f, "Request values out of range") | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub const fn bit_mask(mask: u8) -> u8 { | ||||
|     match mask { | ||||
|         0 => 0x00, | ||||
|  | ||||
| @ -1,7 +1,30 @@ | ||||
| use crate::byte_stream::{ByteStream, bit_mask}; | ||||
| use crate::byte_stream::{ByteStream, bit_mask, ByteStreamError}; | ||||
| use serde::Deserialize; | ||||
| use std::fmt::Write; | ||||
| use std::fmt::{Write, Display, Formatter}; | ||||
| use num_bigint::{BigUint, BigInt}; | ||||
| use std::io::Cursor; | ||||
| use byteorder::{BigEndian, ReadBytesExt}; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum FormatError { | ||||
|     ByteSteamError(ByteStreamError), | ||||
|     NotSupported | ||||
| } | ||||
| 
 | ||||
| impl From<ByteStreamError> for FormatError { | ||||
|     fn from(e: ByteStreamError) -> Self { | ||||
|         FormatError::ByteSteamError(e) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for FormatError { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             FormatError::ByteSteamError(e) => writeln!(f, "Byte steam error: {}", e), | ||||
|             FormatError::NotSupported => write!(f, "Field type not supported") | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Deserialize, Clone)] | ||||
| #[serde(tag = "type")] | ||||
| @ -10,6 +33,10 @@ pub enum FieldType { | ||||
|     UInt { bit_width: usize }, | ||||
|     /// Unsigned Int
 | ||||
|     Int { bit_width: usize }, | ||||
|     /// Single Precession Float
 | ||||
|     Float, | ||||
|     /// Double Precession Float
 | ||||
|     Double, | ||||
|     /// Null Terminated String Field
 | ||||
|     String { max_len: usize }, | ||||
|     /// Fixed Byte Length Field
 | ||||
| @ -25,8 +52,8 @@ pub struct Field { | ||||
| } | ||||
| 
 | ||||
| impl Field { | ||||
|     fn format_int(byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize) -> (String, usize) { | ||||
|         let mut bytes = byte_stream.get_bytes(bit_ndx, bit_width).unwrap(); | ||||
|     fn format_int(byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize) -> Result<(String, usize), FormatError> { | ||||
|         let mut bytes = byte_stream.get_bytes(bit_ndx, bit_width)?; | ||||
| 
 | ||||
|         if let Some(last_byte) = bytes.last_mut() { | ||||
|             let last_bit = ((bit_width - 1) % 8) as u8; | ||||
| @ -39,25 +66,41 @@ impl Field { | ||||
| 
 | ||||
|             let big_int = BigInt::from_signed_bytes_be(&bytes); | ||||
| 
 | ||||
|             (big_int.to_string(), bit_width) | ||||
|             Ok((big_int.to_string(), bit_width)) | ||||
|         } | ||||
|         else { | ||||
|             ("".to_string(), bit_width) | ||||
|             Err(ByteStreamError::OutOfRange.into()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn format_uint(byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize) -> (String, usize) { | ||||
|         let bytes = byte_stream.get_bytes(bit_ndx, bit_width).unwrap(); | ||||
|     fn format_uint(byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize) -> Result<(String, usize), FormatError> { | ||||
|         let bytes = byte_stream.get_bytes(bit_ndx, bit_width)?; | ||||
| 
 | ||||
|         let big_int = BigUint::from_bytes_be(&bytes); | ||||
|         (big_int.to_string(), bit_width) | ||||
|         Ok((big_int.to_string(), bit_width)) | ||||
|     } | ||||
| 
 | ||||
|     fn format_data(&self, byte_stream: &ByteStream, bit_ndx: usize) -> (String, usize) { | ||||
|     fn format_float(byte_stream: &ByteStream, bit_ndx: usize) -> Result<(String, usize), FormatError> { | ||||
|         let bytes = byte_stream.get_bytes(bit_ndx, 32)?; | ||||
|         let mut cursor = Cursor::new(bytes); | ||||
| 
 | ||||
|         Ok((cursor.read_f32::<BigEndian>().unwrap().to_string(), 4)) | ||||
|     } | ||||
| 
 | ||||
|     fn format_double(byte_stream: &ByteStream, bit_ndx: usize) -> Result<(String, usize), FormatError> { | ||||
|         let bytes = byte_stream.get_bytes(bit_ndx, 64)?; | ||||
|         let mut cursor = Cursor::new(bytes); | ||||
| 
 | ||||
|         Ok((cursor.read_f64::<BigEndian>().unwrap().to_string(), 4)) | ||||
|     } | ||||
| 
 | ||||
|     fn format_data(&self, byte_stream: &ByteStream, bit_ndx: usize) -> Result<(String, usize), FormatError> { | ||||
|         match self.field_type { | ||||
|             FieldType::UInt { bit_width } => Self::format_uint(byte_stream, bit_ndx, bit_width), | ||||
|             FieldType::Int { bit_width } => Self::format_int(byte_stream, bit_ndx, bit_width), | ||||
|             _ => ("".to_string(), 0), | ||||
|             FieldType::Float => Self::format_float(byte_stream, bit_ndx), | ||||
|             FieldType::Double => Self::format_double(byte_stream, bit_ndx), | ||||
|             _ => Err(FormatError::NotSupported), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -71,18 +114,18 @@ pub struct Format { | ||||
| } | ||||
| 
 | ||||
| impl Format { | ||||
|     pub fn format_data(&self, data: &[u8]) -> String { | ||||
|         let mut s = String::new(); | ||||
|     pub fn format_data(&self, data: &[u8]) -> Result<String, FormatError> { | ||||
|         let mut format_str = String::new(); | ||||
|         let byte_stream = ByteStream::from(data); | ||||
|         let mut bit_ndx: usize = 0; | ||||
| 
 | ||||
|         for field in &self.fields { | ||||
|             let (data_str, bit_width) = field.format_data(&byte_stream, bit_ndx); | ||||
|             let (data_str, bit_width) = field.format_data(&byte_stream, bit_ndx)?; | ||||
|             bit_ndx += bit_width; | ||||
|             writeln!(s, "{}: {}", field.name, data_str).unwrap(); | ||||
|             writeln!(format_str, "{}: {}", field.name, data_str).unwrap(); | ||||
|         } | ||||
| 
 | ||||
|         s | ||||
|         Ok(format_str) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -101,8 +144,8 @@ mod tests { | ||||
|             byte_vec.push((-i) as u8); | ||||
| 
 | ||||
|             let byte_steam = ByteStream::from(byte_vec); | ||||
|             let (pos_output, _) = field.format_data(&byte_steam, 0); | ||||
|             let (neg_output, _) = field.format_data(&byte_steam, 8); | ||||
|             let (pos_output, _) = field.format_data(&byte_steam, 0).unwrap(); | ||||
|             let (neg_output, _) = field.format_data(&byte_steam, 8).unwrap(); | ||||
| 
 | ||||
|             assert_eq!(pos_output, i.to_string()); | ||||
|             assert_eq!(neg_output, (-i).to_string()); | ||||
| @ -113,7 +156,7 @@ mod tests { | ||||
|     fn test_format_int_5_bits() { | ||||
|         let field = Field {field_type: FieldType::Int {bit_width: 5,}, name: "test".to_string()}; | ||||
|         let byte_steam = ByteStream::from(vec![0x1B]); | ||||
|         let (output, _) = field.format_data(&byte_steam, 0); | ||||
|         let (output, _) = field.format_data(&byte_steam, 0).unwrap(); | ||||
| 
 | ||||
|         assert_eq!(output, "-5") | ||||
|     } | ||||
| @ -124,7 +167,7 @@ mod tests { | ||||
| 
 | ||||
| 
 | ||||
|         let byte_steam = ByteStream::from(vec![0xA5, 0xFC]); | ||||
|         let (output, _) = field.format_data(&byte_steam, 0); | ||||
|         let (output, _) = field.format_data(&byte_steam, 0).unwrap(); | ||||
| 
 | ||||
|         assert_eq!(output, "-23044") | ||||
|     } | ||||
| @ -135,8 +178,37 @@ mod tests { | ||||
| 
 | ||||
| 
 | ||||
|         let byte_steam = ByteStream::from(vec![0x50, 0xCA,  0x0F]); | ||||
|         let (output, _) = field.format_data(&byte_steam, 4); | ||||
|         let (output, _) = field.format_data(&byte_steam, 4).unwrap(); | ||||
| 
 | ||||
|         assert_eq!(output, "-23044") | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_format_float() { | ||||
|         let field = Field {field_type: FieldType::Float, name: "test".to_string()}; | ||||
| 
 | ||||
|         let byte_steam = ByteStream::from(b"\xc3\xd2\x58\x52".to_vec()); | ||||
|         let (output, _) = field.format_data(&byte_steam, 0).unwrap(); | ||||
| 
 | ||||
|         assert_eq!(output, "-420.69") | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_format_double() { | ||||
|         let field = Field {field_type: FieldType::Double, name: "test".to_string()}; | ||||
| 
 | ||||
|         let byte_steam = ByteStream::from(b"\xC0\x7A\x4B\x0A\x3D\x70\xA3\xD7".to_vec()); | ||||
|         let (output, _) = field.format_data(&byte_steam, 0).unwrap(); | ||||
| 
 | ||||
|         assert_eq!(output, "-420.69") | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_format_float_err() { | ||||
|         let field = Field {field_type: FieldType::Double, name: "test".to_string()}; | ||||
| 
 | ||||
|         let byte_steam = ByteStream::from(b"\x3D\x70\xA3\xD7".to_vec()); | ||||
| 
 | ||||
|         assert!(field.format_data(&byte_steam, 0).is_err()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -33,5 +33,8 @@ fn main() { | ||||
| 
 | ||||
|     let data = parse_bytes_from_input_arg(args.data).unwrap(); | ||||
| 
 | ||||
|     println!("{}", format.format_data(&data)); | ||||
|     match format.format_data(&data) { | ||||
|         Ok(data_str) => println!("{}", data_str), | ||||
|         Err(e) => println!("Unable to format data: {}", e) | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user