1#[cfg(test)]
2#[path = "test.rs"]
3mod test;
4
5use std::ops::{Deref, DerefMut};
6use std::sync::Arc;
7
8use bincode::error::EncodeError;
9use cairo_lang_defs as defs;
10use cairo_lang_defs::cache::{
11 CachedCrateMetadata, DefCacheLoadingData, DefCacheSavingContext, LanguageElementCached,
12 SyntaxStablePtrIdCached,
13};
14use cairo_lang_defs::db::DefsGroup;
15use cairo_lang_defs::diagnostic_utils::StableLocation;
16use cairo_lang_defs::ids::{
17 FreeFunctionLongId, FunctionWithBodyId, ImplFunctionLongId, TraitFunctionLongId,
18};
19use cairo_lang_diagnostics::{DiagnosticAdded, Maybe, skip_diagnostic};
20use cairo_lang_filesystem::db::FilesGroup;
21use cairo_lang_filesystem::ids::CrateId;
22use cairo_lang_semantic::cache::{
23 ConcreteEnumCached, ConcreteVariantCached, ConstValueIdCached, ExprVarMemberPathCached,
24 ImplIdCached, MatchArmSelectorCached, SemanticCacheLoadingData, SemanticCacheSavingContext,
25 SemanticCacheSavingData, SemanticConcreteFunctionWithBodyCached, SemanticFunctionIdCached,
26 TypeIdCached, generate_crate_def_cache, generate_crate_semantic_cache,
27};
28use cairo_lang_semantic::db::SemanticGroup;
29use cairo_lang_semantic::expr::inference::InferenceError;
30use cairo_lang_semantic::items::function_with_body::FunctionWithBodySemantic;
31use cairo_lang_semantic::items::imp::ImplSemantic;
32use cairo_lang_semantic::items::macro_call::module_macro_modules;
33use cairo_lang_semantic::items::trt::TraitSemantic;
34use cairo_lang_semantic::types::TypeInfo;
35use cairo_lang_syntax::node::TypedStablePtr;
36use cairo_lang_syntax::node::ast::{ExprPtr, FunctionWithBodyPtr, TraitItemFunctionPtr};
37use cairo_lang_utils::Intern;
38use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
39use id_arena::Arena;
40use itertools::chain;
41use salsa::Database;
42use serde::{Deserialize, Serialize};
43use thiserror::Error;
44
45use crate::blocks::BlocksBuilder;
46use crate::ids::{
47 FunctionId, FunctionLongId, GeneratedFunction, GeneratedFunctionKey, LocationId, LoweredParam,
48 Signature,
49};
50use crate::lower::{MultiLowering, lower_semantic_function};
51use crate::objects::{
52 BlockId, MatchExternInfo, Statement, StatementCall, StatementConst, StatementStructDestructure,
53 VariableId,
54};
55use crate::{
56 Block, BlockEnd, Location, Lowered, MatchArm, MatchEnumInfo, MatchEnumValue, MatchInfo,
57 StatementDesnap, StatementEnumConstruct, StatementSnapshot, StatementStructConstruct,
58 VarRemapping, VarUsage, Variable,
59};
60
61type LookupCache = (CacheLookups, Vec<(DefsFunctionWithBodyIdCached, MultiLoweringCached)>);
62
63pub fn load_cached_crate_functions<'db>(
65 db: &'db dyn Database,
66 crate_id: CrateId<'db>,
67) -> Option<OrderedHashMap<defs::ids::FunctionWithBodyId<'db>, MultiLowering<'db>>> {
68 let blob_id = db.crate_config(crate_id)?.cache_file?;
69 let Some(content) = db.blob_content(blob_id) else {
70 return Default::default();
71 };
72
73 let semantic_loading_data = db.cached_crate_semantic_data(crate_id)?.loading_data;
74
75 let def_size = usize::from_be_bytes(content[..8].try_into().unwrap()); let semantic_start = 8 + def_size;
77 let semantic_size =
78 usize::from_be_bytes(content[semantic_start..semantic_start + 8].try_into().unwrap()); let lowering_start = semantic_start + semantic_size + 8;
81 let lowering_size =
82 usize::from_be_bytes(content[lowering_start..lowering_start + 8].try_into().unwrap()); let content = &content[lowering_start + 8..lowering_start + 8 + lowering_size];
85
86 let ((lookups, lowerings), _): (LookupCache, _) =
87 bincode::serde::decode_from_slice(content, bincode::config::standard()).unwrap_or_else(
88 |e| {
89 panic!(
90 "failed to deserialize lookup cache for crate `{}`: {e}",
91 crate_id.long(db).name().long(db),
92 )
93 },
94 );
95
96 let mut ctx = CacheLoadingContext::new(db, lookups, semantic_loading_data);
99
100 Some(
101 lowerings
102 .into_iter()
103 .map(|(function_id, lowering)| {
104 let function_id =
105 function_id.embed(&ctx.semantic_loading_data.defs_loading_data, ctx.db);
106
107 let lowering = lowering.embed(&mut ctx);
108 (function_id, lowering)
109 })
110 .collect::<OrderedHashMap<_, _>>(),
111 )
112}
113
114#[derive(Debug, Error)]
115pub enum CrateCacheError {
116 #[error("Failed compilation of crate.")]
117 CompilationFailed,
118 #[error("Cache encoding failed: {0}")]
119 EncodingError(#[from] EncodeError),
120}
121
122impl From<DiagnosticAdded> for CrateCacheError {
123 fn from(_e: DiagnosticAdded) -> Self {
124 Self::CompilationFailed
125 }
126}
127
128pub fn generate_crate_cache<'db>(
130 db: &'db dyn Database,
131 crate_id: CrateId<'db>,
132) -> Result<Vec<u8>, CrateCacheError> {
133 let modules = db.crate_modules(crate_id);
134 let mut function_ids = Vec::new();
135 for module_id in modules.iter() {
136 for module_id in chain!([module_id], module_macro_modules(db, true, *module_id)) {
137 for free_func in db.module_free_functions_ids(*module_id)?.iter() {
138 function_ids.push(FunctionWithBodyId::Free(*free_func));
139 }
140 for impl_id in db.module_impls_ids(*module_id)?.iter() {
141 for impl_func in db.impl_functions(*impl_id)?.values() {
142 function_ids.push(FunctionWithBodyId::Impl(*impl_func));
143 }
144 }
145 for trait_id in db.module_traits_ids(*module_id)?.iter() {
146 for trait_func in db.trait_functions(*trait_id)?.values() {
147 function_ids.push(FunctionWithBodyId::Trait(*trait_func));
148 }
149 }
150 for trait_id in db.module_traits_ids(*module_id)?.iter() {
151 for trait_func in db.trait_functions(*trait_id)?.values() {
152 function_ids.push(FunctionWithBodyId::Trait(*trait_func));
153 }
154 }
155 }
156 }
157
158 let mut ctx = CacheSavingContext::new(db, crate_id);
159
160 let def_cache = generate_crate_def_cache(db, crate_id, &mut ctx.semantic_ctx.defs_ctx)?;
161 let semantic_cache = generate_crate_semantic_cache(crate_id, &mut ctx.semantic_ctx)?;
162
163 let cached = function_ids
164 .iter()
165 .filter_map(|id| {
166 db.function_body(*id).ok()?;
167 let multi = match lower_semantic_function(db, *id).map(Arc::new) {
168 Ok(multi) => multi,
169 Err(err) => return Some(Err(err)),
170 };
171
172 Some(Ok((
173 DefsFunctionWithBodyIdCached::new(*id, &mut ctx.semantic_ctx),
174 MultiLoweringCached::new((*multi).clone(), &mut ctx),
175 )))
176 })
177 .collect::<Maybe<Vec<_>>>()?;
178
179 let mut artifact = Vec::<u8>::new();
180
181 let def = bincode::serde::encode_to_vec(
182 &(CachedCrateMetadata::new(crate_id, db), def_cache, &ctx.semantic_ctx.defs_ctx.lookups),
183 bincode::config::standard(),
184 )?;
185 artifact.extend(def.len().to_be_bytes());
186 artifact.extend(def);
187
188 let semantic = bincode::serde::encode_to_vec(
189 &(semantic_cache, &ctx.semantic_ctx.lookups),
190 bincode::config::standard(),
191 )?;
192 artifact.extend(semantic.len().to_be_bytes());
193 artifact.extend(semantic);
194
195 let lowered =
196 bincode::serde::encode_to_vec(&(&ctx.lookups, cached), bincode::config::standard())?;
197 artifact.extend(lowered.len().to_be_bytes());
198 artifact.extend(lowered);
199
200 Ok(artifact)
201}
202
203struct CacheLoadingContext<'db> {
205 lowered_variables_id: Vec<VariableId>,
207 db: &'db dyn Database,
208
209 data: CacheLoadingData<'db>,
211
212 semantic_loading_data: Arc<SemanticCacheLoadingData<'db>>,
213}
214
215impl<'db> CacheLoadingContext<'db> {
216 fn new(
217 db: &'db dyn Database,
218 lookups: CacheLookups,
219 semantic_loading_data: Arc<SemanticCacheLoadingData<'db>>,
220 ) -> Self {
221 Self {
222 lowered_variables_id: Vec::new(),
223 db,
224 data: CacheLoadingData {
225 function_ids: OrderedHashMap::default(),
226 location_ids: OrderedHashMap::default(),
227 lookups,
228 },
229 semantic_loading_data,
230 }
231 }
232}
233
234impl<'db> Deref for CacheLoadingContext<'db> {
235 type Target = CacheLoadingData<'db>;
236
237 fn deref(&self) -> &Self::Target {
238 &self.data
239 }
240}
241impl<'db> DerefMut for CacheLoadingContext<'db> {
242 fn deref_mut(&mut self) -> &mut Self::Target {
243 &mut self.data
244 }
245}
246
247struct CacheLoadingData<'db> {
249 function_ids: OrderedHashMap<FunctionIdCached, FunctionId<'db>>,
250 location_ids: OrderedHashMap<LocationIdCached, LocationId<'db>>,
251 lookups: CacheLookups,
252}
253impl Deref for CacheLoadingData<'_> {
254 type Target = CacheLookups;
255
256 fn deref(&self) -> &Self::Target {
257 &self.lookups
258 }
259}
260impl DerefMut for CacheLoadingData<'_> {
261 fn deref_mut(&mut self) -> &mut Self::Target {
262 &mut self.lookups
263 }
264}
265
266struct CacheSavingContext<'db> {
268 db: &'db dyn Database,
269 data: CacheSavingData<'db>,
270 semantic_ctx: SemanticCacheSavingContext<'db>,
271}
272impl<'db> Deref for CacheSavingContext<'db> {
273 type Target = CacheSavingData<'db>;
274
275 fn deref(&self) -> &Self::Target {
276 &self.data
277 }
278}
279impl DerefMut for CacheSavingContext<'_> {
280 fn deref_mut(&mut self) -> &mut Self::Target {
281 &mut self.data
282 }
283}
284impl<'db> CacheSavingContext<'db> {
285 fn new(db: &'db dyn Database, self_crate_id: CrateId<'db>) -> Self {
286 Self {
287 db,
288 data: CacheSavingData::default(),
289 semantic_ctx: SemanticCacheSavingContext {
290 db,
291 data: SemanticCacheSavingData::default(),
292 defs_ctx: DefCacheSavingContext::new(db, self_crate_id),
293 },
294 }
295 }
296}
297
298#[derive(Default)]
300struct CacheSavingData<'db> {
301 function_ids: OrderedHashMap<FunctionId<'db>, FunctionIdCached>,
302 location_ids: OrderedHashMap<LocationId<'db>, LocationIdCached>,
303 lookups: CacheLookups,
304}
305impl<'db> Deref for CacheSavingData<'db> {
306 type Target = CacheLookups;
307
308 fn deref(&self) -> &Self::Target {
309 &self.lookups
310 }
311}
312impl<'db> DerefMut for CacheSavingData<'db> {
313 fn deref_mut(&mut self) -> &mut Self::Target {
314 &mut self.lookups
315 }
316}
317
318#[derive(Serialize, Deserialize, Default)]
320struct CacheLookups {
321 function_ids_lookup: Vec<FunctionCached>,
322 location_ids_lookup: Vec<LocationCached>,
323}
324
325#[derive(Serialize, Deserialize, Hash, Eq, PartialEq)]
328enum DefsFunctionWithBodyIdCached {
329 Free(LanguageElementCached),
330 Impl(LanguageElementCached),
331 Trait(LanguageElementCached),
332}
333impl DefsFunctionWithBodyIdCached {
334 fn new<'db>(
335 id: defs::ids::FunctionWithBodyId<'db>,
336 ctx: &mut SemanticCacheSavingContext<'db>,
337 ) -> Self {
338 match id {
339 defs::ids::FunctionWithBodyId::Free(id) => DefsFunctionWithBodyIdCached::Free(
340 LanguageElementCached::new(id, &mut ctx.defs_ctx),
341 ),
342 defs::ids::FunctionWithBodyId::Impl(id) => DefsFunctionWithBodyIdCached::Impl(
343 LanguageElementCached::new(id, &mut ctx.defs_ctx),
344 ),
345 defs::ids::FunctionWithBodyId::Trait(id) => DefsFunctionWithBodyIdCached::Trait(
346 LanguageElementCached::new(id, &mut ctx.defs_ctx),
347 ),
348 }
349 }
350
351 fn embed<'db>(
352 self,
353 defs_loading_data: &Arc<DefCacheLoadingData<'db>>,
354 db: &'db dyn Database,
355 ) -> defs::ids::FunctionWithBodyId<'db> {
356 match self {
357 DefsFunctionWithBodyIdCached::Free(id) => {
358 let (module_id, function_stable_ptr) = id.get_embedded(defs_loading_data);
359 defs::ids::FunctionWithBodyId::Free(
360 FreeFunctionLongId(module_id, FunctionWithBodyPtr(function_stable_ptr))
361 .intern(db),
362 )
363 }
364 DefsFunctionWithBodyIdCached::Impl(id) => {
365 let (module_id, function_stable_ptr) = id.get_embedded(defs_loading_data);
366 defs::ids::FunctionWithBodyId::Impl(
367 ImplFunctionLongId(module_id, FunctionWithBodyPtr(function_stable_ptr))
368 .intern(db),
369 )
370 }
371 DefsFunctionWithBodyIdCached::Trait(id) => {
372 let (module_id, function_stable_ptr) = id.get_embedded(defs_loading_data);
373 defs::ids::FunctionWithBodyId::Trait(
374 TraitFunctionLongId(module_id, TraitItemFunctionPtr(function_stable_ptr))
375 .intern(db),
376 )
377 }
378 }
379 }
380}
381
382#[derive(Serialize, Deserialize)]
384struct MultiLoweringCached {
385 main_lowering: LoweredCached,
386 generated_lowerings: Vec<(GeneratedFunctionKeyCached, LoweredCached)>,
387}
388impl MultiLoweringCached {
389 fn new<'db>(lowering: MultiLowering<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
390 Self {
391 main_lowering: LoweredCached::new(lowering.main_lowering, ctx),
392 generated_lowerings: lowering
393 .generated_lowerings
394 .into_iter()
395 .map(|(key, lowered)| {
396 (GeneratedFunctionKeyCached::new(key, ctx), LoweredCached::new(lowered, ctx))
397 })
398 .collect(),
399 }
400 }
401 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MultiLowering<'db> {
402 MultiLowering {
403 main_lowering: self.main_lowering.embed(ctx),
404 generated_lowerings: self
405 .generated_lowerings
406 .into_iter()
407 .map(|(key, lowered)| (key.embed(ctx), lowered.embed(ctx)))
408 .collect(),
409 }
410 }
411}
412
413#[derive(Serialize, Deserialize)]
414struct LoweredCached {
415 signature: LoweredSignatureCached,
417 variables: Vec<VariableCached>,
419 blocks: Vec<BlockCached>,
421 parameters: Vec<usize>,
423}
424impl LoweredCached {
425 fn new<'db>(lowered: Lowered<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
426 Self {
427 signature: LoweredSignatureCached::new(lowered.signature, ctx),
428 variables: lowered
429 .variables
430 .into_iter()
431 .map(|var| VariableCached::new(var.1, ctx))
432 .collect(),
433 blocks: lowered
434 .blocks
435 .iter()
436 .map(|block: (BlockId, &Block<'_>)| BlockCached::new(block.1.clone(), ctx))
437 .collect(),
438 parameters: lowered.parameters.iter().map(|var| var.index()).collect(),
439 }
440 }
441 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Lowered<'db> {
442 ctx.lowered_variables_id.clear();
443 let mut variables = Arena::new();
444 for var in self.variables {
445 let id = variables.alloc(var.embed(ctx));
446 ctx.lowered_variables_id.push(id);
447 }
448
449 let mut blocks = BlocksBuilder::new();
450 for block in self.blocks {
451 blocks.alloc(block.embed(ctx));
452 }
453 Lowered {
454 diagnostics: Default::default(),
455 signature: self.signature.embed(ctx),
456 variables,
457 blocks: blocks.build().unwrap(),
458 parameters: self
459 .parameters
460 .into_iter()
461 .map(|var_id| ctx.lowered_variables_id[var_id])
462 .collect(),
463 }
464 }
465}
466
467#[derive(Serialize, Deserialize)]
468struct LoweredSignatureCached {
469 params: Vec<LoweredParamCached>,
471 extra_rets: Vec<ExprVarMemberPathCached>,
473 return_type: TypeIdCached,
475 implicits: Vec<TypeIdCached>,
477 panicable: bool,
479 location: LocationIdCached,
480}
481impl LoweredSignatureCached {
482 fn new<'db>(signature: Signature<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
483 Self {
484 params: signature
485 .params
486 .iter()
487 .map(|param| LoweredParamCached::new(param, ctx))
488 .collect(),
489 extra_rets: signature
490 .extra_rets
491 .into_iter()
492 .map(|var| ExprVarMemberPathCached::new(var, &mut ctx.semantic_ctx))
493 .collect(),
494
495 return_type: TypeIdCached::new(signature.return_type, &mut ctx.semantic_ctx),
496 implicits: signature
497 .implicits
498 .into_iter()
499 .map(|ty| TypeIdCached::new(ty, &mut ctx.semantic_ctx))
500 .collect(),
501 panicable: signature.panicable,
502 location: LocationIdCached::new(signature.location, ctx),
503 }
504 }
505 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Signature<'db> {
506 Signature {
507 params: self.params.into_iter().map(|var| var.embed(ctx)).collect(),
508 extra_rets: self
509 .extra_rets
510 .into_iter()
511 .map(|var| var.get_embedded(&ctx.semantic_loading_data, ctx.db))
512 .collect(),
513 return_type: self.return_type.get_embedded(&ctx.semantic_loading_data),
514 implicits: self
515 .implicits
516 .into_iter()
517 .map(|ty| ty.get_embedded(&ctx.semantic_loading_data))
518 .collect(),
519 panicable: self.panicable,
520 location: self.location.embed(ctx),
521 }
522 }
523}
524
525#[derive(Serialize, Deserialize)]
526struct LoweredParamCached {
527 ty: TypeIdCached,
528 stable_ptr: SyntaxStablePtrIdCached,
529}
530impl LoweredParamCached {
531 fn new<'db>(param: &LoweredParam<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
532 Self {
533 ty: TypeIdCached::new(param.ty, &mut ctx.semantic_ctx),
534 stable_ptr: SyntaxStablePtrIdCached::new(
535 param.stable_ptr.untyped(),
536 &mut ctx.semantic_ctx.defs_ctx,
537 ),
538 }
539 }
540 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> LoweredParam<'db> {
541 LoweredParam {
542 ty: self.ty.get_embedded(&ctx.semantic_loading_data),
543 stable_ptr: ExprPtr(
544 self.stable_ptr.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
545 ),
546 }
547 }
548}
549#[derive(Serialize, Deserialize)]
550struct VariableCached {
551 droppable: Option<ImplIdCached>,
552 copyable: Option<ImplIdCached>,
554 destruct_impl: Option<ImplIdCached>,
556 panic_destruct_impl: Option<ImplIdCached>,
558 ty: TypeIdCached,
560 location: LocationIdCached,
561}
562impl VariableCached {
563 fn new<'db>(variable: Variable<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
564 let TypeInfo { droppable, copyable, destruct_impl, panic_destruct_impl } = variable.info;
565 Self {
566 droppable: droppable
567 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
568 .ok(),
569 copyable: copyable
570 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
571 .ok(),
572 destruct_impl: destruct_impl
573 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
574 .ok(),
575 panic_destruct_impl: panic_destruct_impl
576 .map(|impl_id| ImplIdCached::new(impl_id, &mut ctx.semantic_ctx))
577 .ok(),
578 ty: TypeIdCached::new(variable.ty, &mut ctx.semantic_ctx),
579 location: LocationIdCached::new(variable.location, ctx),
580 }
581 }
582 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Variable<'db> {
583 Variable {
584 ty: self.ty.get_embedded(&ctx.semantic_loading_data),
585 location: self.location.embed(ctx),
586 info: TypeInfo {
587 droppable: self
588 .droppable
589 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
590 .ok_or(InferenceError::Reported(skip_diagnostic())),
591 copyable: self
592 .copyable
593 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
594 .ok_or(InferenceError::Reported(skip_diagnostic())),
595 destruct_impl: self
596 .destruct_impl
597 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
598 .ok_or(InferenceError::Reported(skip_diagnostic())),
599 panic_destruct_impl: self
600 .panic_destruct_impl
601 .map(|impl_id| impl_id.get_embedded(&ctx.semantic_loading_data))
602 .ok_or(InferenceError::Reported(skip_diagnostic())),
603 },
604 }
605 }
606}
607
608#[derive(Serialize, Deserialize)]
609struct VarUsageCached {
610 var_id: usize,
612 location: LocationIdCached,
614}
615
616impl VarUsageCached {
617 fn new<'db>(var_usage: VarUsage<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
618 Self {
619 var_id: var_usage.var_id.index(),
620 location: LocationIdCached::new(var_usage.location, ctx),
621 }
622 }
623 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> VarUsage<'db> {
624 VarUsage {
625 var_id: ctx.lowered_variables_id[self.var_id],
626 location: self.location.embed(ctx),
627 }
628 }
629}
630
631#[derive(Serialize, Deserialize)]
632struct BlockCached {
633 statements: Vec<StatementCached>,
635 end: BlockEndCached,
637}
638impl BlockCached {
639 fn new<'db>(block: Block<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
640 Self {
641 statements: block
642 .statements
643 .into_iter()
644 .map(|stmt| StatementCached::new(stmt, ctx))
645 .collect(),
646 end: BlockEndCached::new(block.end, ctx),
647 }
648 }
649 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Block<'db> {
650 Block {
651 statements: self.statements.into_iter().map(|stmt| stmt.embed(ctx)).collect(),
652 end: self.end.embed(ctx),
653 }
654 }
655}
656#[derive(Serialize, Deserialize)]
657enum BlockEndCached {
658 NotSet,
661 Return(Vec<VarUsageCached>, LocationIdCached),
663 Panic(VarUsageCached),
665 Goto(usize, VarRemappingCached),
667 Match {
668 info: MatchInfoCached,
669 },
670}
671impl BlockEndCached {
672 fn new<'db>(block_end: BlockEnd<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
673 match block_end {
674 BlockEnd::Return(returns, location) => BlockEndCached::Return(
675 returns.iter().map(|var| VarUsageCached::new(*var, ctx)).collect(),
676 LocationIdCached::new(location, ctx),
677 ),
678 BlockEnd::Panic(data) => BlockEndCached::Panic(VarUsageCached::new(data, ctx)),
679 BlockEnd::Goto(block_id, remapping) => {
680 BlockEndCached::Goto(block_id.0, VarRemappingCached::new(remapping, ctx))
681 }
682 BlockEnd::NotSet => BlockEndCached::NotSet,
683 BlockEnd::Match { info } => {
684 BlockEndCached::Match { info: MatchInfoCached::new(info, ctx) }
685 }
686 }
687 }
688 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> BlockEnd<'db> {
689 match self {
690 BlockEndCached::Return(returns, location) => BlockEnd::Return(
691 returns.into_iter().map(|var_usage| var_usage.embed(ctx)).collect(),
692 location.embed(ctx),
693 ),
694 BlockEndCached::Panic(var_id) => BlockEnd::Panic(var_id.embed(ctx)),
695 BlockEndCached::Goto(block_id, remapping) => {
696 BlockEnd::Goto(BlockId(block_id), remapping.embed(ctx))
697 }
698 BlockEndCached::NotSet => BlockEnd::NotSet,
699 BlockEndCached::Match { info } => BlockEnd::Match { info: info.embed(ctx) },
700 }
701 }
702}
703
704#[derive(Serialize, Deserialize)]
705struct VarRemappingCached {
706 remapping: OrderedHashMap<usize, VarUsageCached>,
708}
709impl VarRemappingCached {
710 fn new<'db>(var_remapping: VarRemapping<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
711 Self {
712 remapping: var_remapping
713 .iter()
714 .map(|(dst, src)| (dst.index(), VarUsageCached::new(*src, ctx)))
715 .collect(),
716 }
717 }
718 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> VarRemapping<'db> {
719 let mut remapping = OrderedHashMap::default();
720 for (dst, src) in self.remapping {
721 remapping.insert(ctx.lowered_variables_id[dst], src.embed(ctx));
722 }
723 VarRemapping { remapping }
724 }
725}
726
727#[derive(Serialize, Deserialize)]
728enum MatchInfoCached {
729 Enum(MatchEnumInfoCached),
730 Extern(MatchExternInfoCached),
731 Value(MatchEnumValueCached),
732}
733impl MatchInfoCached {
734 fn new<'db>(match_info: MatchInfo<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
735 match match_info {
736 MatchInfo::Enum(info) => MatchInfoCached::Enum(MatchEnumInfoCached::new(info, ctx)),
737 MatchInfo::Extern(info) => {
738 MatchInfoCached::Extern(MatchExternInfoCached::new(info, ctx))
739 }
740 MatchInfo::Value(info) => MatchInfoCached::Value(MatchEnumValueCached::new(info, ctx)),
741 }
742 }
743 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchInfo<'db> {
744 match self {
745 MatchInfoCached::Enum(info) => MatchInfo::Enum(info.embed(ctx)),
746 MatchInfoCached::Extern(info) => MatchInfo::Extern(info.embed(ctx)),
747 MatchInfoCached::Value(info) => MatchInfo::Value(info.embed(ctx)),
748 }
749 }
750}
751
752#[derive(Serialize, Deserialize)]
753struct MatchEnumInfoCached {
754 concrete_enum_id: ConcreteEnumCached,
755 input: VarUsageCached,
757 arms: Vec<MatchArmCached>,
760 location: LocationIdCached,
761}
762impl MatchEnumInfoCached {
763 fn new<'db>(match_enum_info: MatchEnumInfo<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
764 Self {
765 concrete_enum_id: ConcreteEnumCached::new(
766 match_enum_info.concrete_enum_id,
767 &mut ctx.semantic_ctx,
768 ),
769 input: VarUsageCached::new(match_enum_info.input, ctx),
770 arms: match_enum_info
771 .arms
772 .into_iter()
773 .map(|arm| MatchArmCached::new(arm, ctx))
774 .collect(),
775 location: LocationIdCached::new(match_enum_info.location, ctx),
776 }
777 }
778 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchEnumInfo<'db> {
779 MatchEnumInfo {
780 concrete_enum_id: self
781 .concrete_enum_id
782 .get_embedded(&ctx.semantic_loading_data, ctx.db),
783 input: self.input.embed(ctx),
784 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
785 location: self.location.embed(ctx),
786 }
787 }
788}
789
790#[derive(Serialize, Deserialize)]
791struct MatchExternInfoCached {
792 function: FunctionIdCached,
794 inputs: Vec<VarUsageCached>,
796 arms: Vec<MatchArmCached>,
799 location: LocationIdCached,
800}
801
802impl MatchExternInfoCached {
803 fn new<'db>(
804 match_extern_info: MatchExternInfo<'db>,
805 ctx: &mut CacheSavingContext<'db>,
806 ) -> Self {
807 Self {
808 function: FunctionIdCached::new(match_extern_info.function, ctx),
809 inputs: match_extern_info
810 .inputs
811 .iter()
812 .map(|var| VarUsageCached::new(*var, ctx))
813 .collect(),
814 arms: match_extern_info
815 .arms
816 .into_iter()
817 .map(|arm| MatchArmCached::new(arm, ctx))
818 .collect(),
819 location: LocationIdCached::new(match_extern_info.location, ctx),
820 }
821 }
822 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchExternInfo<'db> {
823 MatchExternInfo {
824 function: self.function.embed(ctx),
825 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
826 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
827 location: self.location.embed(ctx),
828 }
829 }
830}
831
832#[derive(Serialize, Deserialize)]
833struct MatchEnumValueCached {
834 num_of_arms: usize,
835
836 input: VarUsageCached,
838 arms: Vec<MatchArmCached>,
840 location: LocationIdCached,
841}
842
843impl MatchEnumValueCached {
844 fn new<'db>(match_enum_value: MatchEnumValue<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
845 Self {
846 num_of_arms: match_enum_value.num_of_arms,
847 input: VarUsageCached::new(match_enum_value.input, ctx),
848 arms: match_enum_value
849 .arms
850 .into_iter()
851 .map(|arm| MatchArmCached::new(arm, ctx))
852 .collect(),
853 location: LocationIdCached::new(match_enum_value.location, ctx),
854 }
855 }
856 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchEnumValue<'db> {
857 MatchEnumValue {
858 num_of_arms: self.num_of_arms,
859 input: self.input.embed(ctx),
860 arms: self.arms.into_iter().map(|arm| arm.embed(ctx)).collect(),
861 location: self.location.embed(ctx),
862 }
863 }
864}
865#[derive(Serialize, Deserialize)]
867struct MatchArmCached {
868 arm_selector: MatchArmSelectorCached,
870
871 block_id: usize,
873
874 var_ids: Vec<usize>,
876}
877
878impl MatchArmCached {
879 fn new<'db>(match_arm: MatchArm<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
880 Self {
881 arm_selector: MatchArmSelectorCached::new(
882 match_arm.arm_selector,
883 &mut ctx.semantic_ctx,
884 ),
885 block_id: match_arm.block_id.0,
886 var_ids: match_arm.var_ids.iter().map(|var| var.index()).collect(),
887 }
888 }
889 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> MatchArm<'db> {
890 MatchArm {
891 arm_selector: self.arm_selector.get_embedded(&ctx.semantic_loading_data, ctx.db),
892 block_id: BlockId(self.block_id),
893 var_ids: self
894 .var_ids
895 .into_iter()
896 .map(|var_id| ctx.lowered_variables_id[var_id])
897 .collect(),
898 }
899 }
900}
901
902#[derive(Serialize, Deserialize)]
903enum StatementCached {
904 Const(StatementConstCached),
906
907 Call(StatementCallCached),
909
910 StructConstruct(StatementStructConstructCached),
912 StructDestructure(StatementStructDestructureCached),
913
914 EnumConstruct(StatementEnumConstructCached),
916
917 Snapshot(StatementSnapshotCached),
918 Desnap(StatementDesnapCached),
919}
920
921impl StatementCached {
922 fn new<'db>(stmt: Statement<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
923 match stmt {
924 Statement::Const(stmt) => StatementCached::Const(StatementConstCached::new(stmt, ctx)),
925 Statement::Call(stmt) => StatementCached::Call(StatementCallCached::new(stmt, ctx)),
926 Statement::StructConstruct(stmt) => {
927 StatementCached::StructConstruct(StatementStructConstructCached::new(stmt, ctx))
928 }
929 Statement::StructDestructure(stmt) => {
930 StatementCached::StructDestructure(StatementStructDestructureCached::new(stmt, ctx))
931 }
932 Statement::EnumConstruct(stmt) => {
933 StatementCached::EnumConstruct(StatementEnumConstructCached::new(stmt, ctx))
934 }
935 Statement::Snapshot(stmt) => {
936 StatementCached::Snapshot(StatementSnapshotCached::new(stmt, ctx))
937 }
938 Statement::Desnap(stmt) => {
939 StatementCached::Desnap(StatementDesnapCached::new(stmt, ctx))
940 }
941 }
942 }
943 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Statement<'db> {
944 match self {
945 StatementCached::Const(stmt) => Statement::Const(stmt.embed(ctx)),
946 StatementCached::Call(stmt) => Statement::Call(stmt.embed(ctx)),
947 StatementCached::StructConstruct(stmt) => Statement::StructConstruct(stmt.embed(ctx)),
948 StatementCached::StructDestructure(stmt) => {
949 Statement::StructDestructure(stmt.embed(ctx))
950 }
951 StatementCached::EnumConstruct(stmt) => Statement::EnumConstruct(stmt.embed(ctx)),
952 StatementCached::Snapshot(stmt) => Statement::Snapshot(stmt.embed(ctx)),
953 StatementCached::Desnap(stmt) => Statement::Desnap(stmt.embed(ctx)),
954 }
955 }
956}
957
958#[derive(Serialize, Deserialize)]
959struct StatementConstCached {
960 value: ConstValueIdCached,
962 output: usize,
964 boxed: bool,
966}
967impl StatementConstCached {
968 fn new<'db>(stmt: StatementConst<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
969 Self {
970 value: ConstValueIdCached::new(stmt.value, &mut ctx.semantic_ctx),
971 output: stmt.output.index(),
972 boxed: stmt.boxed,
973 }
974 }
975 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementConst<'db> {
976 StatementConst::new(
977 self.value.get_embedded(&ctx.semantic_loading_data),
978 ctx.lowered_variables_id[self.output],
979 self.boxed,
980 )
981 }
982}
983
984#[derive(Serialize, Deserialize)]
985struct StatementCallCached {
986 function: FunctionIdCached,
987 inputs: Vec<VarUsageCached>,
988 with_coupon: bool,
989 outputs: Vec<usize>,
990 location: LocationIdCached,
991}
992impl StatementCallCached {
993 fn new<'db>(stmt: StatementCall<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
994 Self {
995 function: FunctionIdCached::new(stmt.function, ctx),
996 inputs: stmt.inputs.iter().map(|var| VarUsageCached::new(*var, ctx)).collect(),
997 with_coupon: stmt.with_coupon,
998 outputs: stmt.outputs.iter().map(|var| var.index()).collect(),
999 location: LocationIdCached::new(stmt.location, ctx),
1000 }
1001 }
1002 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementCall<'db> {
1003 StatementCall {
1004 function: self.function.embed(ctx),
1005 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
1006 with_coupon: self.with_coupon,
1007 outputs: self
1008 .outputs
1009 .into_iter()
1010 .map(|var_id| ctx.lowered_variables_id[var_id])
1011 .collect(),
1012 location: self.location.embed(ctx),
1013 }
1014 }
1015}
1016
1017#[derive(Serialize, Deserialize, Clone)]
1018enum FunctionCached {
1019 Semantic(SemanticFunctionIdCached),
1021 Generated(GeneratedFunctionCached),
1023}
1024impl FunctionCached {
1025 fn new<'db>(function: FunctionLongId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1026 match function {
1027 FunctionLongId::Semantic(id) => {
1028 FunctionCached::Semantic(SemanticFunctionIdCached::new(id, &mut ctx.semantic_ctx))
1029 }
1030 FunctionLongId::Generated(id) => {
1031 FunctionCached::Generated(GeneratedFunctionCached::new(id, ctx))
1032 }
1033 FunctionLongId::Specialized(_) => {
1034 unreachable!("Specialization of functions only occurs post concretization.")
1035 }
1036 }
1037 }
1038 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> FunctionId<'db> {
1039 match self {
1040 FunctionCached::Semantic(id) => {
1041 FunctionLongId::Semantic(id.get_embedded(&ctx.semantic_loading_data))
1042 }
1043 FunctionCached::Generated(id) => FunctionLongId::Generated(id.embed(ctx)),
1044 }
1045 .intern(ctx.db)
1046 }
1047}
1048
1049#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash)]
1050struct FunctionIdCached(usize);
1051impl FunctionIdCached {
1052 fn new<'db>(function_id: FunctionId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1053 if let Some(id) = ctx.function_ids.get(&function_id) {
1054 return *id;
1055 }
1056 let function = FunctionCached::new(function_id.long(ctx.db).clone(), ctx);
1057 let id = FunctionIdCached(ctx.function_ids_lookup.len());
1058 ctx.function_ids_lookup.push(function);
1059 ctx.function_ids.insert(function_id, id);
1060 id
1061 }
1062 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> FunctionId<'db> {
1063 if let Some(function_id) = ctx.function_ids.get(&self) {
1064 return *function_id;
1065 }
1066
1067 let function = ctx.function_ids_lookup[self.0].clone();
1068 let function_id = function.embed(ctx);
1069 ctx.function_ids.insert(self, function_id);
1070 function_id
1071 }
1072}
1073
1074#[derive(Serialize, Deserialize, Clone)]
1075struct GeneratedFunctionCached {
1076 parent: SemanticConcreteFunctionWithBodyCached,
1077 key: GeneratedFunctionKeyCached,
1078}
1079impl GeneratedFunctionCached {
1080 fn new<'db>(function: GeneratedFunction<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1081 Self {
1082 parent: SemanticConcreteFunctionWithBodyCached::new(
1083 function.parent,
1084 &mut ctx.semantic_ctx,
1085 ),
1086 key: GeneratedFunctionKeyCached::new(function.key, ctx),
1087 }
1088 }
1089 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> GeneratedFunction<'db> {
1090 GeneratedFunction {
1091 parent: self.parent.get_embedded(&ctx.semantic_loading_data, ctx.db),
1092 key: self.key.embed(ctx),
1093 }
1094 }
1095}
1096
1097#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
1098enum GeneratedFunctionKeyCached {
1099 Loop(SyntaxStablePtrIdCached),
1100 TraitFunc(LanguageElementCached, SyntaxStablePtrIdCached),
1101}
1102
1103impl GeneratedFunctionKeyCached {
1104 fn new<'db>(key: GeneratedFunctionKey<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1105 match key {
1106 GeneratedFunctionKey::Loop(id) => GeneratedFunctionKeyCached::Loop(
1107 SyntaxStablePtrIdCached::new(id.untyped(), &mut ctx.semantic_ctx.defs_ctx),
1108 ),
1109 GeneratedFunctionKey::TraitFunc(id, stable_location) => {
1110 GeneratedFunctionKeyCached::TraitFunc(
1111 LanguageElementCached::new(id, &mut ctx.semantic_ctx.defs_ctx),
1112 SyntaxStablePtrIdCached::new(
1113 stable_location.stable_ptr(),
1114 &mut ctx.semantic_ctx.defs_ctx,
1115 ),
1116 )
1117 }
1118 }
1119 }
1120 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> GeneratedFunctionKey<'db> {
1121 match self {
1122 GeneratedFunctionKeyCached::Loop(id) => GeneratedFunctionKey::Loop(ExprPtr(
1123 id.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1124 )),
1125 GeneratedFunctionKeyCached::TraitFunc(id, stable_location) => {
1126 let (module_id, stable_ptr) =
1127 id.get_embedded(&ctx.semantic_loading_data.defs_loading_data);
1128 GeneratedFunctionKey::TraitFunc(
1129 TraitFunctionLongId(module_id, TraitItemFunctionPtr(stable_ptr)).intern(ctx.db),
1130 StableLocation::new(
1131 stable_location.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1132 ),
1133 )
1134 }
1135 }
1136 }
1137}
1138
1139#[derive(Serialize, Deserialize)]
1140struct StatementStructConstructCached {
1141 inputs: Vec<VarUsageCached>,
1142 output: usize,
1144}
1145impl StatementStructConstructCached {
1146 fn new<'db>(stmt: StatementStructConstruct<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1147 Self {
1148 inputs: stmt.inputs.iter().map(|var| VarUsageCached::new(*var, _ctx)).collect(),
1149 output: stmt.output.index(),
1150 }
1151 }
1152 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementStructConstruct<'db> {
1153 StatementStructConstruct {
1154 inputs: self.inputs.into_iter().map(|var_id| var_id.embed(ctx)).collect(),
1155 output: ctx.lowered_variables_id[self.output],
1156 }
1157 }
1158}
1159#[derive(Serialize, Deserialize)]
1160struct StatementStructDestructureCached {
1161 input: VarUsageCached,
1163 outputs: Vec<usize>,
1165}
1166impl StatementStructDestructureCached {
1167 fn new<'db>(stmt: StatementStructDestructure<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1168 Self {
1169 input: VarUsageCached::new(stmt.input, _ctx),
1170 outputs: stmt.outputs.iter().map(|var| var.index()).collect(),
1171 }
1172 }
1173 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementStructDestructure<'db> {
1174 StatementStructDestructure {
1175 input: self.input.embed(ctx),
1176 outputs: self
1177 .outputs
1178 .into_iter()
1179 .map(|var_id| ctx.lowered_variables_id[var_id])
1180 .collect(),
1181 }
1182 }
1183}
1184
1185#[derive(Serialize, Deserialize)]
1186struct StatementEnumConstructCached {
1187 variant: ConcreteVariantCached,
1188 input: VarUsageCached,
1190 output: usize,
1192}
1193impl StatementEnumConstructCached {
1194 fn new<'db>(stmt: StatementEnumConstruct<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1195 Self {
1196 variant: ConcreteVariantCached::new(stmt.variant, &mut ctx.semantic_ctx),
1197 input: VarUsageCached::new(stmt.input, ctx),
1198 output: stmt.output.index(),
1199 }
1200 }
1201 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementEnumConstruct<'db> {
1202 StatementEnumConstruct {
1203 variant: self.variant.get_embedded(&ctx.semantic_loading_data, ctx.db),
1204 input: self.input.embed(ctx),
1205 output: ctx.lowered_variables_id[self.output],
1206 }
1207 }
1208}
1209
1210#[derive(Serialize, Deserialize)]
1211struct StatementSnapshotCached {
1212 input: VarUsageCached,
1213 outputs: [usize; 2],
1214}
1215impl StatementSnapshotCached {
1216 fn new<'db>(stmt: StatementSnapshot<'db>, _ctx: &mut CacheSavingContext<'db>) -> Self {
1217 Self {
1218 input: VarUsageCached::new(stmt.input, _ctx),
1219 outputs: stmt.outputs.map(|var| var.index()),
1220 }
1221 }
1222 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementSnapshot<'db> {
1223 StatementSnapshot {
1224 input: self.input.embed(ctx),
1225 outputs: [
1226 ctx.lowered_variables_id[self.outputs[0]],
1227 ctx.lowered_variables_id[self.outputs[1]],
1228 ],
1229 }
1230 }
1231}
1232
1233#[derive(Serialize, Deserialize)]
1234struct StatementDesnapCached {
1235 input: VarUsageCached,
1236 output: usize,
1238}
1239impl StatementDesnapCached {
1240 fn new<'db>(stmt: StatementDesnap<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1241 Self { input: VarUsageCached::new(stmt.input, ctx), output: stmt.output.index() }
1242 }
1243 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementDesnap<'db> {
1244 StatementDesnap {
1245 input: self.input.embed(ctx),
1246 output: ctx.lowered_variables_id[self.output],
1247 }
1248 }
1249}
1250
1251#[derive(Serialize, Deserialize, Clone)]
1252struct LocationCached {
1253 stable_location: SyntaxStablePtrIdCached,
1255 inline_locations: Vec<SyntaxStablePtrIdCached>,
1257}
1258impl LocationCached {
1259 fn new<'db>(location: Location<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1260 Self {
1261 stable_location: SyntaxStablePtrIdCached::new(
1262 location.stable_location.stable_ptr(),
1263 &mut ctx.semantic_ctx.defs_ctx,
1264 ),
1265 inline_locations: location
1266 .inline_locations
1267 .iter()
1268 .map(|loc| {
1269 SyntaxStablePtrIdCached::new(loc.stable_ptr(), &mut ctx.semantic_ctx.defs_ctx)
1270 })
1271 .collect(),
1272 }
1273 }
1274 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Location<'db> {
1275 Location {
1276 stable_location: StableLocation::new(
1277 self.stable_location.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1278 ),
1279 inline_locations: self
1280 .inline_locations
1281 .into_iter()
1282 .map(|loc| {
1283 StableLocation::new(
1284 loc.get_embedded(&ctx.semantic_loading_data.defs_loading_data),
1285 )
1286 })
1287 .collect(),
1288 notes: Default::default(),
1289 }
1290 }
1291}
1292
1293#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Hash)]
1294struct LocationIdCached(usize);
1295
1296impl LocationIdCached {
1297 fn new<'db>(location_id: LocationId<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
1298 if let Some(id) = ctx.location_ids.get(&location_id) {
1299 return *id;
1300 }
1301 let location = LocationCached::new(location_id.long(ctx.db).clone(), ctx);
1302 let id = LocationIdCached(ctx.location_ids_lookup.len());
1303 ctx.location_ids_lookup.push(location);
1304 ctx.location_ids.insert(location_id, id);
1305 id
1306 }
1307 fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> LocationId<'db> {
1308 if let Some(location_id) = ctx.location_ids.get(&self) {
1309 return *location_id;
1310 }
1311 let location = ctx.location_ids_lookup[self.0].clone();
1312 let location = location.embed(ctx).intern(ctx.db);
1313 ctx.location_ids.insert(self, location);
1314 location
1315 }
1316}