Added default formatters + error handling

pull/1/head
Joey Hines 2022-04-09 12:34:15 -06:00
parent f8ba81e2ca
commit 59351fb699
No known key found for this signature in database
GPG Key ID: 80F567B5C968F91B
8 changed files with 337 additions and 21 deletions

132
Cargo.lock generated
View File

@ -34,12 +34,27 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.33.3"
@ -55,17 +70,46 @@ dependencies = [
"vec_map",
]
[[package]]
name = "cpufeatures"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
dependencies = [
"libc",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "formaty"
version = "0.1.0"
dependencies = [
"byteorder",
"num-bigint",
"rust-embed",
"serde",
"structopt",
"toml",
]
[[package]]
name = "generic-array"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "heck"
version = "0.3.3"
@ -126,6 +170,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@ -168,6 +218,49 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rust-embed"
version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40377bff8cceee81e28ddb73ac97f5c2856ce5522f0b260b763f434cdfae602"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad22c7226e4829104deab21df575e995bfbc4adfad13a595e387477f238c1aec"
dependencies = [
"sha2",
"walkdir",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "serde"
version = "1.0.130"
@ -188,6 +281,19 @@ dependencies = [
"syn",
]
[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer",
"cfg-if",
"cpufeatures",
"digest",
"opaque-debug",
]
[[package]]
name = "strsim"
version = "0.8.0"
@ -247,6 +353,12 @@ dependencies = [
"serde",
]
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
@ -277,6 +389,17 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "winapi"
version = "0.3.9"
@ -293,6 +416,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"

View File

@ -11,3 +11,4 @@ serde = { version = "1.0", features = ["derive"] }
toml = "0.5.8"
byteorder = "1.4.3"
num-bigint = "0.4"
rust-embed="6.3.0"

View File

@ -5,6 +5,7 @@
# Example Packet:
# [0xe0, 0xa1, 0xc0, 0x00, 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05]
# CCSDS packet w/ primary header + payload
[[formats]]
name = "ccsds"
bit_flip = false
@ -47,3 +48,51 @@ field_type = {type = "UInt", bit_width = 16, endianness = "BigEndian"}
name = "Data"
# Allow payloads up to the max size that can be specfied in "Data Length"
field_type = {type = "Bytes", max_len = 65535, endianness = "BigEndian"}
# CCSDS packet w/ primary header + secondary header + payload
[[formats]]
name = "ccsds_sec"
bit_flip = false
[[formats.fields]]
name = "Version Number"
bit_flip = true
field_type = {type = "UInt", bit_width = 3, endianness = "BigEndian"}
[[formats.fields]]
name = "Packet Type"
bit_flip = true
field_type = {type = "UInt", bit_width = 1, endianness = "BigEndian"}
[[formats.fields]]
name = "Secondary Header Flag"
bit_flip = true
field_type = {type = "UInt", bit_width = 1, endianness = "BigEndian"}
[[formats.fields]]
name = "APID"
bit_flip = true
field_type = {type = "UInt", bit_width = 11, endianness = "BigEndian"}
[[formats.fields]]
name = "Sequence Flags"
bit_flip = true
field_type = {type = "UInt", bit_width = 2, endianness = "BigEndian"}
[[formats.fields]]
name = "Packet Sequence Count"
bit_flip = true
field_type = {type = "UInt", bit_width = 14, endianness = "BigEndian"}
[[formats.fields]]
name = "Data Length"
field_type = {type = "UInt", bit_width = 16, endianness = "BigEndian"}
[[formats.fields]]
name = "Secondary header"
field_type = {type = "Bytes", max_len = 8, endianness = "BigEndian"}
[[formats.fields]]
name = "data"
# allow payloads up to the max size that can be specfied in "data length"
field_type = {type = "Bytes", max_len = 65535, endianness = "BigEndian"}

View File

@ -0,0 +1,8 @@
# Built-In Formats
All formats in this directory are automatically included in the formaty binary. Additional formats can be included
at run time by using the `--config` flag.
## Formats Included
* [CCSDS](ccsds.toml) - Standard CCSDS command/tlm packets
* `ccsds`: CCSDS packet with primary header + raw payload
* `ccsds_sec`: CCSDS packet with primary header + secondary header + raw payload

47
src/error/mod.rs 100644
View File

@ -0,0 +1,47 @@
use std::error::Error;
use std::fmt::{Display, Formatter};
use crate::parser::ByteArrayParseErr;
use crate::formatter::format::FormatError;
use crate::formatter::FormatConfigError;
#[derive(Debug)]
pub enum FormatyError {
ByteArrayParseError(ByteArrayParseErr),
FormatError(FormatError),
FormatConfigError(FormatConfigError),
FormatNotFound(String)
}
impl From<ByteArrayParseErr> for FormatyError {
fn from(e: ByteArrayParseErr) -> Self {
Self::ByteArrayParseError(e)
}
}
impl From<FormatError> for FormatyError {
fn from(e: FormatError) -> Self {
Self::FormatError(e)
}
}
impl From<FormatConfigError> for FormatyError {
fn from(e: FormatConfigError) -> Self {
Self::FormatConfigError(e)
}
}
impl Display for FormatyError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let err_msg = match self {
FormatyError::ByteArrayParseError(e) => e.to_string(),
FormatyError::FormatError(e) => e.to_string(),
FormatyError::FormatConfigError(e) => e.to_string(),
FormatyError::FormatNotFound(err_msg) => format!("'{}' config not found.", err_msg)
};
write!(f, "{}", err_msg)
}
}
impl Error for FormatyError {}

