ca-rules 0.3.0

Parsing rule strings of life-like cellular automata.
Documentation
#![macro_use]

/// A macro to define a helper struct that represents the rule.
macro_rules! rule_struct {
    ($name: ident) => {
        #[derive(Clone, Debug, Eq, PartialEq)]
        struct $name {
            b: Vec<u8>,
            s: Vec<u8>,
        }

        impl $name {
            /// Construct the struct from `b` / `s` data.
            fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self {
                $name { b, s }
            }

            /// Construct the Generations struct from `b` / `s` data and the number of states.
            fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Gen<Self> {
                Gen {
                    rule: $name { b, s },
                    gen,
                }
            }

            /// A parser for numbers.
            fn parse_num<I>(chars: &mut std::iter::Peekable<I>) -> Result<usize, ParseRuleError>
            where
                I: Iterator<Item = char>,
            {
                let mut n = 0;
                if chars.peek().is_none() || !chars.peek().unwrap().is_digit(10) {
                    return Err(ParseRuleError::MissingNumber);
                }
                while let Some(&c) = chars.peek() {
                    match c {
                        c if c.is_digit(10) => {
                            chars.next();
                            n *= 10;
                            n += c.to_digit(10).unwrap() as usize;
                        }
                        _ => return Ok(n),
                    }
                }
                Ok(n)
            }
        }
    };
}

/// A macro to define a function to parse the helper struct.
macro_rules! parse_rule {
    ($($suffix: expr)?) => {
        /// A parser for the struct.
        fn parse_rule(input: &str) -> Result<Self, ParseRuleError> {
            let mut chars = input.chars().peekable();
            let (b, s);

            match chars.peek() {
                Some('B') | Some('b') => {
                    // Rule strings using B/S notation
                    chars.next();
                    b = Self::parse_bs(&mut chars)?;
                    if let Some('/') = chars.peek() {
                        chars.next();
                    }
                    match chars.next() {
                        Some('S') | Some('s') => (),
                        _ => return Err(ParseRuleError::Missing('S')),
                    }
                    s = Self::parse_bs(&mut chars)?;
                }
                _ => {
                    // Rule strings using S/B notation
                    s = Self::parse_bs(&mut chars)?;
                    match chars.next() {
                        Some('/') => (),
                        _ => return Err(ParseRuleError::Missing('/')),
                    }
                    b = Self::parse_bs(&mut chars)?;
                }
            }

            $(
                // Suffix
                if let Some(c) = chars.next() {
                    if $suffix.to_lowercase().chain($suffix.to_uppercase()).all(|s| s != c) {
                        return Err(ParseRuleError::Missing($suffix));
                    }
                } else {
                    return Err(ParseRuleError::Missing($suffix));
                }
            )?

            match chars.next() {
                None => Ok(Self::from_bs(b, s)),
                _ => Err(ParseRuleError::ExtraJunk),
            }
        }

        /// A parser for the Generations struct.
        fn parse_rule_gen(input: &str) -> Result<Gen<Self>, ParseRuleError> {
            let mut chars = input.chars().peekable();
            let (b, s);
            let mut gen = 2;

            match chars.peek() {
                // Rule strings using B/S/G notation
                Some('B') | Some('b') => {
                    chars.next();
                    b = Self::parse_bs(&mut chars)?;
                    if let Some('/') = chars.peek() {
                        chars.next();
                    }
                    match chars.next() {
                        Some('S') | Some('s') => (),
                        _ => return Err(ParseRuleError::Missing('S')),
                    }
                    s = Self::parse_bs(&mut chars)?;
                    match chars.peek() {
                        Some('/') => {
                            chars.next();
                            match chars.peek() {
                                Some('C') | Some('c') | Some('G') | Some('g') => {
                                    chars.next();
                                }
                                _ => (),
                            }
                            gen = Self::parse_num(&mut chars)?;
                        }
                        Some('C') | Some('c') | Some('G') | Some('g') => {
                            chars.next();
                            gen = Self::parse_num(&mut chars)?;
                        }
                        _ => (),
                    }
                }

                // Rule strings using G/B/S notation
                Some('C') | Some('c') | Some('G') | Some('g') => {
                    chars.next();
                    gen = Self::parse_num(&mut chars)?;
                    if let Some('/') = chars.peek() {
                        chars.next();
                    }
                    match chars.next() {
                        Some('B') | Some('b') => (),
                        _ => return Err(ParseRuleError::Missing('B')),
                    }
                    b = Self::parse_bs(&mut chars)?;
                    if let Some('/') = chars.peek() {
                        chars.next();
                    }
                    match chars.next() {
                        Some('S') | Some('s') => (),
                        _ => return Err(ParseRuleError::Missing('S')),
                    }
                    s = Self::parse_bs(&mut chars)?;
                }

                // Rule strings using S/B/G notation
                _ => {
                    s = Self::parse_bs(&mut chars)?;
                    match chars.next() {
                        Some('/') => (),
                        _ => return Err(ParseRuleError::Missing('/')),
                    }
                    b = Self::parse_bs(&mut chars)?;
                    if let Some('/') = chars.peek() {
                        chars.next();
                        gen = Self::parse_num(&mut chars)?;
                    }
                }
            }

            $(
                // Suffix
                if let Some(c) = chars.next() {
                    if $suffix.to_lowercase().chain($suffix.to_uppercase()).all(|s| s != c) {
                        return Err(ParseRuleError::Missing($suffix));
                    }
                } else {
                    return Err(ParseRuleError::Missing($suffix));
                }
            )?

            if gen < 2 {
                Err(ParseRuleError::GenLessThan2)
            } else {
                match chars.next() {
                    None => Ok(Self::from_bsg(b, s, gen)),
                    _ => Err(ParseRuleError::ExtraJunk),
                }
            }
        }
    };
}

