Skip to main content

code_moniker_workspace/snapshot/inventory/
catalog.rs

1use rustc_hash::FxHashMap;
2
3use super::{SymbolId, SymbolOrdinal, SymbolSet};
4
5// An ordinal catalogue is a bidirectional index; its lookup and lifecycle
6// methods intentionally touch different sides of the same invariant.
7// code-moniker: ignore[smell-god-type-local-metrics]
8#[derive(Clone, Debug, Default, Eq, PartialEq)]
9pub struct SymbolOrdinalCatalog {
10	next_ordinal: u32,
11	ids: FxHashMap<SymbolOrdinal, SymbolId>,
12	ordinals_by_id: FxHashMap<SymbolId, SymbolOrdinal>,
13}
14
15impl SymbolOrdinalCatalog {
16	pub(super) fn estimated_heap_bytes(&self) -> usize {
17		self.ids.capacity()
18			* (std::mem::size_of::<SymbolOrdinal>() + std::mem::size_of::<SymbolId>())
19			+ self.ordinals_by_id.capacity()
20				* (std::mem::size_of::<SymbolId>() + std::mem::size_of::<SymbolOrdinal>())
21	}
22
23	pub fn push(&mut self, id: SymbolId) -> SymbolOrdinal {
24		if let Some(ordinal) = self.ordinals_by_id.get(&id).copied() {
25			return ordinal;
26		}
27		let ordinal = SymbolOrdinal::from_index(self.next_ordinal as usize);
28		assert!(
29			self.next_ordinal < u32::MAX,
30			"symbol ordinal space exhausted"
31		);
32		self.next_ordinal += 1;
33		self.bind_id(ordinal, id);
34		ordinal
35	}
36
37	pub fn retire(&mut self, ordinal: SymbolOrdinal) {
38		self.unbind_id(ordinal);
39	}
40
41	pub(super) fn bind_id(&mut self, ordinal: SymbolOrdinal, id: SymbolId) {
42		if let Some(previous) = self.ids.insert(ordinal, id) {
43			self.ordinals_by_id.remove(&previous);
44		}
45		if let Some(previous_ordinal) = self.ordinals_by_id.insert(id, ordinal)
46			&& previous_ordinal != ordinal
47		{
48			self.ids.remove(&previous_ordinal);
49		}
50	}
51
52	pub fn unbind_id(&mut self, ordinal: SymbolOrdinal) {
53		if let Some(previous_id) = self.ids.remove(&ordinal)
54			&& self.ordinals_by_id.get(&previous_id) == Some(&ordinal)
55		{
56			self.ordinals_by_id.remove(&previous_id);
57		}
58	}
59
60	pub fn len(&self) -> usize {
61		self.ordinals_by_id.len()
62	}
63
64	pub fn is_empty(&self) -> bool {
65		self.len() == 0
66	}
67
68	pub fn storage_len(&self) -> usize {
69		self.ids.len()
70	}
71
72	pub fn ordinal(&self, id: &SymbolId) -> Option<SymbolOrdinal> {
73		self.ordinals_by_id.get(id).copied()
74	}
75
76	pub fn ids(&self, symbols: &SymbolSet) -> Vec<SymbolId> {
77		symbols
78			.iter()
79			.filter_map(|symbol| self.id(symbol).copied())
80			.collect()
81	}
82
83	pub fn id(&self, ordinal: SymbolOrdinal) -> Option<&SymbolId> {
84		self.ids.get(&ordinal)
85	}
86
87	pub fn active_ordinals(&self) -> impl Iterator<Item = (u32, SymbolId)> + '_ {
88		let mut ordinals = self
89			.ids
90			.iter()
91			.map(|(ordinal, id)| (ordinal.raw(), *id))
92			.collect::<Vec<_>>();
93		ordinals.sort_unstable_by_key(|(ordinal, _)| *ordinal);
94		ordinals.into_iter()
95	}
96}