base and extension fully compiles, host in good shape

This commit is contained in:
2025-01-25 00:10:49 +01:00
parent 7be8716b19
commit 2b79e96dc9
49 changed files with 1719 additions and 1168 deletions

89
orchid-base/src/format.rs Normal file
View File

@@ -0,0 +1,89 @@
use std::convert::Infallible;
use std::iter;
use std::rc::Rc;
use std::str::FromStr;
use itertools::Itertools;
use regex::Regex;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct FmtUnit {
pub subs: Vec<FmtUnit>,
pub variants: Rc<Variants>,
}
impl FmtUnit {
pub fn new(variants: Rc<Variants>, subs: impl IntoIterator<Item = FmtUnit>) -> Self {
Self { subs: subs.into_iter().collect(), variants }
}
}
impl<T> From<T> for FmtUnit
where Variants: From<T>
{
fn from(value: T) -> Self { Self { subs: vec![], variants: Rc::new(Variants::from(value)) } }
}
impl FromStr for FmtUnit {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self { subs: vec![], variants: Rc::new(Variants::new([s])) })
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum FmtElement {
Sub(u8),
String(Rc<String>),
InlineSub(u8),
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Variants(pub Vec<Vec<FmtElement>>);
impl Variants {
pub fn new<'a>(variants: impl IntoIterator<Item = &'a str>) -> Self {
let re = Regex::new(r"(?<tpl>\{\d+?-?\})|(\{\{)|(\}\})").unwrap();
Self(Vec::from_iter(variants.into_iter().map(|s: &str| {
let matches = re.captures_iter(s);
let slots = matches.into_iter().filter_map(|m| m.name("tpl")).map(|tpl| {
let no_opencurly = tpl.as_str().strip_prefix("{").expect("required by regex");
let maybe_dash = no_opencurly.strip_suffix("}").expect("required by regex");
let (num, had_dash) =
maybe_dash.strip_suffix('-').map_or((maybe_dash, false), |s| (s, true));
let idx = num.parse::<u8>().expect("Decimal digits required by regex");
(tpl.range(), idx, had_dash)
});
(iter::once(None).chain(slots.into_iter().map(Some)).chain(None).tuple_windows())
.flat_map(|(l, r)| {
let string = match (l, &r) {
(None, Some((r, ..))) => &s[..r.start],
(Some((r1, ..)), Some((r2, ..))) => &s[r1.end..r2.start],
(Some((r, ..)), None) => &s[r.end..],
(None, None) => s,
};
let str_item = FmtElement::String(Rc::new(string.to_string()));
match r {
None => itertools::Either::Left([str_item]),
Some((_, idx, inline)) => itertools::Either::Right([str_item, match inline {
true => FmtElement::InlineSub(idx),
false => FmtElement::Sub(idx),
}]),
}
.into_iter()
})
.coalesce(|left, right| match (left, right) {
(FmtElement::String(left), FmtElement::String(right)) =>
Ok(FmtElement::String(Rc::new(left.to_string() + right.as_str()))),
tuple => Err(tuple),
})
.collect_vec()
})))
}
}
impl From<String> for Variants {
fn from(value: String) -> Self { Self(vec![vec![FmtElement::String(Rc::new(value))]]) }
}
impl From<Rc<String>> for Variants {
fn from(value: Rc<String>) -> Self { Self(vec![vec![FmtElement::String(value)]]) }
}
impl FromStr for Variants {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Self::new([s])) }
}