Skip to main content

mathtex_editor_session/
tokens.rs

1use std::collections::BTreeSet;
2use std::fmt;
3
4use mathtex_editor_core::{Document, Editor, MAX_HOST_TOKEN};
5
6use crate::UndoStack;
7
8/// Why a host box token cannot be used or minted.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum TokenError {
11    /// The token is above [`MAX_HOST_TOKEN`], TeX cannot read it back from `\hostbox{N}`.
12    TooLarge(u32),
13    /// Every token up to [`MAX_HOST_TOKEN`] has been handed out.
14    Exhausted,
15}
16
17impl fmt::Display for TokenError {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            TokenError::TooLarge(t) => write!(f, "host box token {t} is above {MAX_HOST_TOKEN}"),
21            TokenError::Exhausted => write!(f, "every host box token up to {MAX_HOST_TOKEN} is taken"),
22        }
23    }
24}
25
26impl std::error::Error for TokenError {}
27
28/// Hands out host box tokens that were never minted or reserved before, from 1 up to [`MAX_HOST_TOKEN`].
29#[derive(Debug, Clone)]
30pub struct TokenRegistry {
31    next: u32,
32    /// Reserved tokens at or above `next`, the ones below it can never be minted again anyway.
33    reserved: BTreeSet<u32>,
34}
35
36impl Default for TokenRegistry {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl TokenRegistry {
43    /// A registry that has handed out nothing.
44    pub fn new() -> Self {
45        Self { next: 1, reserved: BTreeSet::new() }
46    }
47
48    /// A fresh token.
49    pub fn mint(&mut self) -> Result<u32, TokenError> {
50        while self.next <= MAX_HOST_TOKEN {
51            let token = self.next;
52            self.next += 1;
53            if !self.reserved.remove(&token) {
54                return Ok(token);
55            }
56        }
57        Err(TokenError::Exhausted)
58    }
59
60    /// Mark a token the host chose itself as taken so it is never minted.
61    pub fn reserve(&mut self, token: u32) -> Result<(), TokenError> {
62        if token > MAX_HOST_TOKEN {
63            return Err(TokenError::TooLarge(token));
64        }
65        if token >= self.next {
66            self.reserved.insert(token);
67        }
68        Ok(())
69    }
70
71    /// Reserve every token in a document, tokens above the limit are left to [`Document::validate`].
72    pub fn reserve_document(&mut self, doc: &Document) {
73        for token in doc.host_tokens() {
74            let _ = self.reserve(token);
75        }
76    }
77
78    /// Give every host box in `doc` its own fresh token and return `(old, new)` per box in document order.
79    pub fn remint(&mut self, doc: &mut Document) -> Result<Vec<(u32, u32)>, TokenError> {
80        let mut pairs = Vec::new();
81        let mut failed = None;
82        doc.map_host_tokens(|old| match self.mint() {
83            Ok(new) => {
84                pairs.push((old, new));
85                new
86            }
87            Err(e) => {
88                failed = Some(e);
89                old
90            }
91        });
92        match failed {
93            Some(e) => Err(e),
94            None => Ok(pairs),
95        }
96    }
97
98    /// Tokens the document, the history, or the clipboard still reference, any other token's content is dead.
99    pub fn live(editor: &Editor, history: &UndoStack, clipboard: Option<&Document>) -> BTreeSet<u32> {
100        let mut live = editor.document().host_tokens();
101        for snapshot in history.snapshots() {
102            live.extend(snapshot.document.host_tokens());
103        }
104        if let Some(doc) = clipboard {
105            live.extend(doc.host_tokens());
106        }
107        live
108    }
109}