#[cfg(test)]
mod tests;
#[allow(unused_imports)]
use crate::{syms, xkb::Context};
use {
crate::{
Keysym,
xkb::{
code_map::CodeMap,
compose::parser::{Production, Step},
diagnostic::{DiagnosticKind, DiagnosticSink},
format::FormatFormat,
span::{SpanExt, Spanned},
},
},
bstr::ByteSlice,
kbvm_proc::ad_hoc_display,
std::{
cell::Cell,
fmt::{Debug, Display, Formatter},
ops::Range,
},
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct Payload {
pub(crate) string: Option<Box<str>>,
pub(crate) keysym: Option<Keysym>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct Node {
pub(crate) keysym: Keysym,
data: [u32; 2],
}
#[derive(Clone, PartialEq)]
enum NodeType {
Intermediate { range: Range<usize> },
Leaf { payload: usize },
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ComposeTable {
nodes: Box<[Node]>,
payloads: Box<[Payload]>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct State {
range: Range<usize>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FeedResult<'a> {
Pending,
Aborted,
Composed {
string: Option<&'a str>,
keysym: Option<Keysym>,
},
}
impl NodeType {
fn serialize(self) -> [u32; 2] {
match self {
NodeType::Intermediate { range } => [range.start as u32, range.end as u32],
NodeType::Leaf { payload } => [!0, payload as u32],
}
}
}
impl Node {
fn deserialize(&self) -> NodeType {
if self.data[0] == !0 {
NodeType::Leaf {
payload: self.data[1] as usize,
}
} else {
NodeType::Intermediate {
range: (self.data[0] as usize)..(self.data[1] as usize),
}
}
}
}
impl ComposeTable {
pub(crate) fn new(
map: &mut CodeMap,
diagnostics: &mut DiagnosticSink<'_, '_>,
productions: &[Spanned<Production>],
) -> Self {
struct PreData {
step_range: Range<usize>,
production: Option<usize>,
}
let mut steps = vec![];
let mut pre_datas = vec![];
for (idx, production) in productions.iter().enumerate() {
let start = steps.len();
if u32::MAX as usize - steps.len() - 1 <= production.val.steps.len() {
break;
}
for step in production.val.steps.iter() {
steps.push(*step);
pre_datas.push(PreData {
step_range: start..steps.len(),
production: None,
});
}
pre_datas.last_mut().unwrap().production = Some(idx);
}
pre_datas.sort_by_key(|k| &steps[k.step_range.clone()]);
let mut warn_duplicate = |pre_data: &PreData| {
if let Some(pl) = pre_data.production {
let pl = &productions[pl];
diagnostics.push(
map,
DiagnosticKind::ComposeProductionOverwritten,
ad_hoc_display!("compose production has been overwritten").spanned2(pl.span),
);
}
};
let mut pre_datas_dedup = Vec::<&PreData>::new();
let mut prev_step = None;
let mut prev_len = 0;
let mut prev_production = false;
for k in &pre_datas {
let len = k.step_range.len();
if prev_production && len > prev_len {
warn_duplicate(k);
continue;
}
let step = steps[k.step_range.end - 1];
if (Some(step), len) == (prev_step, prev_len) {
if let Some(prev) = pre_datas_dedup.pop() {
warn_duplicate(prev);
}
}
prev_step = Some(step);
prev_len = len;
prev_production = k.production.is_some();
pre_datas_dedup.push(k);
}
struct Data {
step: Step,
production: Option<usize>,
num_children: u32,
parent: Option<u32>,
heap_pos: Cell<u32>,
children_heap_pos: Cell<u32>,
next_child_pos: Cell<u32>,
}
let mut datas: Vec<Data> = vec![];
let mut num_root = 0;
let mut stack: Vec<u32> = vec![];
let mut prev_len = 0;
for pre_data in pre_datas_dedup {
let len = pre_data.step_range.len();
let step = steps[pre_data.step_range.end - 1];
if len <= prev_len {
for _ in 0..prev_len - len + 1 {
assert!(stack.pop().is_some());
}
}
let parent = match stack.last() {
Some(&idx) => {
let data = &mut datas[idx as usize];
data.num_children += 1;
Some(idx)
}
_ => {
num_root += 1;
None
}
};
prev_len = len;
stack.push(datas.len() as u32);
datas.push(Data {
step,
production: pre_data.production,
num_children: 0,
parent,
heap_pos: Cell::new(0),
children_heap_pos: Cell::new(0),
next_child_pos: Cell::new(0),
});
}
let mut next_free_node_position = num_root as u32 + 1;
let mut next_root_pos = 1;
for data in &datas {
match data.parent {
Some(parent_idx) => {
let parent = &datas[parent_idx as usize];
let next_child_pos = parent.next_child_pos.get();
data.heap_pos.set(next_child_pos);
parent.next_child_pos.set(next_child_pos + 1);
}
_ => {
data.heap_pos.set(next_root_pos);
next_root_pos += 1;
}
}
data.children_heap_pos.set(next_free_node_position);
data.next_child_pos.set(next_free_node_position);
next_free_node_position += data.num_children;
}
datas.sort_unstable_by_key(|d| d.heap_pos.get());
let mut payloads = vec![];
let mut nodes = Vec::with_capacity(datas.len() + 1);
nodes.push(Node {
keysym: Default::default(),
data: NodeType::Intermediate {
range: 1..1 + num_root,
}
.serialize(),
});
for data in datas {
let ty = match data.production {
Some(idx) => {
let production = &productions[idx];
let pos = payloads.len();
payloads.push(Payload {
string: production
.val
.string
.as_ref()
.map(|s| s.as_bstr().to_string().into_boxed_str()),
keysym: production.val.keysym,
});
NodeType::Leaf { payload: pos }
}
_ => {
let lo = data.children_heap_pos.get() as usize;
let hi = lo + data.num_children as usize;
NodeType::Intermediate { range: lo..hi }
}
};
nodes.push(Node {
keysym: data.step.keysym,
data: ty.serialize(),
});
}
Self {
nodes: nodes.into_boxed_slice(),
payloads: payloads.into_boxed_slice(),
}
}
pub fn create_state(&self) -> State {
let NodeType::Intermediate { range } = self.nodes[0].deserialize() else {
unreachable!();
};
State { range }
}
pub fn feed(&self, state: &mut State, sym: Keysym) -> Option<FeedResult<'_>> {
if sym.is_modifier() {
return None;
}
let range = &self.nodes[state.range.clone()];
if let Ok(node) = range.binary_search_by_key(&sym, |n| n.keysym) {
let node = &range[node];
let res = match node.deserialize() {
NodeType::Intermediate { range } => {
state.range = range;
FeedResult::Pending
}
NodeType::Leaf { payload } => {
*state = self.create_state();
let payload = &self.payloads[payload];
FeedResult::Composed {
string: payload.string.as_deref(),
keysym: payload.keysym,
}
}
};
return Some(res);
}
if state.range.start == 1 {
return None;
}
*state = self.create_state();
Some(FeedResult::Aborted)
}
pub fn iter(&self) -> Iter<'_> {
Iter {
table: self,
stack: vec![],
child_range: vec![self.create_state().range],
}
}
pub fn format(&self) -> impl Display + use<'_> {
FormatFormat(self)
}
}
#[derive(Copy, Clone)]
pub struct MatchStep<'a> {
pub(crate) node: &'a Node,
}
impl MatchStep<'_> {
pub fn keysym(&self) -> Keysym {
self.node.keysym
}
}
#[derive(Copy, Clone)]
pub struct MatchRule<'a, 'b> {
pub(crate) steps: &'a [MatchStep<'b>],
pub(crate) payload: &'b Payload,
}
impl<'b> MatchRule<'_, 'b> {
pub fn steps(&self) -> &[MatchStep<'b>] {
self.steps
}
pub fn string(&self) -> Option<&'b str> {
self.payload.string.as_deref()
}
pub fn keysym(&self) -> Option<Keysym> {
self.payload.keysym
}
}
impl Debug for MatchRule<'_, '_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
FormatFormat(self).fmt(f)
}
}
impl Debug for MatchStep<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
FormatFormat(self).fmt(f)
}
}
#[derive(Clone, Debug)]
pub struct Iter<'a> {
table: &'a ComposeTable,
stack: Vec<MatchStep<'a>>,
child_range: Vec<Range<usize>>,
}
impl<'a> Iter<'a> {
pub fn next(&mut self) -> Option<MatchRule<'_, 'a>> {
self.stack.pop();
loop {
let mut range = self.child_range.pop()?;
let Some(idx) = range.next() else {
self.stack.pop();
continue;
};
self.child_range.push(range);
let node = &self.table.nodes[idx];
self.stack.push(MatchStep { node });
match node.deserialize() {
NodeType::Intermediate { range } => {
self.child_range.push(range);
}
NodeType::Leaf { payload } => {
let payload = &self.table.payloads[payload];
return Some(MatchRule {
steps: &self.stack,
payload,
});
}
}
}
}
}