mod endings;
use std::fmt;
use crate::unicode as U;
pub mod regular;
pub use crate::adjective::regular::{Regular, RegularError};
pub use crate::decline::{Gender, Case, is_i_stem};
pub use crate::inflection::{Number};
pub trait Adjective {
fn stem(&self) -> Option<&str>;
fn group(&self) -> Option<Group>;
fn decline(&self, number: Number, case: Case, gender: Gender) -> Option<Vec<String>>;
}
pub enum DictionaryForm {
Three(String, String, String),
Two(String, String),
}
impl fmt::Display for DictionaryForm {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
DictionaryForm::Three(first, second, third) => write!(f, "{}, {}, {}", first, second, third),
DictionaryForm::Two(first, second) => write!(f, "{}, {}", first, second),
}
}
}
pub enum Termination {
One,
Two,
Three,
}
pub enum Group {
FirstSecond,
Third(Termination),
}
impl DictionaryForm {
pub(self) fn first(&self) -> &str {
match self {
DictionaryForm::Three(first, _, _) => first,
DictionaryForm::Two(first, _) => first,
}
}
pub(self) fn second(&self) -> &str {
match self {
DictionaryForm::Three(_, second, _) => second,
DictionaryForm::Two(_, second) => second,
}
}
pub(self) fn third(&self) -> Option<&str> {
match self {
DictionaryForm::Three(_, _, third) => Some(third),
DictionaryForm::Two(_, _) => None,
}
}
}
fn normalize_dictionary_form(dictionary_form: DictionaryForm) -> DictionaryForm {
match dictionary_form {
DictionaryForm::Three(f, s, t) => DictionaryForm::Three(U::normalize(f), U::normalize(s), U::normalize(t)),
DictionaryForm::Two(f, s) => DictionaryForm::Two(U::normalize(f), U::normalize(s)),
}
}
fn not_normalized_group(f: &str, s: &str, t: Option<&str>) -> Option<Group> {
match (f, s, t) {
(f, s, Some(t)) if (f.ends_with("us") || f.ends_with("er")) && s.ends_with('a') && t.ends_with("um") => Some(Group::FirstSecond),
(f, s, Some(t)) if f.ends_with("er") && s.ends_with("is") && t.ends_with('e') => Some(Group::Third(Termination::Three)),
(f, s, None) if f.ends_with("is") && s.ends_with('e') => Some(Group::Third(Termination::Two)),
(_, s, None) if s.ends_with("is") => Some(Group::Third(Termination::One)),
_ => None,
}
}
pub fn group(dictionary_form: &DictionaryForm) -> Option<Group> {
match dictionary_form {
DictionaryForm::Three(f, s, t) => not_normalized_group(U::normalize_if_needed(f).as_ref(), U::normalize_if_needed(s).as_ref(), Some(U::normalize_if_needed(t).as_ref())),
DictionaryForm::Two(f, s) => not_normalized_group(U::normalize_if_needed(f).as_ref(), U::normalize_if_needed(s).as_ref(), None),
}
}
fn not_normalized_stem<'a>(f: &'a str, s: &'a str, t: Option<&'a str>) -> Option<&'a str> {
match not_normalized_group(f, s, t) {
Some(Group::FirstSecond) => Some(s.trim_end_matches('a')),
Some(Group::Third(Termination::Two)) => Some(f.trim_end_matches("is")),
Some(Group::Third(_)) => Some(s.trim_end_matches("is")),
_ => None,
}
}
pub fn stem(dictionary_form: &DictionaryForm) -> Option<String> {
match dictionary_form {
DictionaryForm::Three(f, s, t) => {
match not_normalized_stem(U::normalize_if_needed(f).as_ref(), U::normalize_if_needed(s).as_ref(), Some(U::normalize_if_needed(t).as_ref())) {
Some(stem) => Some(stem.to_string()),
None => None,
}
},
DictionaryForm::Two(f, s) => {
match not_normalized_stem(U::normalize_if_needed(f).as_ref(), U::normalize_if_needed(s).as_ref(), None) {
Some(stem) => Some(stem.to_string()),
None => None,
}
},
}
}
#[cfg(test)]
mod test {
use super::*;
use unicode_normalization::{is_nfc};
#[test]
fn test_group() {
let first = DictionaryForm::Three("altus".to_string(), "alta".to_string(), "altum".to_string());
match group(&first) {
Some(Group::FirstSecond) => (),
_ => panic!("Received an incorrect group for a first and second declension adjective."),
}
let third_one = DictionaryForm::Two("atrōx".to_string(), "atrōcis".to_string());
match group(&third_one) {
Some(Group::Third(Termination::One)) => (),
_ => panic!("Received an incorrect group for a third declension adjective with one termination."),
}
let third_two = DictionaryForm::Two("agilis".to_string(), "agile".to_string());
match group(&third_two) {
Some(Group::Third(Termination::Two)) => (),
_ => panic!("Received an incorrect group for a third declension adjective with two terminations."),
}
let third_three = DictionaryForm::Three("celer".to_string(), "celeris".to_string(), "celere".to_string());
match group(&third_three) {
Some(Group::Third(Termination::Three)) => (),
_ => panic!("Received an incorrect group for a third declension adjective with three terminations."),
}
}
#[test]
fn test_stem() {
let first = DictionaryForm::Three("altus".to_string(), "alta".to_string(), "altum".to_string());
assert_eq!(stem(&first), Some("alt".to_string()), "Failed to get the stem for a first and second declension adjective.");
let third_one = DictionaryForm::Two("atrōx".to_string(), "atrōcis".to_string());
assert_eq!(stem(&third_one), Some("atrōc".to_string()), "Failed to get the stem for a third declension adjective with one termination.");
let third_two = DictionaryForm::Two("agilis".to_string(), "agile".to_string());
assert_eq!(stem(&third_two), Some("agil".to_string()), "Failed to get the stem for a third declension adjective with two terminations.");
let third_three = DictionaryForm::Three("celer".to_string(), "celeris".to_string(), "celere".to_string());
assert_eq!(stem(&third_three), Some("celer".to_string()), "Failed to get the stem for a third declension adjective with three terminations.");
}
}