View File

@ -5,7 +5,56 @@ use crate::formatter::format::Format;
use serde::Deserialize;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use rust_embed::RustEmbed;
use std::str;
use std::str::Utf8Error;
use std::fmt::{Display, Formatter};
use std::error::Error;
#[derive(Debug)]
pub enum FormatConfigError {
IOError(std::io::Error),
TomlError(toml::de::Error),
Utf8Error(Utf8Error)
}
impl Error for FormatConfigError {}
impl From<std::io::Error> for FormatConfigError {
fn from(e: std::io::Error) -> Self {
Self::IOError(e)
}
}
impl From<toml::de::Error> for FormatConfigError {
fn from(e: toml::de::Error) -> Self {
Self::TomlError(e)
}
}
impl From<Utf8Error> for FormatConfigError {
fn from(e: Utf8Error) -> Self {
Self::Utf8Error(e)
}
}
impl Display for FormatConfigError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let err_msg = match self {
FormatConfigError::IOError(e) => e.to_string(),
FormatConfigError::TomlError(e) => e.to_string(),
FormatConfigError::Utf8Error(e) => e.to_string()
};
write!(f, "Format Config Error: {}", err_msg)
}
}
#[derive(RustEmbed)]
#[folder = "formats/"]
#[include = "*.toml"]
struct BuiltInFormats;
#[derive(Debug, Deserialize, Clone)]
pub struct FormatConfig {
@ -13,13 +62,25 @@ pub struct FormatConfig {
}
impl FormatConfig {
pub fn new(config_path: &Path) -> Result<Self, std::io::Error> {
let mut config = File::open(config_path)?;
pub fn new(config_path: &Option<PathBuf>) -> Result<Self, FormatConfigError> {
let mut contents = String::new();
if let Some(config_path) = config_path {
let mut config = File::open(config_path)?;
config.read_to_string(&mut contents)?;
}
Ok(toml::from_str(&contents).unwrap())
for format_file_path in BuiltInFormats::iter() {
if format_file_path.ends_with("md") {
continue;
}
let format_file = BuiltInFormats::get(&format_file_path).unwrap();
contents.push_str(str::from_utf8(&format_file.data).unwrap());
}
Ok(toml::from_str(&contents)?)
}
}

View File

@ -2,16 +2,18 @@ use crate::parser::parse_bytes_from_input_arg;
use formatter::FormatConfig;
use std::path::PathBuf;
use structopt::StructOpt;
use crate::error::FormatyError;
mod byte_stream;
mod formatter;
mod parser;
mod error;
#[derive(Debug, StructOpt)]
#[structopt(name = "Formaty", about = "Arbitrary Binary Data Formatting")]
pub struct Args {
#[structopt(parse(from_os_str), help = "Path to the format config")]
config: PathBuf,
#[structopt(short = "c", long="config", parse(from_os_str), help = "Path to the format config")]
config: Option<PathBuf>,
#[structopt(help = "Format to parse data as")]
format: String,
@ -20,23 +22,27 @@ pub struct Args {
data: Vec<String>,
}
fn main() {
fn formaty() -> Result<(), FormatyError> {
let args: Args = Args::from_args();
let config = FormatConfig::new(&args.config).unwrap();
let config = FormatConfig::new(&args.config)?;
let format = match config.formats.iter().find(|f| f.name == args.format) {
None => {
println!("Format not found in config file");
return;
}
Some(format) => format,
};
let format = config.formats.iter().find(|f| f.name == args.format).ok_or(FormatyError::FormatNotFound(args.format.to_string()))?;
let data = parse_bytes_from_input_arg(args.data).unwrap();
match format.format_data(&data) {
Ok(data_str) => println!("{}", data_str),
Err(_) => println!("Error formatting data"),
let data = format.format_data(&data)?;
println!("{}", data);
Ok(())
}
fn main() {
match formaty() {
Ok(_) => {}
Err(e) => {
println!("Error formatting data: {}", e.to_string())
}
}
}

View File

@ -1,4 +1,5 @@
use std::num::ParseIntError;
use std::fmt::{Display, Formatter};
#[derive(Debug, Clone)]
pub enum ByteArrayParseErr {
@ -12,6 +13,17 @@ impl From<ParseIntError> for ByteArrayParseErr {
}
}
impl Display for ByteArrayParseErr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let err_msg = match self {
ByteArrayParseErr::EmptySrcArray => "Provided array is empty!".to_string(),
ByteArrayParseErr::ParseIntError(e) => format!("Failed to parse as int: {}", e),
};
write!(f, "{}", err_msg)
}
}
fn bytes_from_str_array(src: Vec<String>) -> Result<Vec<u8>, ByteArrayParseErr> {
src.iter()
.map(|element| {