use std::collections::BTreeSet;
use std::fmt;
use mathtex_editor_core::{Document, Editor, MAX_HOST_TOKEN};
use crate::UndoStack;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TokenError {
TooLarge(u32),
Exhausted,
}
impl fmt::Display for TokenError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TokenError::TooLarge(t) => write!(f, "host box token {t} is above {MAX_HOST_TOKEN}"),
TokenError::Exhausted => write!(f, "every host box token up to {MAX_HOST_TOKEN} is taken"),
}
}
}
impl std::error::Error for TokenError {}
#[derive(Debug, Clone)]
pub struct TokenRegistry {
next: u32,
reserved: BTreeSet<u32>,
}
impl Default for TokenRegistry {
fn default() -> Self {
Self::new()
}
}
impl TokenRegistry {
pub fn new() -> Self {
Self { next: 1, reserved: BTreeSet::new() }
}
pub fn mint(&mut self) -> Result<u32, TokenError> {
while self.next <= MAX_HOST_TOKEN {
let token = self.next;
self.next += 1;
if !self.reserved.remove(&token) {
return Ok(token);
}
}
Err(TokenError::Exhausted)
}
pub fn reserve(&mut self, token: u32) -> Result<(), TokenError> {
if token > MAX_HOST_TOKEN {
return Err(TokenError::TooLarge(token));
}
if token >= self.next {
self.reserved.insert(token);
}
Ok(())
}
pub fn reserve_document(&mut self, doc: &Document) {
for token in doc.host_tokens() {
let _ = self.reserve(token);
}
}
pub fn remint(&mut self, doc: &mut Document) -> Result<Vec<(u32, u32)>, TokenError> {
let mut pairs = Vec::new();
let mut failed = None;
doc.map_host_tokens(|old| match self.mint() {
Ok(new) => {
pairs.push((old, new));
new
}
Err(e) => {
failed = Some(e);
old
}
});
match failed {
Some(e) => Err(e),
None => Ok(pairs),
}
}
pub fn live(editor: &Editor, history: &UndoStack, clipboard: Option<&Document>) -> BTreeSet<u32> {
let mut live = editor.document().host_tokens();
for snapshot in history.snapshots() {
live.extend(snapshot.document.host_tokens());
}
if let Some(doc) = clipboard {
live.extend(doc.host_tokens());
}
live
}
}