rsmorphy 0.4.0

Morphological analyzer / inflection engine for Russian and Ukrainian (soon) languages (WIP)
use {
    analyzer::MorphAnalyzer,
    container::{
        abc::*, paradigm::ParadigmId, Dictionary, HyphenAdverb, Initials, Lex, Score, Shaped,
        Unknown,
    },
    opencorpora::OpencorporaTagReg,
    std::{borrow::Cow, fmt},
};

#[derive(Debug, Clone, PartialEq)]
pub enum StackSource {
    Dictionary(Dictionary),
    HyphenAdverb(HyphenAdverb),
    Initials(Initials),
    Shaped(Shaped),
    Unknown(Unknown),
}

impl StackSource {
    pub fn new<T>(source: T) -> Self
    where
        T: Into<StackSource>,
    {
        source.into()
    }

    pub fn as_dictionary(&self) -> Option<&Dictionary> {
        match self {
            StackSource::Dictionary(source) => Some(source),
            _ => None,
        }
    }

    pub fn as_hyphen_adverb(&self) -> Option<&HyphenAdverb> {
        match self {
            StackSource::HyphenAdverb(source) => Some(source),
            _ => None,
        }
    }

    pub fn as_initials(&self) -> Option<&Initials> {
        match self {
            StackSource::Initials(source) => Some(source),
            _ => None,
        }
    }

    pub fn as_shaped(&self) -> Option<&Shaped> {
        match self {
            StackSource::Shaped(source) => Some(source),
            _ => None,
        }
    }

    pub fn as_unknown(&self) -> Option<&Unknown> {
        match self {
            StackSource::Unknown(source) => Some(source),
            _ => None,
        }
    }

    pub fn iter_lexeme<'s: 'i, 'm: 'i, 'i>(
        &'s self,
        morph: &'m MorphAnalyzer,
    ) -> Box<dyn Iterator<Item = Lex> + 'i> {
        match self {
            StackSource::Dictionary(source) => Box::new(source.iter_lexeme(morph)),
            StackSource::HyphenAdverb(source) => Box::new(source.iter_lexeme(morph)),
            StackSource::Initials(source) => Box::new(source.iter_lexeme(morph)),
            StackSource::Shaped(source) => Box::new(source.iter_lexeme(morph)),
            StackSource::Unknown(source) => Box::new(source.iter_lexeme(morph)),
        }
    }
}

impl From<Dictionary> for StackSource {
    fn from(source: Dictionary) -> Self {
        StackSource::Dictionary(source)
    }
}

impl From<HyphenAdverb> for StackSource {
    fn from(source: HyphenAdverb) -> Self {
        StackSource::HyphenAdverb(source)
    }
}

impl From<Initials> for StackSource {
    fn from(source: Initials) -> Self {
        StackSource::Initials(source)
    }
}

impl From<Shaped> for StackSource {
    fn from(source: Shaped) -> Self {
        StackSource::Shaped(source)
    }
}

impl From<Unknown> for StackSource {
    fn from(source: Unknown) -> Self {
        StackSource::Unknown(source)
    }
}

impl Source for StackSource {
    fn score(&self) -> Score {
        match *self {
            StackSource::Dictionary(ref source) => source.score(),
            StackSource::HyphenAdverb(ref source) => source.score(),
            StackSource::Initials(ref source) => source.score(),
            StackSource::Shaped(ref source) => source.score(),
            StackSource::Unknown(ref source) => source.score(),
        }
    }

    fn is_lemma(&self) -> bool {
        match *self {
            StackSource::Dictionary(ref source) => source.is_lemma(),
            StackSource::HyphenAdverb(ref source) => source.is_lemma(),
            StackSource::Initials(ref source) => source.is_lemma(),
            StackSource::Shaped(ref source) => source.is_lemma(),
            StackSource::Unknown(ref source) => source.is_lemma(),
        }
    }

    fn is_known(&self) -> bool {
        match *self {
            StackSource::Dictionary(ref source) => source.is_known(),
            StackSource::HyphenAdverb(ref source) => source.is_known(),
            StackSource::Initials(ref source) => source.is_known(),
            StackSource::Shaped(ref source) => source.is_known(),
            StackSource::Unknown(ref source) => source.is_known(),
        }
    }

    fn get_word(&self) -> Cow<str> {
        match *self {
            StackSource::Dictionary(ref source) => source.get_word(),
            StackSource::HyphenAdverb(ref source) => source.get_word(),
            StackSource::Initials(ref source) => source.get_word(),
            StackSource::Shaped(ref source) => source.get_word(),
            StackSource::Unknown(ref source) => source.get_word(),
        }
    }

