1use std::collections::BTreeMap;
2
3use derive_more::{Deref, DerefMut};
4use enum_dispatch::enum_dispatch;
5use lazy_static::lazy_static;
6use rustc_hash::FxHashMap as HashMap;
7use smol_str::SmolStr;
8
9use crate::context::CacheKey;
10
11#[enum_dispatch]
12pub trait Cache {
13 fn mark_valid(&mut self, item: SmolStr);
14
15 fn mark_valid_many(&mut self, items: impl IntoIterator<Item = SmolStr>);
16
17 fn mark_invalid(&mut self, item: SmolStr);
18
19 fn mark_invalid_many(&mut self, items: impl IntoIterator<Item = SmolStr>);
20
21 fn store_css(&mut self, key: CacheKey, value: String);
22
23 fn store_extra_css(&mut self, key: CacheKey, value: String);
24
25 fn has_seen(&self, item: &str) -> bool;
26
27 fn extra_css(&self) -> &BTreeMap<CacheKey, String>;
28
29 fn css(&self) -> &BTreeMap<CacheKey, String>;
30}
31
32#[derive(Debug, Default, Deref, DerefMut)]
33pub struct GeneratorCache {
34 pub need_cache: bool,
35 #[deref]
36 #[deref_mut]
37 pub inner: CacheInner,
38 pub state: CacheState,
39}
40
41impl GeneratorCache {
42 pub fn new(state: CacheState) -> Self {
43 let need_cache = state != CacheState::OneShot;
44 Self {
45 need_cache,
46 state,
47 inner: match need_cache {
48 true => CacheInner::Cache(CacheImpl::default()),
49 false => CacheInner::Noop(NoopCache::default()),
50 },
51 }
52 }
53}
54
55#[derive(Debug)]
56#[enum_dispatch(Cache)]
57pub enum CacheInner {
58 Noop(NoopCache),
59 Cache(CacheImpl),
60}
61
62impl Default for CacheInner {
63 fn default() -> Self {
64 Self::Noop(NoopCache::default())
65 }
66}
67
68#[derive(Debug, Default)]
69pub struct CacheImpl {
70 pub css: BTreeMap<CacheKey, String>,
71 pub groups: BTreeMap<CacheKey, String>,
72 pub valid: HashMap<SmolStr, bool>,
73}
74
75#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
76pub enum CacheState {
77 #[default]
78 OneShot,
79 FirstRun,
80 Cached,
81}
82
83impl CacheState {
84 pub fn is_cached(&self) -> bool {
85 matches!(self, Self::Cached)
86 }
87 pub fn mark_cached(&mut self) {
88 if *self == Self::FirstRun {
89 *self = Self::Cached;
90 }
91 }
92}
93
94impl Cache for CacheImpl {
95 fn css(&self) -> &BTreeMap<CacheKey, String> {
96 &self.css
97 }
98
99 fn store_css(&mut self, key: CacheKey, value: String) {
100 self.css.insert(key, value);
101 }
102
103 fn extra_css(&self) -> &BTreeMap<CacheKey, String> {
104 &self.groups
105 }
106
107 fn store_extra_css(&mut self, key: CacheKey, value: String) {
108 self.groups.insert(key, value);
109 }
110
111 fn has_seen(&self, item: &str) -> bool {
112 self.valid.get(item).copied().unwrap_or(false)
113 }
114
115 fn mark_valid(&mut self, item: SmolStr) {
116 self.valid.insert(item, true);
117 }
118
119 fn mark_valid_many(&mut self, items: impl IntoIterator<Item = SmolStr>) {
120 for item in items {
121 self.valid.insert(item, true);
122 }
123 }
124
125 fn mark_invalid(&mut self, item: SmolStr) {
126 self.valid.insert(item, false);
127 }
128
129 fn mark_invalid_many(&mut self, items: impl IntoIterator<Item = SmolStr>) {
130 for item in items {
131 self.valid.insert(item, false);
132 }
133 }
134}
135
136#[derive(Debug, Default)]
137pub struct NoopCache {
138 pub groups: BTreeMap<CacheKey, String>,
139}
140
141lazy_static! {
142 pub static ref EMPTY_MAP: BTreeMap<CacheKey, String> = BTreeMap::default();
143}
144
145impl Cache for NoopCache {
146 fn css(&self) -> &BTreeMap<CacheKey, String> {
147 &EMPTY_MAP
148 }
149
150 fn extra_css(&self) -> &BTreeMap<CacheKey, String> {
151 &self.groups
152 }
153
154 fn store_extra_css(&mut self, key: CacheKey, value: String) {
155 self.groups.insert(key, value);
156 }
157
158 fn has_seen(&self, _: &str) -> bool {
159 false
160 }
161
162 fn mark_valid(&mut self, _: SmolStr) {}
163
164 fn mark_valid_many(&mut self, _: impl IntoIterator<Item = SmolStr>) {}
165
166 fn mark_invalid(&mut self, _: SmolStr) {}
167
168 fn mark_invalid_many(&mut self, _: impl IntoIterator<Item = SmolStr>) {}
169
170 fn store_css(&mut self, _: CacheKey, _: String) {}
171}