use super::{
neumann::{ParseNeumann, ParseNeumannGen},
Gen,
};
use crate::ParseRuleError;
rule_struct!(NtNeumann);
impl NtNeumann {
parse_rule_map!(4);
}
impl_parser!(
(ParseNeumann, ParseNeumannGen) for NtNeumann,
|i: u8| i.count_ones() as u8,
0x0f,
);
pub trait ParseNtNeumann {
fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self;
fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
where
Self: Sized,
{
let NtNeumann { b, s } = ParseNeumann::parse_rule(input).or_else(|e| {
NtNeumann::parse_rule_map(input).map_err(|e_map| {
if e_map == ParseRuleError::NotMapRule {
e
} else {
e_map
}
})
})?;
Ok(Self::from_bs(b, s))
}
}
pub trait ParseNtNeumannGen {
fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self;
fn parse_rule(input: &str) -> Result<Self, ParseRuleError>
where
Self: Sized,
{
let Gen {
rule: NtNeumann { b, s },
gen,
} = ParseNeumannGen::parse_rule(input).or_else(|e| {
NtNeumann::parse_rule_gen_map(input).map_err(|e_map| {
if e_map == ParseRuleError::NotMapRule {
e
} else {
e_map
}
})
})?;
Ok(Self::from_bsg(b, s, gen))
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Rule;
impl ParseNtNeumann for Rule {
fn from_bs(_b: Vec<u8>, _s: Vec<u8>) -> Self {
Rule
}
}
#[test]
fn valid_rules() -> Result<(), ParseRuleError> {
Rule::parse_rule("B3/S23V")?;
Rule::parse_rule("B3S23V")?;
Rule::parse_rule("b3s23v")?;
Rule::parse_rule("23/3V")?;
Rule::parse_rule("23/v")?;
Rule::parse_rule("MAPHmlphg")?;
Ok(())
}
#[test]
fn invalid_rules() {
assert_eq!(
Rule::parse_rule("B3/S23va").err(),
Some(ParseRuleError::ExtraJunk)
);
assert_eq!(
Rule::parse_rule("B3V/S23").err(),
Some(ParseRuleError::Missing('S'))
);
assert_eq!(
Rule::parse_rule("B3/S23").err(),
Some(ParseRuleError::Missing('V'))
);
assert_eq!(
Rule::parse_rule("B3/S25V").err(),
Some(ParseRuleError::Missing('V'))
);
assert_eq!(
Rule::parse_rule("233v").err(),
Some(ParseRuleError::Missing('/'))
);
assert_eq!(
Rule::parse_rule("MAPFgFoF2gXgH5oF4B+gH4A6A").err(),
Some(ParseRuleError::InvalidLength)
);
}
#[test]
fn parse_neumann_as_ntneumann() -> Result<(), ParseRuleError> {
let rule: NtNeumann = ParseNeumann::parse_rule("B2/S013V")?;
for b in 0..=0x0f {
assert_eq!(rule.b.contains(&b), [2].contains(&b.count_ones()));
}
for s in 0..=0x0f {
assert_eq!(rule.s.contains(&s), [0, 1, 3].contains(&s.count_ones()));
}
Ok(())
}
#[test]
fn parse_map() -> Result<(), ParseRuleError> {
let rule1: NtNeumann = NtNeumann::parse_rule("B2/S013V")?;
let rule2: NtNeumann = NtNeumann::parse_rule_map("MAPHmlphg")?;
assert_eq!(rule1, rule2);
Ok(())
}
}