1use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
2use std::{
3 collections::HashMap,
4 ops::{Deref, DerefMut},
5 path::PathBuf,
6 sync::Arc,
7 time::SystemTime,
8};
9use sway_error::{error::CompileError, warning::CompileWarning};
10use sway_types::{IdentUnique, ProgramId, SourceId, Spanned};
11
12use crate::{
13 decl_engine::{DeclId, DeclRef},
14 language::ty::{TyFunctionDecl, TyFunctionSig, TyModule},
15 namespace, Engines, Programs,
16};
17
18#[derive(Debug, Clone, Hash, PartialEq, Eq)]
19pub struct ModuleCacheKey {
20 pub path: Arc<PathBuf>,
21 pub include_tests: bool,
22}
23
24impl ModuleCacheKey {
25 pub fn new(path: Arc<PathBuf>, include_tests: bool) -> Self {
26 Self {
27 path,
28 include_tests,
29 }
30 }
31}
32
33#[derive(Clone, Debug)]
34pub struct ModuleCommonInfo {
35 pub path: Arc<PathBuf>,
36 pub hash: u64,
37 pub include_tests: bool,
38 pub dependencies: Vec<Arc<PathBuf>>,
39}
40
41#[derive(Clone, Debug)]
42pub struct ParsedModuleInfo {
43 pub modified_time: Option<SystemTime>,
44 pub version: Option<u64>,
45}
46
47#[derive(Clone, Debug)]
48pub struct TypedModuleInfo {
49 pub module: Arc<TyModule>,
50 pub namespace_module: Arc<namespace::Module>,
51 pub version: Option<u64>,
52}
53
54#[derive(Clone, Debug)]
55pub struct ModuleCacheEntry {
56 pub common: ModuleCommonInfo,
57 pub parsed: ParsedModuleInfo,
58 pub typed: Option<TypedModuleInfo>,
59}
60
61impl ModuleCacheEntry {
62 pub fn new(common: ModuleCommonInfo, parsed: ParsedModuleInfo) -> Self {
63 Self {
64 common,
65 parsed,
66 typed: None,
67 }
68 }
69
70 pub fn is_typed(&self) -> bool {
71 self.typed.is_some()
72 }
73
74 pub fn set_typed(&mut self, typed: TypedModuleInfo) {
75 self.typed = Some(typed);
76 }
77
78 pub fn update_common(&mut self, new_common: ModuleCommonInfo) {
79 self.common = new_common;
80 }
81
82 pub fn update_parsed(&mut self, new_parsed: ParsedModuleInfo) {
83 self.parsed = new_parsed;
84 }
85
86 pub fn update_parsed_and_common(
87 &mut self,
88 new_common: ModuleCommonInfo,
89 new_parsed: ParsedModuleInfo,
90 ) {
91 self.common = new_common;
92 self.parsed = new_parsed;
93 }
94}
95
96#[derive(Debug, Default, Clone)]
97pub struct ModuleCacheMap(HashMap<ModuleCacheKey, ModuleCacheEntry>);
98
99impl Deref for ModuleCacheMap {
100 type Target = HashMap<ModuleCacheKey, ModuleCacheEntry>;
101 fn deref(&self) -> &Self::Target {
102 &self.0
103 }
104}
105
106impl DerefMut for ModuleCacheMap {
107 fn deref_mut(&mut self) -> &mut Self::Target {
108 &mut self.0
109 }
110}
111
112impl ModuleCacheMap {
113 pub fn update_entry(
114 &mut self,
115 key: &ModuleCacheKey,
116 new_common: ModuleCommonInfo,
117 new_parsed: ParsedModuleInfo,
118 ) {
119 if let Some(entry) = self.get_mut(key) {
120 entry.update_parsed_and_common(new_common, new_parsed);
121 } else {
122 self.insert(key.clone(), ModuleCacheEntry::new(new_common, new_parsed));
123 }
124 }
125}
126
127pub type ProgramsCacheMap = HashMap<Arc<PathBuf>, ProgramsCacheEntry>;
128pub type FunctionsCacheMap = HashMap<(IdentUnique, String), FunctionCacheEntry>;
129
130#[derive(Clone, Debug)]
131pub struct ProgramsCacheEntry {
132 pub path: Arc<PathBuf>,
133 pub programs: Programs,
134 pub handler_data: (Vec<CompileError>, Vec<CompileWarning>),
135}
136
137#[derive(Clone, Debug)]
138pub struct FunctionCacheEntry {
139 pub fn_decl: DeclRef<DeclId<TyFunctionDecl>>,
140}
141
142#[derive(Debug, Default)]
143pub struct QueryEngine {
144 programs_cache: CowCache<ProgramsCacheMap>,
146 pub module_cache: CowCache<ModuleCacheMap>,
147 function_cache: CowCache<FunctionsCacheMap>,
149}
150
151impl Clone for QueryEngine {
152 fn clone(&self) -> Self {
153 Self {
154 programs_cache: CowCache::new(self.programs_cache.read().clone()),
155 module_cache: CowCache::new(self.module_cache.read().clone()),
156 function_cache: CowCache::new(self.function_cache.read().clone()),
157 }
158 }
159}
160
161impl QueryEngine {
162 pub fn update_or_insert_parsed_module_cache_entry(&self, entry: ModuleCacheEntry) {
163 let path = entry.common.path.clone();
164 let include_tests = entry.common.include_tests;
165 let key = ModuleCacheKey::new(path, include_tests);
166 let mut cache = self.module_cache.write();
167 cache.update_entry(&key, entry.common, entry.parsed);
168 }
169
170 pub fn update_typed_module_cache_entry(&self, key: &ModuleCacheKey, entry: TypedModuleInfo) {
171 let mut cache = self.module_cache.write();
172 cache.get_mut(key).unwrap().set_typed(entry);
173 }
174
175 pub fn get_programs_cache_entry(&self, path: &Arc<PathBuf>) -> Option<ProgramsCacheEntry> {
176 let cache = self.programs_cache.read();
177 cache.get(path).cloned()
178 }
179
180 pub fn insert_programs_cache_entry(&self, entry: ProgramsCacheEntry) {
181 let mut cache = self.programs_cache.write();
182 cache.insert(entry.path.clone(), entry);
183 }
184
185 pub fn get_function(
186 &self,
187 engines: &Engines,
188 ident: IdentUnique,
189 sig: TyFunctionSig,
190 ) -> Option<DeclRef<DeclId<TyFunctionDecl>>> {
191 let cache = self.function_cache.read();
192 cache
193 .get(&(ident, sig.get_type_str(engines)))
194 .map(|s| s.fn_decl.clone())
195 }
196
197 pub fn insert_function(
198 &self,
199 engines: &Engines,
200 ident: IdentUnique,
201 sig: TyFunctionSig,
202 fn_decl: DeclRef<DeclId<TyFunctionDecl>>,
203 ) {
204 let mut cache = self.function_cache.write();
205 cache.insert(
206 (ident, sig.get_type_str(engines)),
207 FunctionCacheEntry { fn_decl },
208 );
209 }
210
211 pub fn clear_module(&mut self, source_id: &SourceId) {
213 self.function_cache
214 .write()
215 .retain(|(ident, _), _| (ident.span().source_id() != Some(source_id)));
216 }
217
218 pub fn clear_program(&mut self, program_id: &ProgramId) {
220 self.function_cache.write().retain(|(ident, _), _| {
221 ident
222 .span()
223 .source_id()
224 .is_none_or(|id| id.program_id() != *program_id)
225 });
226 }
227
228 pub fn commit(&self) {
230 self.programs_cache.commit();
231 self.module_cache.commit();
232 self.function_cache.commit();
233 }
234}
235
236#[derive(Debug, Default)]
247pub struct CowCache<T: Clone> {
248 inner: Arc<RwLock<T>>,
249 local: RwLock<Option<T>>,
250}
251
252impl<T: Clone> CowCache<T> {
253 pub fn new(value: T) -> Self {
257 Self {
258 inner: Arc::new(RwLock::new(value)),
259 local: RwLock::new(None),
260 }
261 }
262
263 pub fn read(&self) -> impl Deref<Target = T> + '_ {
270 if self.local.read().is_some() {
271 ReadGuard::Local(self.local.read())
272 } else {
273 ReadGuard::Shared(self.inner.read())
274 }
275 }
276
277 pub fn write(&self) -> impl DerefMut<Target = T> + '_ {
282 let mut local = self.local.write();
283 if local.is_none() {
284 *local = Some(self.inner.read().clone());
285 }
286 WriteGuard(local)
287 }
288
289 pub fn commit(&self) {
294 if let Some(local) = self.local.write().take() {
295 *self.inner.write() = local;
296 }
297 }
298}
299
300enum ReadGuard<'a, T: Clone> {
302 Local(RwLockReadGuard<'a, Option<T>>),
303 Shared(RwLockReadGuard<'a, T>),
304}
305
306impl<T: Clone> Deref for ReadGuard<'_, T> {
307 type Target = T;
308
309 fn deref(&self) -> &Self::Target {
310 match self {
311 ReadGuard::Local(r) => r.as_ref().unwrap(),
312 ReadGuard::Shared(guard) => guard.deref(),
313 }
314 }
315}
316
317struct WriteGuard<'a, T: Clone>(RwLockWriteGuard<'a, Option<T>>);
319
320impl<T: Clone> Deref for WriteGuard<'_, T> {
321 type Target = T;
322
323 fn deref(&self) -> &Self::Target {
324 self.0.as_ref().unwrap()
325 }
326}
327
328impl<T: Clone> DerefMut for WriteGuard<'_, T> {
329 fn deref_mut(&mut self) -> &mut Self::Target {
330 self.0.as_mut().unwrap()
331 }
332}