yowl 0.1.0

Primitives for reading and writing the SMILES language
Documentation
use super::{error::ReadError, missing_character::missing_character, scanner::Scanner};
use crate::feature::{Aliphatic, Aromatic, AtomKind};

pub fn read_organic(scanner: &mut Scanner) -> Result<Option<AtomKind>, ReadError> {
    match scanner.peek() {
        Some('b') => aromatic(Aromatic::B, scanner),
        Some('c') => aromatic(Aromatic::C, scanner),
        Some('n') => aromatic(Aromatic::N, scanner),
        Some('o') => aromatic(Aromatic::O, scanner),
        Some('p') => aromatic(Aromatic::P, scanner),
        Some('s') => aromatic(Aromatic::S, scanner),
        Some('A') => {
            scanner.pop();

            match scanner.peek() {
                Some('t') => aliphatic(Aliphatic::At, scanner),

                _ => Err(missing_character(scanner)),
            }
        }
        Some('B') => {
            scanner.pop();

            match scanner.peek() {
                Some('r') => aliphatic(Aliphatic::Br, scanner),
                _ => Ok(Some(AtomKind::Aliphatic(Aliphatic::B))),
            }
        }
        Some('C') => {
            scanner.pop();

            match scanner.peek() {
                Some('l') => aliphatic(Aliphatic::Cl, scanner),
                _ => Ok(Some(AtomKind::Aliphatic(Aliphatic::C))),
            }
        }
        Some('N') => aliphatic(Aliphatic::N, scanner),
        Some('O') => aliphatic(Aliphatic::O, scanner),
        Some('P') => aliphatic(Aliphatic::P, scanner),
        Some('S') => aliphatic(Aliphatic::S, scanner),
        Some('F') => aliphatic(Aliphatic::F, scanner),
        Some('I') => aliphatic(Aliphatic::I, scanner),
        Some('T') => {
            scanner.pop();

            match scanner.peek() {
                Some('s') => aliphatic(Aliphatic::Ts, scanner),
                _ => Err(missing_character(scanner)),
            }
        }
        _ => Ok(None),
    }
}

fn aromatic(aromatic: Aromatic, scanner: &mut Scanner) -> Result<Option<AtomKind>, ReadError> {
    scanner.pop();

    Ok(Some(AtomKind::Aromatic(aromatic)))
}

fn aliphatic(aliphatic: Aliphatic, scanner: &mut Scanner) -> Result<Option<AtomKind>, ReadError> {
    scanner.pop();

    Ok(Some(AtomKind::Aliphatic(aliphatic)))
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn a_x() {
        let mut scanner = Scanner::new("Ax");
        let atom = read_organic(&mut scanner);

        assert_eq!(atom, Err(ReadError::Character(1)))
    }

    #[test]
    fn t_x() {
        let mut scanner = Scanner::new("Tx");
        let atom = read_organic(&mut scanner);

        assert_eq!(atom, Err(ReadError::Character(1)))
    }

    #[test]
    fn b_x() {
        let mut scanner = Scanner::new("Bx");
        let atom = read_organic(&mut scanner);

        assert_eq!(atom, Ok(Some(AtomKind::Aliphatic(Aliphatic::B))))
    }

    #[test]
    fn c_x() {
        let mut scanner = Scanner::new("Cx");
        let atom = read_organic(&mut scanner);

        assert_eq!(atom, Ok(Some(AtomKind::Aliphatic(Aliphatic::C))))
    }

    #[test]
    fn aromatic_carbon() {
        let mut scanner = Scanner::new("c");
        let atom = read_organic(&mut scanner);

        assert_eq!(atom, Ok(Some(AtomKind::Aromatic(Aromatic::C))))
    }

    #[test]
    fn chlorine() {
        let mut scanner = Scanner::new("Cl");
        let atom = read_organic(&mut scanner);

        assert_eq!(atom, Ok(Some(AtomKind::Aliphatic(Aliphatic::Cl))))
    }
}