/// A macro to define a function to parse `b` / `s` data.
macro_rules! parse_bs {
    ($n: expr) => {
        /// A parser for `b` / `s` data.
        fn parse_bs<I>(chars: &mut std::iter::Peekable<I>) -> Result<Vec<u8>, ParseRuleError>
        where
            I: Iterator<Item = char>,
        {
            let mut bs = Vec::new();

            while let Some(&c) = chars.peek() {
                match c {
                    c if c.is_digit($n + 1) => {
                        chars.next();
                        bs.push(c.to_digit($n + 1).unwrap() as u8);
                    }
                    _ => break,
                }
            }

            bs.sort();
            Ok(bs)
        }
    };

    { $($count: expr => { $($key: expr => $value: expr),* $(,)? }),*  $(,)? } => {
        /// A parser for `b` / `s` data.
        fn parse_bs<I>(chars: &mut std::iter::Peekable<I>) -> Result<Vec<u8>, ParseRuleError>
        where
            I: Iterator<Item = char>,
        {
            let mut bs = Vec::new();

            while let Some(&c) = chars.peek() {
                match c {
                    $(
                        $count => {
                            chars.next();
                            let all_keys = vec![$($key),*];
                            let keys = match chars.peek() {
                                Some('-') => {
                                    chars.next();
                                    let mut keys = Vec::new();
                                    while let Some(&c) = chars.peek() {
                                        if all_keys.contains(&c) {
                                            chars.next();
                                            keys.push(c);
                                        } else {
                                            break;
                                        }
                                    }
                                    all_keys.into_iter().filter(|c| !keys.contains(c)).collect()
                                }
                                Some(c) if all_keys.contains(&c) => {
                                    let mut keys = Vec::new();
                                    while let Some(&c) = chars.peek() {
                                        if all_keys.contains(&c) {
                                            chars.next();
                                            keys.push(c);
                                        } else {
                                            break;
                                        }
                                    }
                                    keys
                                }
                                Some(_) => {
                                    all_keys
                                }
                                None => all_keys
                            };
                            for &c in keys.iter() {
                                match c {
                                    $(
                                        $key => bs.extend_from_slice(&($value)),
                                    )*
                                    _ => unreachable!(),
                                }
                            }
                        }
                    ),*
                    _ => break,
                }
            }

            bs.sort();
            Ok(bs)
        }
    };
}

