xi_core_lib/
width_cache.rs1use std::borrow::Cow;
18use std::collections::{BTreeMap, HashMap};
19
20use xi_rpc;
21
22use crate::client::Client;
23
24pub type Token = usize;
29
30type Width = f64;
32
33type StyleId = usize;
34
35pub struct WidthCache {
36 m: HashMap<WidthCacheKey<'static>, Token>,
38 widths: Vec<Width>,
39}
40
41#[derive(Eq, PartialEq, Hash)]
42struct WidthCacheKey<'a> {
43 id: StyleId,
44 s: Cow<'a, str>,
45}
46
47pub struct WidthBatchReq<'a> {
50 cache: &'a mut WidthCache,
51 pending_tok: Token,
52 req: Vec<WidthReq>,
53 req_toks: Vec<Vec<Token>>,
54 req_ids: BTreeMap<StyleId, Token>,
56}
57
58#[derive(Serialize, Deserialize)]
61pub struct WidthReq {
62 pub id: StyleId,
63 pub strings: Vec<String>,
64}
65
66pub type WidthResponse = Vec<Vec<Width>>;
68
69pub trait WidthMeasure {
73 fn measure_width(&self, request: &[WidthReq]) -> Result<WidthResponse, xi_rpc::Error>;
74}
75
76impl WidthMeasure for Client {
77 fn measure_width(&self, request: &[WidthReq]) -> Result<WidthResponse, xi_rpc::Error> {
78 Client::measure_width(self, request)
79 }
80}
81
82pub struct CodepointMono;
84
85impl WidthMeasure for CodepointMono {
86 fn measure_width(&self, request: &[WidthReq]) -> Result<WidthResponse, xi_rpc::Error> {
88 Ok(request
89 .iter()
90 .map(|r| r.strings.iter().map(|s| s.chars().count() as f64).collect())
91 .collect())
92 }
93}
94
95impl WidthCache {
96 pub fn new() -> WidthCache {
97 WidthCache { m: HashMap::new(), widths: Vec::new() }
98 }
99
100 pub(crate) fn len(&self) -> usize {
102 self.m.len()
103 }
104
105 pub fn resolve(&self, tok: Token) -> Width {
107 self.widths[tok]
108 }
109
110 pub fn batch_req(self: &mut WidthCache) -> WidthBatchReq {
112 let pending_tok = self.widths.len();
113 WidthBatchReq {
114 cache: self,
115 pending_tok,
116 req: Vec::new(),
117 req_toks: Vec::new(),
118 req_ids: BTreeMap::new(),
119 }
120 }
121}
122
123impl<'a> WidthBatchReq<'a> {
124 pub fn request(&mut self, id: StyleId, s: &str) -> Token {
126 let key = WidthCacheKey { id, s: Cow::Borrowed(s) };
127 if let Some(tok) = self.cache.m.get(&key) {
128 return *tok;
129 }
130 let key = WidthCacheKey { id, s: Cow::Owned(s.to_owned()) };
132 let req = &mut self.req;
133 let req_toks = &mut self.req_toks;
134 let id_off = *self.req_ids.entry(id).or_insert_with(|| {
135 let id_off = req.len();
136 req.push(WidthReq { id, strings: Vec::new() });
137 req_toks.push(Vec::new());
138 id_off
139 });
140 req[id_off].strings.push(s.to_owned());
143 let tok = self.pending_tok;
144 self.cache.m.insert(key, tok);
145 self.pending_tok += 1;
146 req_toks[id_off].push(tok);
147 tok
148 }
149
150 pub fn resolve_pending<T: WidthMeasure + ?Sized>(
153 &mut self,
154 handler: &T,
155 ) -> Result<(), xi_rpc::Error> {
156 if self.pending_tok > self.cache.widths.len() {
159 self.cache.widths.resize(self.pending_tok, 0.0);
160 let widths = handler.measure_width(&self.req)?;
161 for (w, t) in widths.iter().zip(self.req_toks.iter()) {
162 for (width, tok) in w.iter().zip(t.iter()) {
163 self.cache.widths[*tok] = *width;
164 }
165 }
166 }
167 Ok(())
168 }
169}