#[derive(Debug, Clone, PartialEq)]
pub enum LineContent {
Plain(String),
Template(LineTemplate),
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LineFlags: u8 {
const STARTS_WITH_WS = 0b0001;
const ENDS_WITH_WS = 0b0010;
const ALL_WS = 0b0100;
const EMPTY = 0b1000;
}
}
impl LineFlags {
pub fn from_content(content: &LineContent) -> Self {
match content {
LineContent::Plain(s) => Self::from_plain(s),
LineContent::Template(parts) => Self::from_template(parts),
}
}
pub fn from_plain(s: &str) -> Self {
if s.is_empty() {
return Self::EMPTY;
}
let mut flags = Self::empty();
if s.starts_with(char::is_whitespace) {
flags |= Self::STARTS_WITH_WS;
}
if s.ends_with(char::is_whitespace) {
flags |= Self::ENDS_WITH_WS;
}
if s.trim().is_empty() {
flags |= Self::ALL_WS;
}
flags
}
fn from_template(parts: &[LinePart]) -> Self {
if parts.is_empty() {
return Self::EMPTY;
}
let mut flags = Self::empty();
if let Some(LinePart::Literal(s)) = parts.first()
&& s.starts_with(char::is_whitespace)
{
flags |= Self::STARTS_WITH_WS;
}
match parts.last() {
Some(LinePart::Literal(s)) if s.ends_with(char::is_whitespace) => {
flags |= Self::ENDS_WITH_WS;
}
_ => {}
}
let all_ws = parts.iter().all(|p| match p {
LinePart::Literal(s) => s.trim().is_empty(),
_ => false,
});
if all_ws {
flags |= Self::ALL_WS;
}
flags
}
}
pub type LineTemplate = Vec<LinePart>;
#[derive(Debug, Clone, PartialEq)]
pub enum LinePart {
Literal(String),
Slot(u8),
Select {
slot: u8,
variants: Vec<(SelectKey, String)>,
default: String,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum SelectKey {
Cardinal(PluralCategory),
Ordinal(PluralCategory),
Exact(i32),
Keyword(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PluralCategory {
Zero,
One,
Two,
Few,
Many,
Other,
}
pub trait PluralResolver {
fn cardinal(&self, n: i64, locale_override: Option<&str>) -> PluralCategory;
fn ordinal(&self, n: i64) -> PluralCategory;
}