pub mod list;
pub mod parser;
use crate::ScriptDate;
use std::borrow::Cow;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ScriptCode<'a> {
pub alias: Option<Cow<'a, str>>,
pub code: Cow<'a, str>,
pub date: ScriptDate,
pub name: Cow<'a, str>,
pub name_french: Cow<'a, str>,
pub num: Cow<'a, str>,
pub unicode_version: Option<(u8, u8)>,
}
impl ScriptCode<'_> {
pub fn all() -> &'static [ScriptCode<'static>] {
self::list::all()
}
pub fn by_alias(alias: impl AsRef<str>) -> Option<&'static ScriptCode<'static>> {
Self::_by_alias(alias.as_ref())
}
fn _by_alias(alias: &str) -> Option<&'static ScriptCode<'static>> {
Self::all().into_iter().find(|s| s.alias.as_ref().map(|a| a == alias).unwrap_or(false))
}
pub fn by_code(code: impl AsRef<str>) -> Option<&'static ScriptCode<'static>> {
Self::_by_code(code.as_ref())
}
fn _by_code(code: &str) -> Option<&'static ScriptCode<'static>> {
Self::all().into_iter().find(|s| s.code == code)
}
pub fn by_date_range(
from: Option<ScriptDate>,
to: Option<ScriptDate>,
) -> Vec<&'static ScriptCode<'static>> {
let from_do = from.is_some();
let to_do = to.is_some();
if !from_do && !to_do {
return Vec::new();
}
let mut codes = Vec::new();
for code in Self::all() {
if let Some(from) = from {
if code.date < from {
continue;
}
}
if let Some(to) = to {
if code.date > to {
continue;
}
}
codes.push(code);
}
codes
}
pub fn by_name(name: impl AsRef<str>) -> Option<&'static ScriptCode<'static>> {
Self::_by_name(name.as_ref())
}
fn _by_name(name: &str) -> Option<&'static ScriptCode<'static>> {
Self::all().into_iter().find(|s| s.name == name)
}
pub fn by_name_french(name: impl AsRef<str>) -> Option<&'static ScriptCode<'static>> {
Self::_by_name_french(name.as_ref())
}
fn _by_name_french(name: &str) -> Option<&'static ScriptCode<'static>> {
Self::all().into_iter().find(|s| s.name_french == name)
}
pub fn by_num(num: impl AsRef<str>) -> Option<&'static ScriptCode<'static>> {
Self::_by_num(num.as_ref())
}
fn _by_num(num: &str) -> Option<&'static ScriptCode<'static>> {
Self::all().into_iter().find(|s| s.num == num)
}
}
#[cfg(test)]
mod tests {
use crate::ScriptDate;
use std::{
convert::TryFrom,
error::Error,
};
use super::ScriptCode;
#[test]
fn test_all() {
assert_eq!(202, ScriptCode::all().len());
}
#[test]
fn test_get_by_alias() {
assert!(ScriptCode::by_alias("Ahom").is_some());
assert!(ScriptCode::by_alias(String::from("Ahom")).is_some());
assert!(ScriptCode::by_alias("aaaa").is_none());
}
#[test]
fn test_get_by_code() {
assert!(ScriptCode::by_code("Blis").is_some());
assert!(ScriptCode::by_code(String::from("Blis")).is_some());
assert!(ScriptCode::by_alias("abza").is_none());
}
#[test]
fn test_get_by_date_range() -> Result<(), Box<dyn Error>> {
let f = ScriptDate::try_from((2005, 1, 1))?;
let t = ScriptDate::try_from((2012, 1, 1))?;
let r1 = ScriptCode::by_date_range(Some(f), Some(t));
assert!(r1.len() > 1);
let r2 = ScriptCode::by_date_range(Some(f), None);
assert!(r2.len() > 1);
let r3 = ScriptCode::by_date_range(None, Some(t));
assert!(r3.len() > 1);
let r4 = ScriptCode::by_date_range(None, None);
assert!(r4.is_empty());
Ok(())
}
#[test]
fn test_get_by_name() {
assert!(ScriptCode::by_name("Adlam").is_some());
assert!(ScriptCode::by_name(String::from("Adlam")).is_some());
assert!(ScriptCode::by_name("Aaaaa").is_none());
}
#[test]
fn test_get_by_name_french() {
assert!(ScriptCode::by_name_french("arabe").is_some());
assert!(ScriptCode::by_name_french(String::from("arabe")).is_some());
assert!(ScriptCode::by_name_french("aaaaa").is_none());
}
#[test]
fn test_get_by_num() {
assert!(ScriptCode::by_num("070").is_some());
assert!(ScriptCode::by_num(String::from("070")).is_some());
assert!(ScriptCode::by_num("000").is_none());
}
}