use std::collections::HashMap;
pub const LAYER_PRIORITY_STRIDE: i64 = 1000;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OplsTypeRow {
pub class: String,
pub def: Option<String>,
pub overrides: Vec<String>,
pub priority: Option<i64>,
pub layer: u32,
}
#[derive(Debug, Clone, Default)]
pub struct OplsTypingMeta {
rows: HashMap<String, OplsTypeRow>,
}
impl OplsTypingMeta {
pub fn new() -> Self {
Self::default()
}
pub fn from_rows(rows: HashMap<String, OplsTypeRow>) -> Self {
Self { rows }
}
pub fn insert(&mut self, name: impl Into<String>, row: OplsTypeRow) {
self.rows.insert(name.into(), row);
}
pub fn get(&self, name: &str) -> Option<&OplsTypeRow> {
self.rows.get(name)
}
pub fn len(&self) -> usize {
self.rows.len()
}
pub fn is_empty(&self) -> bool {
self.rows.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&String, &OplsTypeRow)> {
self.rows.iter()
}
pub fn priorities(&self) -> HashMap<String, i64> {
let mut out = HashMap::with_capacity(self.rows.len());
for (name, row) in &self.rows {
if let Some(p) = row.priority {
out.insert(name.clone(), p);
continue;
}
let mut priority: i64 = 0;
for other in self.rows.values() {
if other.overrides.iter().any(|o| o == name) {
priority -= 1;
}
}
priority += row.overrides.len() as i64;
priority += i64::from(row.layer) * LAYER_PRIORITY_STRIDE;
out.insert(name.clone(), priority);
}
out
}
}
#[cfg(test)]
mod tests {
use super::*;
fn row(
class: &str,
def: Option<&str>,
overrides: &[&str],
priority: Option<i64>,
layer: u32,
) -> OplsTypeRow {
OplsTypeRow {
class: class.to_string(),
def: def.map(str::to_string),
overrides: overrides.iter().map(|s| s.to_string()).collect(),
priority,
layer,
}
}
#[test]
fn priority_explicit_wins() {
let mut m = OplsTypingMeta::new();
m.insert(
"opls_900",
row("CT", Some("[C]"), &["opls_135"], Some(42), 3),
);
let p = m.priorities();
assert_eq!(p["opls_900"], 42);
}
#[test]
fn priority_from_overrides() {
let mut m = OplsTypingMeta::new();
m.insert("opls_144", row("HA", Some("[H][C;X3]"), &[], None, 0));
m.insert(
"opls_146",
row("HA", Some("[H][c]"), &["opls_144"], None, 0),
);
let p = m.priorities();
assert_eq!(p["opls_146"], 1, "overrider gains +len(overrides)");
assert_eq!(p["opls_144"], -1, "overridden loses 1");
}
#[test]
fn priority_overrides_multiple() {
let mut m = OplsTypingMeta::new();
m.insert("opls_a", row("X", Some("[*]"), &[], None, 0));
m.insert("opls_b", row("X", Some("[*]"), &[], None, 0));
m.insert(
"opls_c",
row("X", Some("[*]"), &["opls_a", "opls_b"], None, 0),
);
let p = m.priorities();
assert_eq!(p["opls_c"], 2);
assert_eq!(p["opls_a"], -1);
assert_eq!(p["opls_b"], -1);
}
#[test]
fn priority_layer_stride() {
let mut m = OplsTypingMeta::new();
m.insert("opls_overlay", row("CT", Some("[C]"), &[], None, 2));
let p = m.priorities();
assert_eq!(p["opls_overlay"], 2 * LAYER_PRIORITY_STRIDE);
}
#[test]
fn priority_layer_plus_overrides() {
let mut m = OplsTypingMeta::new();
m.insert("opls_base", row("X", Some("[*]"), &[], None, 0));
m.insert("opls_hi", row("X", Some("[*]"), &["opls_base"], None, 1));
let p = m.priorities();
assert_eq!(p["opls_hi"], 1 + LAYER_PRIORITY_STRIDE);
assert_eq!(p["opls_base"], -1);
}
}