use std::borrow::Cow;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CognateSet {
pub proto_form: Option<Cow<'static, str>>,
pub proto_language: Option<Cow<'static, str>>,
pub gloss: Cow<'static, str>,
pub entries: Vec<CognateEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CognateEntry {
pub language: Cow<'static, str>,
pub word: Cow<'static, str>,
pub ipa: Cow<'static, str>,
}
impl CognateSet {
#[must_use]
pub fn for_language(&self, code: &str) -> Option<&CognateEntry> {
self.entries.iter().find(|e| e.language == code)
}
#[must_use]
#[inline]
pub fn language_count(&self) -> usize {
self.entries.len()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Etymology {
pub source_language: Cow<'static, str>,
pub source_form: Cow<'static, str>,
pub borrowing_type: BorrowingType,
pub period: Option<Cow<'static, str>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum BorrowingType {
Loanword,
Calque,
SemanticLoan,
Inherited,
}
#[must_use]
pub fn water_cognates() -> CognateSet {
CognateSet {
proto_form: Some(Cow::Borrowed("*wódr̥")),
proto_language: Some(Cow::Borrowed("Proto-Indo-European")),
gloss: Cow::Borrowed("water"),
entries: vec![
CognateEntry {
language: Cow::Borrowed("en"),
word: Cow::Borrowed("water"),
ipa: Cow::Borrowed("ˈwɔːtər"),
},
CognateEntry {
language: Cow::Borrowed("de"),
word: Cow::Borrowed("Wasser"),
ipa: Cow::Borrowed("ˈvasɐ"),
},
CognateEntry {
language: Cow::Borrowed("ru"),
word: Cow::Borrowed("вода"),
ipa: Cow::Borrowed("vɐˈda"),
},
CognateEntry {
language: Cow::Borrowed("sa"),
word: Cow::Borrowed("उदन्"),
ipa: Cow::Borrowed("udán"),
},
CognateEntry {
language: Cow::Borrowed("el"),
word: Cow::Borrowed("ύδωρ"),
ipa: Cow::Borrowed("ˈiðor"),
},
],
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_water_cognates() {
let cog = water_cognates();
assert_eq!(cog.language_count(), 5);
assert_eq!(cog.proto_form.as_deref(), Some("*wódr̥"));
let en = cog.for_language("en").unwrap();
assert_eq!(en.word, "water");
}
#[test]
fn test_cognate_unknown_language() {
let cog = water_cognates();
assert!(cog.for_language("xx").is_none());
}
#[test]
fn test_cognate_serde_roundtrip() {
let cog = water_cognates();
let json = serde_json::to_string(&cog).unwrap();
let back: CognateSet = serde_json::from_str(&json).unwrap();
assert_eq!(cog, back);
}
#[test]
fn test_etymology_serde_roundtrip() {
let etym = Etymology {
source_language: Cow::Borrowed("fr"),
source_form: Cow::Borrowed("café"),
borrowing_type: BorrowingType::Loanword,
period: Some(Cow::Borrowed("18th century")),
};
let json = serde_json::to_string(&etym).unwrap();
let back: Etymology = serde_json::from_str(&json).unwrap();
assert_eq!(etym, back);
}
#[test]
fn test_borrowing_types() {
assert_ne!(BorrowingType::Loanword, BorrowingType::Calque);
assert_ne!(BorrowingType::SemanticLoan, BorrowingType::Inherited);
}
}