use crate::types::Type;
use cmdmat::{Decider, Decision, SVec};
pub type SomeDec = Option<&'static Decider<Type, String>>;
pub const ANY_ATOM: SomeDec = Some(&Decider {
description: "<atom>",
decider: any_atom_function,
});
pub const ANY_BASE64: SomeDec = Some(&Decider {
description: "<base64>",
decider: any_base64_function,
});
pub const ANY_BOOL: SomeDec = Some(&Decider {
description: "<true/false>",
decider: any_bool_function,
});
pub const ANY_F32: SomeDec = Some(&Decider {
description: "<f32>",
decider: any_f32_function,
});
pub const ANY_I32: SomeDec = Some(&Decider {
description: "<i32>",
decider: any_i32_function,
});
pub const ANY_STRING: SomeDec = Some(&Decider {
description: "<string>",
decider: any_string_function,
});
pub const ANY_U8: SomeDec = Some(&Decider {
description: "<u8>",
decider: any_u8_function,
});
pub const ANY_USIZE: SomeDec = Some(&Decider {
description: "<usize>",
decider: any_usize_function,
});
pub const IGNORE_ALL: SomeDec = Some(&Decider {
description: "<anything> ...",
decider: ignore_all_function,
});
pub const MANY_I32: SomeDec = Some(&Decider {
description: "<i32> ...",
decider: many_i32_function,
});
pub const MANY_STRING: SomeDec = Some(&Decider {
description: "<string> ...",
decider: many_string_function,
});
pub const POSITIVE_F32: SomeDec = Some(&Decider {
description: "<f32>=0>",
decider: positive_f32_function,
});
pub const TWO_STRINGS: SomeDec = Some(&Decider {
description: "<string> <string>",
decider: two_string_function,
});
fn any_atom_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
for i in input[0].chars() {
if i.is_whitespace() {
return Decision::Deny(input[0].into());
}
}
out.push(Type::Atom(input[0].to_string()));
Decision::Accept(1)
}
fn any_base64_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
match base64::decode(input[0]) {
Ok(base64) => {
out.push(Type::Raw(base64));
Decision::Accept(1)
}
Err(err) => Decision::Deny(format!["{}", err]),
}
}
fn any_bool_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
match input[0].parse::<bool>().ok().map(Type::Bool) {
Some(num) => {
out.push(num);
}
None => {
return Decision::Deny("got string: ".to_string() + input[0]);
}
}
Decision::Accept(1)
}
fn any_f32_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
match input[0].parse::<f32>().ok().map(Type::F32) {
Some(num) => {
out.push(num);
}
None => {
return Decision::Deny("got string: ".to_string() + input[0]);
}
}
Decision::Accept(1)
}
fn any_i32_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
match input[0].parse::<i32>().ok().map(Type::I32) {
Some(num) => {
out.push(num);
}
None => {
return Decision::Deny("got string: ".to_string() + input[0]);
}
}
Decision::Accept(1)
}
fn any_string_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
out.push(Type::String(input[0].to_string()));
Decision::Accept(1)
}
fn any_u8_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
match input[0].parse::<u8>().ok().map(Type::U8) {
Some(num) => {
out.push(num);
}
None => {
return Decision::Deny("got string: ".to_string() + input[0]);
}
}
Decision::Accept(1)
}
fn any_usize_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
match input[0].parse::<usize>().ok().map(Type::Usize) {
Some(num) => {
out.push(num);
}
None => {
return Decision::Deny("got string: ".to_string() + input[0]);
}
}
Decision::Accept(1)
}
fn ignore_all_function(input: &[&str], _: &mut SVec<Type>) -> Decision<String> {
Decision::Accept(input.len())
}
fn many_i32_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
let mut cnt = 0;
for i in input.iter() {
if let Some(num) = i.parse::<i32>().ok().map(Type::I32) {
aslen(input, cnt + 1)?;
out.push(num);
cnt += 1;
} else {
break;
}
}
Decision::Accept(cnt)
}
fn many_string_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, input.len())?;
let mut cnt = 0;
for (idx, i) in input.iter().enumerate() {
out.push(Type::String((*i).into()));
cnt = idx + 1;
}
Decision::Accept(cnt)
}
fn positive_f32_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
aslen(input, 1)?;
match input[0].parse::<f32>().ok().map(Type::F32) {
Some(Type::F32(val)) if val >= 0.0f32 => {
out.push(Type::F32(val));
}
_ => {
return Decision::Deny("got string: ".to_string() + input[0]);
}
}
Decision::Accept(1)
}
fn two_string_function(input: &[&str], out: &mut SVec<Type>) -> Decision<String> {
if input.len() == 1 {
return Decision::Deny("expected 1 more string".into());
}
aslen(input, 2)?;
out.push(Type::String(input[0].to_string()));
out.push(Type::String(input[1].to_string()));
Decision::Accept(2)
}
fn aslen(input: &[&str], input_l: usize) -> Result<(), String> {
if input.len() < input_l {
Err(format![
"Too few elements: {:?}, length: {}, expected: {}",
input,
input.len(),
input_l
])
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[quickcheck_macros::quickcheck]
fn basic_quickcheck(input: Vec<String>) {
let input = &input.iter().map(|string| &string[..]).collect::<Vec<_>>()[..];
let out = &mut SVec::new();
any_atom_function(input, out);
any_base64_function(input, out);
any_bool_function(input, out);
any_f32_function(input, out);
any_string_function(input, out);
any_u8_function(input, out);
ignore_all_function(input, out);
many_string_function(input, out);
positive_f32_function(input, out);
two_string_function(input, out);
}
}