use alloc::string::{String, ToString};
pub use crate::cldr::{ListPatterns, ListSpec};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ListStyle {
And,
Or,
}
fn fmt2(pat: &str, a: &str, b: &str) -> String {
let mut out = String::with_capacity(pat.len() + a.len() + b.len());
let mut rest = pat;
while !rest.is_empty() {
if let Some(r) = rest.strip_prefix("{0}") {
out.push_str(a);
rest = r;
} else if let Some(r) = rest.strip_prefix("{1}") {
out.push_str(b);
rest = r;
} else {
let ch = rest.chars().next().unwrap();
out.push(ch);
rest = &rest[ch.len_utf8()..];
}
}
out
}
fn spec(lang: &str) -> ListSpec {
use crate::cldr::list_spec;
let norm: String = lang
.chars()
.map(|c| {
if c == '_' {
'-'
} else {
c.to_ascii_lowercase()
}
})
.collect();
let mut end = norm.len();
loop {
if let Some(s) = list_spec(&norm[..end]) {
return s;
}
match norm[..end].rfind('-') {
Some(i) => end = i,
None => return list_spec("en").expect("root list spec present"),
}
}
}
#[must_use]
pub fn format_list(lang: &str, items: &[&str], style: ListStyle) -> String {
let s = spec(lang);
let p = match style {
ListStyle::And => s.and,
ListStyle::Or => s.or,
};
match items.len() {
0 => String::new(),
1 => items[0].to_string(),
2 => fmt2(p.two, items[0], items[1]),
n => {
let mut acc = fmt2(p.start, items[0], items[1]);
for item in &items[2..n - 1] {
acc = fmt2(p.middle, &acc, item);
}
fmt2(p.end, &acc, items[n - 1])
}
}
}