From 3274386ccf735e71df9525a06974a7f173d03d10 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 19 Jun 2022 14:08:37 -0600 Subject: [PATCH] Added support for layered formats + Formats can include sub-formats of previously defined formats + This search is done post config building so any format in the global config can be used + Clippy + fmt --- README.md | 2 + formats/example.toml | 18 ++++- src/formatter/format.rs | 148 ++++++++++++++++++++++++++++++++-------- src/formatter/mod.rs | 4 +- src/main.rs | 10 +-- 5 files changed, 147 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 0b38617..11de4bf 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ Members: * `Bytes`: Collection of bytes with no termination * `max_len`: max number of bytes * `endianess`: byte ordering of the field +* `Format`: Allows formats to include other formats + * `format_name`: Format definition to use #### Example Config [Example](./formats/example.toml) diff --git a/formats/example.toml b/formats/example.toml index ad5df86..9512433 100644 --- a/formats/example.toml +++ b/formats/example.toml @@ -48,4 +48,20 @@ field_type = {type = "String", endianness = "BigEndian", max_len = 55} # byte field [[formats.fields]] name = "bytes field" -field_type = {type = "Bytes", endianness = "BigEndian", max_len = 55} \ No newline at end of file +field_type = {type = "Bytes", endianness = "BigEndian", max_len = 5} + +# Example of layer formats +[[formats]] +name = "example_layer" +bit_flip = false + +# Example sub-format +[[formats.fields]] +name = "example sub-format" +field_type = {type = "Format", format_name = "example"} + +# UInt after subfield +[[formats.fields]] +name = "uint field" +print_type = {print = "Base", base=16} +field_type = {type = "UInt", bit_width = 16, endianness = "LittleEndian"} diff --git a/src/formatter/format.rs b/src/formatter/format.rs index bedd8ab..04452b4 100644 --- a/src/formatter/format.rs +++ b/src/formatter/format.rs @@ -8,6 +8,7 @@ use serde::Deserialize; use crate::byte_stream::{bit_mask, ByteStream, ByteStreamError}; use crate::formatter::printers::PrintType; +use crate::FormatConfig; pub trait ByteOrderOperations: ByteOrder { fn last_byte(buf: &mut Vec) -> Option<&mut u8>; @@ -109,6 +110,7 @@ pub enum FormatError { #[allow(dead_code)] NotSupported, StringParseError(FromUtf8Error), + FormatNotFound(String), } impl From for FormatError { @@ -129,6 +131,9 @@ impl Display for FormatError { FormatError::ByteSteamError(e) => writeln!(f, "Byte stream error: {}", e), FormatError::NotSupported => write!(f, "Field type not supported"), FormatError::StringParseError(e) => write!(f, "String parse error: {}", e), + FormatError::FormatNotFound(format) => { + write!(f, "Unable to find sub-format: {}", format) + } } } } @@ -160,6 +165,8 @@ pub enum FieldType { max_len: usize, endianness: Endianness, }, + /// Insert a predefine format here + Format { format_name: String }, } #[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq, Copy)] @@ -298,6 +305,7 @@ impl Field { &self, byte_stream: &mut ByteStream, bit_ndx: usize, + config: &FormatConfig, ) -> Result<(String, usize), FormatError> { let global_bit_flip = byte_stream.get_reverse_bits(); @@ -305,16 +313,16 @@ impl Field { byte_stream.set_reverse_bits(bit_flip); } - let fmt = match self.field_type { + let fmt = match &self.field_type { FieldType::UInt { bit_width, endianness, } => match endianness { Endianness::LittleEndian => { - self.format_uint::(byte_stream, bit_ndx, bit_width) + self.format_uint::(byte_stream, bit_ndx, *bit_width) } Endianness::BigEndian => { - self.format_uint::(byte_stream, bit_ndx, bit_width) + self.format_uint::(byte_stream, bit_ndx, *bit_width) } }, FieldType::Int { @@ -322,10 +330,10 @@ impl Field { endianness, } => match endianness { Endianness::LittleEndian => { - self.format_int::(byte_stream, bit_ndx, bit_width) + self.format_int::(byte_stream, bit_ndx, *bit_width) } Endianness::BigEndian => { - self.format_int::(byte_stream, bit_ndx, bit_width) + self.format_int::(byte_stream, bit_ndx, *bit_width) } }, FieldType::Float { endianness } => match endianness { @@ -343,10 +351,10 @@ impl Field { endianness, } => match endianness { Endianness::LittleEndian => { - self.format_string::(byte_stream, bit_ndx, max_len) + self.format_string::(byte_stream, bit_ndx, *max_len) } Endianness::BigEndian => { - self.format_string::(byte_stream, bit_ndx, max_len) + self.format_string::(byte_stream, bit_ndx, *max_len) } }, FieldType::Bytes { @@ -354,12 +362,22 @@ impl Field { endianness, } => match endianness { Endianness::LittleEndian => { - self.format_bytes::(byte_stream, bit_ndx, max_len) + self.format_bytes::(byte_stream, bit_ndx, *max_len) } Endianness::BigEndian => { - self.format_bytes::(byte_stream, bit_ndx, max_len) + self.format_bytes::(byte_stream, bit_ndx, *max_len) } }, + FieldType::Format { format_name } => { + let format_config = config.get_format(format_name).unwrap(); + + let (mut format_str, post_bit_ndx) = format_config + .format_byte_stream(byte_stream, bit_ndx, config) + .map_err(|_| FormatError::FormatNotFound(format_name.to_string()))?; + + format_str.insert(0, '\n'); + Ok((format_str, post_bit_ndx - bit_ndx)) + } }?; byte_stream.set_reverse_bits(global_bit_flip); @@ -379,15 +397,18 @@ pub struct Format { } impl Format { - pub fn format_data(&self, data: &[u8]) -> Result { + pub fn format_byte_stream( + &self, + byte_stream: &mut ByteStream, + mut bit_ndx: usize, + config: &FormatConfig, + ) -> Result<(String, usize), FormatError> { let mut format_str = String::new(); - let mut byte_stream = ByteStream::from(data); - let mut bit_ndx: usize = 0; - + let old_reverse = byte_stream.get_reverse_bits(); byte_stream.set_reverse_bits(self.bit_flip); for field in &self.fields { - match field.format_data(&mut byte_stream, bit_ndx) { + match field.format_data(byte_stream, bit_ndx, config) { Ok((data_str, bit_width)) => { bit_ndx += bit_width; writeln!(format_str, "{}: {}", field.name, data_str).unwrap(); @@ -402,6 +423,16 @@ impl Format { } } + byte_stream.set_reverse_bits(old_reverse); + + Ok((format_str, bit_ndx)) + } + + pub fn format_data(&self, data: &[u8], config: &FormatConfig) -> Result { + let mut byte_stream = ByteStream::from(data); + + let (format_str, _) = self.format_byte_stream(&mut byte_stream, 0, config)?; + Ok(format_str) } } @@ -410,6 +441,7 @@ impl Format { mod tests { use crate::byte_stream::ByteStream; use crate::formatter::format::{Endianness, Field, FieldType}; + use crate::{Format, FormatConfig}; #[test] fn test_format_int_4_bits() { @@ -429,8 +461,12 @@ mod tests { byte_vec.push((-i) as u8); let mut byte_stream = ByteStream::from(byte_vec); - let (pos_output, width1) = field.format_data(&mut byte_stream, 4).unwrap(); - let (neg_output, width2) = field.format_data(&mut byte_stream, 12).unwrap(); + let (pos_output, width1) = field + .format_data(&mut byte_stream, 4, &FormatConfig::default()) + .unwrap(); + let (neg_output, width2) = field + .format_data(&mut byte_stream, 12, &FormatConfig::default()) + .unwrap(); assert_eq!(width1, 4); assert_eq!(width2, 4); @@ -452,7 +488,9 @@ mod tests { print_type: Default::default(), }; let mut byte_stream = ByteStream::from(vec![0x1B]); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 5); assert_eq!(output, "-5") @@ -471,7 +509,9 @@ mod tests { }; let mut byte_stream = ByteStream::from(vec![0xFC, 0xA5]); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 16); assert_eq!(output, "-23044") @@ -490,7 +530,9 @@ mod tests { }; let mut byte_stream = ByteStream::from(vec![0x0C, 0xF5, 0xA0]); - let (output, width) = field.format_data(&mut byte_stream, 4).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 4, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 16); assert_eq!(output, "-23044") @@ -508,7 +550,9 @@ mod tests { }; let mut byte_stream = ByteStream::from(b"\x52\x58\xd2\xc3".to_vec()); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 32); assert_eq!(output, "-420.69") @@ -526,7 +570,9 @@ mod tests { }; let mut byte_stream = ByteStream::from(b"\xD7\xA3\x70\x3D\x0A\x4B\x7A\xC0".to_vec()); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 64); assert_eq!(output, "-420.69") @@ -545,7 +591,9 @@ mod tests { let mut byte_stream = ByteStream::from(b"\x3D\x70\xA3\xD7".to_vec()); - assert!(field.format_data(&mut byte_stream, 0).is_err()) + assert!(field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .is_err()) } #[test] @@ -566,7 +614,9 @@ mod tests { let mut byte_stream = ByteStream::from(bytes); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, (test_string.len() + 1) * 8); //extra byte to account for the '\0' char assert_eq!(output, test_string) @@ -586,7 +636,9 @@ mod tests { let mut byte_stream = ByteStream::from(vec![0xDE, 0xAD, 0xBE, 0xEF]); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 16); assert_eq!(output, "[222, 173]") @@ -606,7 +658,9 @@ mod tests { let mut byte_stream = ByteStream::from(vec![0xDE, 0xAD]); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 16); assert_eq!(output, "[222, 173]") @@ -627,7 +681,9 @@ mod tests { let src_str = b"Test\x00abcdefg"; let mut byte_stream = ByteStream::from(src_str.to_vec()); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 40); assert_eq!(output, "Test") @@ -648,9 +704,47 @@ mod tests { let src_str = b"Test\x00abcdefg"; let mut byte_stream = ByteStream::from(src_str.to_vec()); - let (output, width) = field.format_data(&mut byte_stream, 0).unwrap(); + let (output, width) = field + .format_data(&mut byte_stream, 0, &FormatConfig::default()) + .unwrap(); assert_eq!(width, 40); assert_eq!(output, "Test") } + + #[test] + fn test_sub_field() { + let field = Field { + name: "test".to_string(), + field_type: FieldType::Format { + format_name: "sub_format".to_string(), + }, + print_type: Default::default(), + bit_flip: None, + }; + + let config = FormatConfig { + formats: vec![Format { + name: "sub_format".to_string(), + bit_flip: false, + fields: vec![Field { + name: "test".to_string(), + field_type: FieldType::String { + max_len: 25, + endianness: Endianness::LittleEndian, + }, + print_type: Default::default(), + bit_flip: None, + }], + }], + }; + + let src_str = b"Test\x00abcdefg"; + let mut byte_stream = ByteStream::from(src_str.to_vec()); + + let (output, width) = field.format_data(&mut byte_stream, 0, &config).unwrap(); + + assert_eq!(width, 40); + assert_eq!(output, "test: Test\n") + } } diff --git a/src/formatter/mod.rs b/src/formatter/mod.rs index 44c0f5e..9a3218f 100644 --- a/src/formatter/mod.rs +++ b/src/formatter/mod.rs @@ -286,7 +286,7 @@ mod test { let format = get_ccsds_format(); let data = ccsds_packet.to_bytes(); - let output = format.format_data(&data).unwrap(); + let output = format.format_data(&data, &FormatConfig::default()).unwrap(); assert_eq!(ccsds_packet.print(), output) } @@ -308,7 +308,7 @@ mod test { }; let data = ccsds_packet.to_bytes(); - let output = format.format_data(&data).unwrap(); + let output = format.format_data(&data, &FormatConfig::default()).unwrap(); assert_eq!(ccsds_packet.print(), output) } diff --git a/src/main.rs b/src/main.rs index 038c7a7..eecd296 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,7 +55,7 @@ pub struct Args { data: Vec, } -fn init() -> Result<(Vec, Format), FormatyError> { +fn init() -> Result<(Vec, Format, FormatConfig), FormatyError> { let args: Args = Args::from_args(); let config = FormatConfig::new(&args.config, &args.global_config)?; @@ -70,19 +70,19 @@ fn init() -> Result<(Vec, Format), FormatyError> { args.input_type.parse_arg_input(args.data, args.base)? }; - Ok((data, format)) + Ok((data, format, config)) } fn main() { - let (data, format) = match init() { - Ok((data, format)) => (data, format), + let (data, format, config) = match init() { + Ok((data, format, config)) => (data, format, config), Err(e) => { println!("Error initializing: {}", e); return; } }; - match format.format_data(&data) { + match format.format_data(&data, &config) { Ok(data) => println!("{}", data), Err(_) => print!("Unable to parse data"), }