Skip to main content

code_moniker_workspace/snapshot/inventory/
facets.rs

1use std::sync::Arc;
2
3use rustc_hash::FxHashMap;
4
5use super::{InventorySegment, InventorySymbol, SourceId, SymbolOrdinal, SymbolSet};
6
7// Posting-list accessors are independent projections over one immutable
8// inventory; low field overlap is the intended shape of this index.
9// code-moniker: ignore[smell-god-type-local-metrics]
10#[derive(Clone, Debug, Default, Eq, PartialEq)]
11pub struct SymbolInventoryFacets {
12	by_identity: FxHashMap<Arc<str>, SymbolSet>,
13	by_name: FxHashMap<Arc<str>, SymbolSet>,
14	by_kind: FxHashMap<Arc<str>, SymbolSet>,
15	by_shape: FxHashMap<Arc<str>, SymbolSet>,
16	by_visibility: FxHashMap<Arc<str>, SymbolSet>,
17	by_language: FxHashMap<Arc<str>, SymbolSet>,
18	by_source: FxHashMap<SourceId, SymbolSet>,
19	by_source_path: FxHashMap<Arc<str>, SymbolSet>,
20	by_source_root: FxHashMap<usize, SymbolSet>,
21	by_srcset: FxHashMap<Arc<str>, SymbolSet>,
22	by_segment: FxHashMap<InventorySegment, SymbolSet>,
23}
24
25impl SymbolInventoryFacets {
26	pub(super) fn estimated_heap_bytes(&self) -> usize {
27		string_postings_bytes(&self.by_identity)
28			+ string_postings_bytes(&self.by_name)
29			+ string_postings_bytes(&self.by_kind)
30			+ string_postings_bytes(&self.by_shape)
31			+ string_postings_bytes(&self.by_visibility)
32			+ string_postings_bytes(&self.by_language)
33			+ postings_bytes(&self.by_source)
34			+ string_postings_bytes(&self.by_source_path)
35			+ postings_bytes(&self.by_source_root)
36			+ string_postings_bytes(&self.by_srcset)
37			+ postings_bytes(&self.by_segment)
38	}
39
40	pub fn symbols_by_identity(&self, identity: &str) -> Option<&SymbolSet> {
41		self.by_identity.get(identity)
42	}
43
44	pub fn symbols_by_name(&self, name: &str) -> Option<&SymbolSet> {
45		self.by_name.get(name)
46	}
47
48	pub fn name_postings(&self) -> impl Iterator<Item = (&str, &SymbolSet)> {
49		posting_values(&self.by_name)
50	}
51
52	pub fn symbols_by_kind(&self, kind: &str) -> Option<&SymbolSet> {
53		self.by_kind.get(kind)
54	}
55
56	pub fn kind_postings(&self) -> impl Iterator<Item = (&str, &SymbolSet)> {
57		posting_values(&self.by_kind)
58	}
59
60	pub fn symbols_by_shape(&self, shape: &str) -> Option<&SymbolSet> {
61		self.by_shape.get(shape)
62	}
63
64	pub fn shape_postings(&self) -> impl Iterator<Item = (&str, &SymbolSet)> {
65		posting_values(&self.by_shape)
66	}
67
68	pub fn symbols_by_visibility(&self, visibility: &str) -> Option<&SymbolSet> {
69		self.by_visibility.get(visibility)
70	}
71
72	pub fn visibility_postings(&self) -> impl Iterator<Item = (&str, &SymbolSet)> {
73		posting_values(&self.by_visibility)
74	}
75
76	pub fn symbols_by_language(&self, language: &str) -> Option<&SymbolSet> {
77		self.by_language.get(language)
78	}
79
80	pub fn language_postings(&self) -> impl Iterator<Item = (&str, &SymbolSet)> {
81		posting_values(&self.by_language)
82	}
83
84	pub fn symbols_by_source(&self, source: SourceId) -> Option<&SymbolSet> {
85		self.by_source.get(&source)
86	}
87
88	pub fn symbols_by_source_path(&self, path: &str) -> Option<&SymbolSet> {
89		self.by_source_path.get(path)
90	}
91
92	pub fn source_path_postings(&self) -> impl Iterator<Item = (&str, &SymbolSet)> {
93		posting_values(&self.by_source_path)
94	}
95
96	pub fn symbols_by_source_root(&self, root: usize) -> Option<&SymbolSet> {
97		self.by_source_root.get(&root)
98	}
99
100	pub fn symbols_by_srcset(&self, srcset: &str) -> Option<&SymbolSet> {
101		self.by_srcset.get(srcset)
102	}
103
104	pub fn srcset_postings(&self) -> impl Iterator<Item = (&str, &SymbolSet)> {
105		posting_values(&self.by_srcset)
106	}
107
108	pub fn symbols_by_segment(&self, kind: &str, name: &str) -> Option<&SymbolSet> {
109		self.by_segment.get(&InventorySegment {
110			kind: Arc::from(kind),
111			name: Arc::from(name),
112		})
113	}
114
115	pub fn segment_postings(&self) -> impl Iterator<Item = (&InventorySegment, &SymbolSet)> {
116		self.by_segment.iter()
117	}
118}
119
120fn postings_bytes<K>(postings: &FxHashMap<K, SymbolSet>) -> usize {
121	postings.capacity() * (std::mem::size_of::<K>() + std::mem::size_of::<SymbolSet>())
122		+ postings
123			.values()
124			.map(SymbolSet::estimated_heap_bytes)
125			.sum::<usize>()
126}
127
128fn string_postings_bytes(postings: &FxHashMap<Arc<str>, SymbolSet>) -> usize {
129	postings_bytes(postings)
130}
131
132pub(super) fn insert_facets(
133	facets: &mut SymbolInventoryFacets,
134	record: &InventorySymbol,
135	ordinal: SymbolOrdinal,
136) {
137	insert_posting(
138		&mut facets.by_identity,
139		Arc::clone(&record.identity),
140		ordinal,
141	);
142	insert_posting(&mut facets.by_name, Arc::clone(&record.name), ordinal);
143	insert_posting(&mut facets.by_kind, Arc::clone(&record.kind), ordinal);
144	insert_posting(&mut facets.by_shape, Arc::clone(&record.shape), ordinal);
145	insert_posting(
146		&mut facets.by_visibility,
147		Arc::clone(&record.visibility),
148		ordinal,
149	);
150	insert_posting(
151		&mut facets.by_language,
152		Arc::clone(&record.language),
153		ordinal,
154	);
155	insert_posting(&mut facets.by_source, record.source, ordinal);
156	insert_posting(
157		&mut facets.by_source_path,
158		Arc::clone(&record.source_path),
159		ordinal,
160	);
161	insert_posting(&mut facets.by_source_root, record.source_root, ordinal);
162	insert_posting(&mut facets.by_srcset, Arc::clone(&record.srcset), ordinal);
163	for segment in record.segments.iter() {
164		insert_posting(&mut facets.by_segment, segment.clone(), ordinal);
165	}
166}
167
168pub(super) fn remove_facets(
169	facets: &mut SymbolInventoryFacets,
170	record: &InventorySymbol,
171	ordinal: SymbolOrdinal,
172) {
173	remove_posting(&mut facets.by_identity, &record.identity, ordinal);
174	remove_posting(&mut facets.by_name, &record.name, ordinal);
175	remove_posting(&mut facets.by_kind, &record.kind, ordinal);
176	remove_posting(&mut facets.by_shape, &record.shape, ordinal);
177	remove_posting(&mut facets.by_visibility, &record.visibility, ordinal);
178	remove_posting(&mut facets.by_language, &record.language, ordinal);
179	remove_posting(&mut facets.by_source, &record.source, ordinal);
180	remove_posting(&mut facets.by_source_path, &record.source_path, ordinal);
181	remove_posting(&mut facets.by_source_root, &record.source_root, ordinal);
182	remove_posting(&mut facets.by_srcset, &record.srcset, ordinal);
183	for segment in record.segments.iter() {
184		remove_posting(&mut facets.by_segment, segment, ordinal);
185	}
186}
187
188fn posting_values(
189	index: &FxHashMap<Arc<str>, SymbolSet>,
190) -> impl Iterator<Item = (&str, &SymbolSet)> {
191	index
192		.iter()
193		.map(|(value, symbols)| (value.as_ref(), symbols))
194}
195
196fn insert_posting<K: Eq + std::hash::Hash>(
197	index: &mut FxHashMap<K, SymbolSet>,
198	key: K,
199	ordinal: SymbolOrdinal,
200) {
201	index.entry(key).or_default().insert(ordinal);
202}
203
204fn remove_posting<K: Eq + std::hash::Hash>(
205	index: &mut FxHashMap<K, SymbolSet>,
206	key: &K,
207	ordinal: SymbolOrdinal,
208) {
209	if let Some(symbols) = index.get_mut(key) {
210		symbols.remove(ordinal);
211		if symbols.is_empty() {
212			index.remove(key);
213		}
214	}
215}