    fn get_normal_form(&self, morph: &MorphAnalyzer) -> Cow<str> {
        match *self {
            StackSource::Dictionary(ref source) => source.get_normal_form(morph),
            StackSource::HyphenAdverb(ref source) => source.get_normal_form(morph),
            StackSource::Initials(ref source) => source.get_normal_form(morph),
            StackSource::Shaped(ref source) => source.get_normal_form(morph),
            StackSource::Unknown(ref source) => source.get_normal_form(morph),
        }
    }

    fn get_tag<'m>(&self, morph: &'m MorphAnalyzer) -> &'m OpencorporaTagReg {
        match *self {
            StackSource::Dictionary(ref source) => source.get_tag(morph),
            StackSource::HyphenAdverb(ref source) => source.get_tag(morph),
            StackSource::Initials(ref source) => source.get_tag(morph),
            StackSource::Shaped(ref source) => source.get_tag(morph),
            StackSource::Unknown(ref source) => source.get_tag(morph),
        }
    }

    fn try_get_para_id(&self) -> Option<ParadigmId> {
        match *self {
            StackSource::Dictionary(ref source) => source.try_get_para_id(),
            StackSource::HyphenAdverb(ref source) => source.try_get_para_id(),
            StackSource::Initials(ref source) => source.try_get_para_id(),
            StackSource::Shaped(ref source) => source.try_get_para_id(),
            StackSource::Unknown(ref source) => source.try_get_para_id(),
        }
    }

    fn write_word<W: fmt::Write>(&self, f: &mut W) -> fmt::Result {
        match *self {
            StackSource::Dictionary(ref source) => source.write_word(f),
            StackSource::HyphenAdverb(ref source) => source.write_word(f),
            StackSource::Initials(ref source) => source.write_word(f),
            StackSource::Shaped(ref source) => source.write_word(f),
            StackSource::Unknown(ref source) => source.write_word(f),
        }
    }

    fn write_normal_form<W: fmt::Write>(&self, f: &mut W, morph: &MorphAnalyzer) -> fmt::Result {
        match *self {
            StackSource::Dictionary(ref source) => source.write_normal_form(f, morph),
            StackSource::HyphenAdverb(ref source) => source.write_normal_form(f, morph),
            StackSource::Initials(ref source) => source.write_normal_form(f, morph),
            StackSource::Shaped(ref source) => source.write_normal_form(f, morph),
            StackSource::Unknown(ref source) => source.write_normal_form(f, morph),
        }
    }

    fn get_lexeme(&self, morph: &MorphAnalyzer) -> Vec<Lex> {
        match *self {
            StackSource::Dictionary(ref source) => source.get_lexeme(morph),
            StackSource::HyphenAdverb(ref source) => source.get_lexeme(morph),
            StackSource::Initials(ref source) => source.get_lexeme(morph),
            StackSource::Shaped(ref source) => source.get_lexeme(morph),
            StackSource::Unknown(ref source) => source.get_lexeme(morph),
        }
    }

    fn get_lemma(&self, morph: &MorphAnalyzer) -> Lex {
        match *self {
            StackSource::Dictionary(ref source) => source.get_lemma(morph),
            StackSource::HyphenAdverb(ref source) => source.get_lemma(morph),
            StackSource::Initials(ref source) => source.get_lemma(morph),
            StackSource::Shaped(ref source) => source.get_lemma(morph),
            StackSource::Unknown(ref source) => source.get_lemma(morph),
        }
    }
}

impl MorphySerde for StackSource {
    fn encode<W: fmt::Write>(&self, f: &mut W) -> fmt::Result {
        match *self {
            StackSource::Dictionary(ref source) => source.encode(f),
            StackSource::HyphenAdverb(ref source) => source.encode(f),
            StackSource::Initials(ref source) => source.encode(f),
            StackSource::Shaped(ref source) => source.encode(f),
            StackSource::Unknown(ref source) => source.encode(f),
        }
    }

    fn decode(s: &str) -> Result<(&str, Self), DecodeError> {
        Ok(match try_decode::<Dictionary>(s)? {
            Some(v) => v,
            None => match try_decode::<HyphenAdverb>(s)? {
                Some(v) => v,
                None => match try_decode::<Initials>(s)? {
                    Some(v) => v,
                    None => match try_decode::<Shaped>(s)? {
                        Some(v) => v,
                        None => match try_decode::<Unknown>(s)? {
                            Some(v) => v,
                            None => Err(DecodeError::UnknownPartType)?,
                        },
                    },
                },
            },
        })
    }
}

fn try_decode<T: MorphySerde + Into<StackSource>>(
    s: &str,
) -> Result<Option<(&str, StackSource)>, DecodeError> {
    Ok(match T::decode(s) {
        Err(DecodeError::UnknownPartType) => None,
        Err(e) => Err(e)?,
        Ok((s, v)) => Some((s, v.into())),
    })
}