use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use xi_rpc;
use crate::client::Client;
pub type Token = usize;
type Width = f64;
type StyleId = usize;
pub struct WidthCache {
m: HashMap<WidthCacheKey<'static>, Token>,
widths: Vec<Width>,
}
#[derive(Eq, PartialEq, Hash)]
struct WidthCacheKey<'a> {
id: StyleId,
s: Cow<'a, str>,
}
pub struct WidthBatchReq<'a> {
cache: &'a mut WidthCache,
pending_tok: Token,
req: Vec<WidthReq>,
req_toks: Vec<Vec<Token>>,
req_ids: BTreeMap<StyleId, Token>,
}
#[derive(Serialize, Deserialize)]
pub struct WidthReq {
pub id: StyleId,
pub strings: Vec<String>,
}
pub type WidthResponse = Vec<Vec<Width>>;
pub trait WidthMeasure {
fn measure_width(&self, request: &[WidthReq]) -> Result<WidthResponse, xi_rpc::Error>;
}
impl WidthMeasure for Client {
fn measure_width(&self, request: &[WidthReq]) -> Result<WidthResponse, xi_rpc::Error> {
Client::measure_width(self, request)
}
}
pub struct CodepointMono;
impl WidthMeasure for CodepointMono {
fn measure_width(&self, request: &[WidthReq]) -> Result<WidthResponse, xi_rpc::Error> {
Ok(request
.iter()
.map(|r| r.strings.iter().map(|s| s.chars().count() as f64).collect())
.collect())
}
}
impl WidthCache {
pub fn new() -> WidthCache {
WidthCache { m: HashMap::new(), widths: Vec::new() }
}
pub(crate) fn len(&self) -> usize {
self.m.len()
}
pub fn resolve(&self, tok: Token) -> Width {
self.widths[tok]
}
pub fn batch_req(self: &mut WidthCache) -> WidthBatchReq {
let pending_tok = self.widths.len();
WidthBatchReq {
cache: self,
pending_tok,
req: Vec::new(),
req_toks: Vec::new(),
req_ids: BTreeMap::new(),
}
}
}
impl<'a> WidthBatchReq<'a> {
pub fn request(&mut self, id: StyleId, s: &str) -> Token {
let key = WidthCacheKey { id, s: Cow::Borrowed(s) };
if let Some(tok) = self.cache.m.get(&key) {
return *tok;
}
let key = WidthCacheKey { id, s: Cow::Owned(s.to_owned()) };
let req = &mut self.req;
let req_toks = &mut self.req_toks;
let id_off = *self.req_ids.entry(id).or_insert_with(|| {
let id_off = req.len();
req.push(WidthReq { id, strings: Vec::new() });
req_toks.push(Vec::new());
id_off
});
req[id_off].strings.push(s.to_owned());
let tok = self.pending_tok;
self.cache.m.insert(key, tok);
self.pending_tok += 1;
req_toks[id_off].push(tok);
tok
}
pub fn resolve_pending<T: WidthMeasure + ?Sized>(
&mut self,
handler: &T,
) -> Result<(), xi_rpc::Error> {
if self.pending_tok > self.cache.widths.len() {
self.cache.widths.resize(self.pending_tok, 0.0);
let widths = handler.measure_width(&self.req)?;
for (w, t) in widths.iter().zip(self.req_toks.iter()) {
for (width, tok) in w.iter().zip(t.iter()) {
self.cache.widths[*tok] = *width;
}
}
}
Ok(())
}
}