/// A macro to define a function to parse MAP strings.
macro_rules! parse_rule_map {
    ($n: expr) => {
        /// A parser for the struct that parses MAP strings.
        fn parse_rule_map(input: &str) -> Result<Self, ParseRuleError> {
            const CENTER_MARK: usize = 1 << ($n / 2);
            const RIGHT_MARK: usize = CENTER_MARK - 1;
            const LEFT_MARK: usize = RIGHT_MARK << ($n / 2 + 1);
            if !input.starts_with("MAP") {
                return Err(ParseRuleError::NotMapRule);
            }
            let bytes = base64::decode(&input[3..]).map_err(|_| ParseRuleError::Base64Error)?;
            if bytes.len() * 8 != 2 << $n {
                return Err(ParseRuleError::InvalidLength);
            }
            let mut b = Vec::new();
            let mut s = Vec::new();
            for (i, x) in bytes.iter().map(|x| x.reverse_bits()).enumerate() {
                for j in 0..8 {
                    if x & (1 << j) != 0 {
                        let k = i * 8 + j;
                        let n = ((k & LEFT_MARK) >> 1 | (k & RIGHT_MARK)) as u8;
                        if k & CENTER_MARK == 0 {
                            b.push(n);
                        } else {
                            s.push(n);
                        }
                    }
                }
            }
            Ok(Self::from_bs(b, s))
        }

        /// A parser for the Generations struct that parses MAP strings.
        fn parse_rule_gen_map(input: &str) -> Result<Gen<Self>, ParseRuleError> {
            const CENTER_MARK: usize = 1 << ($n / 2);
            const RIGHT_MARK: usize = CENTER_MARK - 1;
            const LEFT_MARK: usize = RIGHT_MARK << ($n / 2 + 1);
            let mut gen = 2;
            let mut slash = input.len();
            if !input.starts_with("MAP") {
                return Err(ParseRuleError::NotMapRule);
            }
            if let Some(n) = input.rfind('/') {
                if (n - 3) * 6 >= 2 << $n {
                    slash = n;
                    let mut chars = input[n + 1..].chars().peekable();
                    if chars.peek().is_some() {
                        gen = Self::parse_num(&mut chars)?;
                        if chars.next().is_some() {
                            return Err(ParseRuleError::ExtraJunk);
                        }
                    }
                }
            }
            let bytes =
                base64::decode(&input[3..slash]).map_err(|_| ParseRuleError::Base64Error)?;
            if bytes.len() * 8 != 2 << $n {
                return Err(ParseRuleError::InvalidLength);
            }
            let mut b = Vec::new();
            let mut s = Vec::new();
            for (i, x) in bytes.iter().map(|x| x.reverse_bits()).enumerate() {
                for j in 0..8 {
                    if x & (1 << j) != 0 {
                        let k = i * 8 + j;
                        let n = ((k & LEFT_MARK) >> 1 | (k & RIGHT_MARK)) as u8;
                        if k & CENTER_MARK == 0 {
                            b.push(n);
                        } else {
                            s.push(n);
                        }
                    }
                }
            }
            Ok(Self::from_bsg(b, s, gen))
        }
    };
}

/// A macro for implementing traits for helper structs.
///
/// `$f` is a function that converts the `b` / `s` data of the struct to those of the trait.
/// `$n` is the upper bound of `b` / `s` data of the struct.
macro_rules! impl_parser {
    (
        ($trait_name: ident, $trait_name_gen: ident) for $struct_name: ident,
        $f: expr,
        $n: expr $(,)?
    ) => {
        impl $trait_name for $struct_name {
            fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self {
                let mut new_b = Vec::new();
                let mut new_s = Vec::new();
                let f = $f;
                for i in 0_u8..=$n {
                    let j = f(i);
                    if b.contains(&j) {
                        new_b.push(i);
                    }
                    if s.contains(&j) {
                        new_s.push(i);
                    }
                }
                $struct_name::from_bs(new_b, new_s)
            }
        }

        impl $trait_name_gen for Gen<$struct_name> {
            fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self {
                let mut new_b = Vec::new();
                let mut new_s = Vec::new();
                let f = $f;
                for i in 0_u8..=$n {
                    let j = f(i);
                    if b.contains(&j) {
                        new_b.push(i);
                    }
                    if s.contains(&j) {
                        new_s.push(i);
                    }
                }
                $struct_name::from_bsg(new_b, new_s, gen)
            }
        }
    };
}