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 + fmtmain
parent
f2cec4c89e
commit
3274386ccf
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
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"}
|
||||
|
|
|
@ -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<u8>) -> Option<&mut u8>;
|
||||
|
@ -109,6 +110,7 @@ pub enum FormatError {
|
|||
#[allow(dead_code)]
|
||||
NotSupported,
|
||||
StringParseError(FromUtf8Error),
|
||||
FormatNotFound(String),
|
||||
}
|
||||
|
||||
impl From<ByteStreamError> 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::<LittleEndian>(byte_stream, bit_ndx, bit_width)
|
||||
self.format_uint::<LittleEndian>(byte_stream, bit_ndx, *bit_width)
|
||||
}
|
||||
Endianness::BigEndian => {
|
||||
self.format_uint::<BigEndian>(byte_stream, bit_ndx, bit_width)
|
||||
self.format_uint::<BigEndian>(byte_stream, bit_ndx, *bit_width)
|
||||
}
|
||||
},
|
||||
FieldType::Int {
|
||||
|
@ -322,10 +330,10 @@ impl Field {
|
|||
endianness,
|
||||
} => match endianness {
|
||||
Endianness::LittleEndian => {
|
||||
self.format_int::<LittleEndian>(byte_stream, bit_ndx, bit_width)
|
||||
self.format_int::<LittleEndian>(byte_stream, bit_ndx, *bit_width)
|
||||
}
|
||||
Endianness::BigEndian => {
|
||||
self.format_int::<BigEndian>(byte_stream, bit_ndx, bit_width)
|
||||
self.format_int::<BigEndian>(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::<LittleEndian>(byte_stream, bit_ndx, max_len)
|
||||
self.format_string::<LittleEndian>(byte_stream, bit_ndx, *max_len)
|
||||
}
|
||||
Endianness::BigEndian => {
|
||||
self.format_string::<LittleEndian>(byte_stream, bit_ndx, max_len)
|
||||
self.format_string::<LittleEndian>(byte_stream, bit_ndx, *max_len)
|
||||
}
|
||||
},
|
||||
FieldType::Bytes {
|
||||
|
@ -354,12 +362,22 @@ impl Field {
|
|||
endianness,
|
||||
} => match endianness {
|
||||
Endianness::LittleEndian => {
|
||||
self.format_bytes::<LittleEndian>(byte_stream, bit_ndx, max_len)
|
||||
self.format_bytes::<LittleEndian>(byte_stream, bit_ndx, *max_len)
|
||||
}
|
||||
Endianness::BigEndian => {
|
||||
self.format_bytes::<LittleEndian>(byte_stream, bit_ndx, max_len)
|
||||
self.format_bytes::<LittleEndian>(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<String, FormatError> {
|
||||
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<String, FormatError> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -55,7 +55,7 @@ pub struct Args {
|
|||
data: Vec<String>,
|
||||
}
|
||||
|
||||
fn init() -> Result<(Vec<u8>, Format), FormatyError> {
|
||||
fn init() -> Result<(Vec<u8>, 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<u8>, 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"),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue