use std::collections::HashMap;
use ratatui::text::Line;
use rustc_hash::FxBuildHasher;
use super::ast::Block;
pub(super) type BlockMap = HashMap<Block, Vec<Line<'static>>, FxBuildHasher>;
pub(super) fn is_cache_worthy(block: &Block) -> bool {
match block {
Block::Table { .. } | Block::CodeBlock { .. } => true,
Block::BlockQuote { blocks } => blocks.iter().any(is_cache_worthy),
Block::List { items, .. } => items.iter().flat_map(|it| &it.blocks).any(is_cache_worthy),
_ => false,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct RenderSettings {
pub theme_addr: usize,
pub viewport_width: usize,
pub code_wrap: bool,
pub image_max_height: usize,
pub row_striping: bool,
pub big_h1: bool,
pub syntax_highlighting: bool,
pub reflow_paragraphs: bool,
pub highlight_generation: u64,
pub highlight_retry_epoch: u64,
}
#[derive(Debug, Default)]
pub struct RenderCache {
pub(super) settings: Option<RenderSettings>,
pub(super) entries: BlockMap,
}
impl RenderCache {
pub(super) fn begin_build(&mut self, settings: RenderSettings) -> BlockMap {
if self.settings.as_ref() != Some(&settings) {
self.entries.clear();
self.settings = Some(settings);
}
std::mem::take(&mut self.entries)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn settings() -> RenderSettings {
RenderSettings {
theme_addr: 0,
viewport_width: 80,
code_wrap: false,
image_max_height: 20,
row_striping: false,
big_h1: false,
syntax_highlighting: true,
reflow_paragraphs: false,
highlight_generation: 0,
highlight_retry_epoch: 0,
}
}
#[test]
fn both_highlight_counters_clear_the_cache() {
for bump in [
|s: &mut RenderSettings| s.highlight_generation += 1,
|s: &mut RenderSettings| s.highlight_retry_epoch += 1,
] {
let mut cache = RenderCache::default();
cache.begin_build(settings());
cache
.entries
.insert(Block::HorizontalRule, vec![Line::from("x")]);
let prev = cache.begin_build(settings());
assert_eq!(prev.len(), 1, "an unchanged fingerprint must not clear");
cache.entries = prev;
let mut changed = settings();
bump(&mut changed);
let prev = cache.begin_build(changed);
assert!(prev.is_empty(), "a moved counter must clear the cache");
}
}
}