rsmorphy 0.4.0

Morphological analyzer / inflection engine for Russian and Ukrainian (soon) languages (WIP)
use std::str::FromStr;
use std::num::ParseIntError;
use std::num::ParseFloatError;


pub enum DecodeError {
    UnexpectedEnd,
    UnknownPartType,
    DoesntMatch,
    ParseIntError(ParseIntError),
    ParseFloatError(ParseFloatError)
}


impl From<ParseIntError> for DecodeError {
    fn from(e: ParseIntError) -> Self {
        DecodeError::ParseIntError(e)
    }
}

impl From<ParseFloatError> for DecodeError {
    fn from(e: ParseFloatError) -> Self {
        DecodeError::ParseFloatError(e)
    }
}


pub fn (chr: char) {ch.is_digit(10)


pub fn take_1_char(s: &str) -> Result<(&str, char), DecodeError> {
    let ch = s.chars().next().ok_or(DecodeError::UnexpectedEnd)?;
    Ok((&s[ch.len_utf8() .. ], ch))
}


pub fn follow_str<'s, 'm>(s: &'s str, m: &'m str) -> Result<(&'s str, &'m str), DecodeError> {
    if s.len() < m.len() {
        Err(DecodeError::UnexpectedEnd)?;
    }
    if s.as_bytes().iter().zip(m.as_bytes().iter()).all(|(a, b)| a == b) {
        Ok((&s[m.len() .. ], m))
    } else {
        Err(DecodeError::DoesntMatch)
    }
}


pub fn take_str_while<'s, P>(s: &'s str, mut predicate: P) -> Result<(&'s str, &'s str), DecodeError>
    where
        P: FnMut(char) -> bool
{
    let mut pos = 0;
    for ch in s.chars() {
        if (predicate)(ch) {
            pos += ch.len_utf8();
        } else {
            break;
        }
    }
    Ok( (&s[pos ..], &s[.. pos]) )
}


pub fn take_str_until<'s, P>(s: &'s str, mut predicate: P) -> Result<(&'s str, &'s str), DecodeError>
    where
        P: FnMut(char) -> bool
{
    let mut pos = 0;
    for ch in s.chars() {
        if (predicate)(ch) {
            break;
        } else {
            pos += ch.len_utf8();
        }
    }
    Ok( (&s[pos ..], &s[.. pos]) )
}


pub fn take_str_while_char<'s>(s: &'s str, chr: char) -> Result<(&'s str, &'s str), DecodeError> {
    take_str_while(s, |ch| ch == chr )
}

pub fn take_str_until_char<'s>(s: &'s str, chr: char) -> Result<(&'s str, &'s str), DecodeError> {
    take_str_until(s, |ch| ch == chr )
}


pub fn map_parse_int<'s, 'm, T>( (s, m): (&'s str, &'m str) ) -> Result<(&'s str, T), DecodeError>
    where
        T: FromStr<Err = ParseIntError>
{
    Ok( (s, T::from_str(m)?) )
}


pub fn map_parse_float<'s, 'm, T>( (s, m): (&'s str, &'m str) ) -> Result<(&'s str, T), DecodeError>
    where
        T: FromStr<Err = ParseFloatError>
{
    Ok( (s, T::from_str(m)?) )
}