formaty/src/parser/mod.rs

193 lines
5.0 KiB
Rust
Raw Normal View History

use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
2022-04-09 18:40:37 +00:00
use std::num::ParseIntError;
use std::str::FromStr;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InputTypes {
Array,
String,
}
impl FromStr for InputTypes {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"array" | "a" => Ok(Self::Array),
"string" | "s" => Ok(Self::String),
_ => Err(format!("Invalid input type '{}'", s)),
}
}
}
impl InputTypes {
fn parse_byte_default(element: &str) -> Result<u8, ParseIntError> {
if element.starts_with("0x") || element.starts_with("0X") {
u8::from_str_radix(&element[2..], 16)
} else if element.starts_with("0b") || element.starts_with("0B") {
u8::from_str_radix(&element[2..], 2)
} else if element.starts_with('h') || element.starts_with('H') {
u8::from_str_radix(&element[1..], 16)
} else if element.len() > 1 && element.starts_with('0') {
u8::from_str_radix(&element[1..], 8)
} else {
element.parse()
}
}
fn parse_byte_base(element: &str, base: u32) -> Result<u8, ParseIntError> {
u8::from_str_radix(element, base)
}
fn parse_array(elements: Vec<String>, base: Option<u32>) -> Result<Vec<u8>, ParseIntError> {
elements
.iter()
.map(|element| {
if let Some(base) = base {
Self::parse_byte_base(element, base)
} else {
Self::parse_byte_default(element)
}
})
.collect()
}
pub fn parse_input(
&self,
src: Vec<String>,
base: Option<u32>,
) -> Result<Vec<u8>, ByteArrayParseErr> {
if src.is_empty() {
return Err(ByteArrayParseErr::EmptySrcArray);
}
let str_arr = if src.len() == 1 {
src[0]
.replace(',', " ")
.replace('[', "")
.replace(']', "")
.split_whitespace()
.map(|s| s.to_string())
.collect()
} else {
src
};
let data = match self {
InputTypes::Array => Self::parse_array(str_arr, base)?,
InputTypes::String => str_arr.join(" ").as_bytes().to_vec(),
};
Ok(data)
}
}
#[derive(Debug, Clone)]
pub enum ByteArrayParseErr {
EmptySrcArray,
ParseIntError(ParseIntError),
}
impl From<ParseIntError> for ByteArrayParseErr {
fn from(e: ParseIntError) -> Self {
ByteArrayParseErr::ParseIntError(e)
}
}
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)
}
}
#[cfg(test)]
mod tests {
use crate::parser::InputTypes;
#[test]
fn parse_base_10_array() {
let array = vec!["[0, 1, 2, 3, 4]".to_string()];
let out = InputTypes::Array.parse_input(array, None).unwrap();
assert_eq!(out, vec![0, 1, 2, 3, 4])
}
#[test]
fn parse_base_2_array() {
let array = vec!["[0b0, 0b1, 0b10, 0b11, 0b100]".to_string()];
let out = InputTypes::Array.parse_input(array, None).unwrap();
assert_eq!(out, vec![0, 1, 2, 3, 4])
}
#[test]
fn parse_base_8_array() {
let array = vec!["[00, 01, 02, 03, 04]".to_string()];
let out = InputTypes::Array.parse_input(array, None).unwrap();
assert_eq!(out, vec![0, 1, 2, 3, 4])
}
#[test]
fn parse_base_16_array() {
let array = vec!["[0x0, 0x1, 0x2, h3, H4]".to_string()];
let out = InputTypes::Array.parse_input(array, None).unwrap();
assert_eq!(out, vec![0, 1, 2, 3, 4])
}
#[test]
fn parse_base_mixed() {
let array = vec!["[00 0x1, 2, h3, H4]".to_string()];
let out = InputTypes::Array.parse_input(array, None).unwrap();
assert_eq!(out, vec![0, 1, 2, 3, 4])
}
#[test]
fn parse_no_braces_multi_args() {
let array = vec![
"0".to_string(),
"1".to_string(),
"2".to_string(),
"3".to_string(),
"4".to_string(),
];
let out = InputTypes::Array.parse_input(array, None).unwrap();
assert_eq!(out, vec![0, 1, 2, 3, 4])
}
#[test]
fn parse_no_braces_one_arg() {
let array = vec!["0 1 2 3 4".to_string()];
let out = InputTypes::Array.parse_input(array, None).unwrap();
assert_eq!(out, vec![0, 1, 2, 3, 4])
}
#[test]
fn parse_string() {
let string = "Hello World!";
let out = InputTypes::String
.parse_input(vec![string.to_string()], None)
.unwrap();
assert_eq!(string.as_bytes(), out)
}
}