use ahash::AHashMap;
use crate::{
intern::StringId,
namespace::NamespaceId,
parse::{CodeRange, ParseError},
};
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
#[serde(into = "NameMapWire", try_from = "NameMapWire")]
pub(crate) struct NameMap {
slots: Vec<StringId>,
by_name: AHashMap<StringId, NamespaceId>,
}
#[derive(serde::Serialize, serde::Deserialize)]
struct NameMapWire {
slots: Vec<StringId>,
}
impl From<NameMap> for NameMapWire {
fn from(map: NameMap) -> Self {
Self { slots: map.slots }
}
}
impl TryFrom<NameMapWire> for NameMap {
type Error = String;
fn try_from(wire: NameMapWire) -> Result<Self, Self::Error> {
let max_slots = usize::from(u16::MAX) + 1;
if wire.slots.len() > max_slots {
return Err(format!(
"NameMap has too many slots: {} (maximum is {max_slots})",
wire.slots.len(),
));
}
let mut by_name = AHashMap::with_capacity(wire.slots.len());
for (idx, &name_id) in wire.slots.iter().enumerate() {
let slot = NamespaceId::new(idx).expect("slot index fits in NamespaceId by length check");
by_name.entry(name_id).or_insert(slot);
}
Ok(Self {
slots: wire.slots,
by_name,
})
}
}
impl NameMap {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(cap: usize) -> Self {
Self {
slots: Vec::with_capacity(cap),
by_name: AHashMap::with_capacity(cap),
}
}
pub fn len(&self) -> usize {
self.slots.len()
}
pub fn get(&self, name_id: StringId) -> Option<NamespaceId> {
self.by_name.get(&name_id).copied()
}
pub fn contains(&self, name_id: StringId) -> bool {
self.by_name.contains_key(&name_id)
}
pub fn ensure_slot(&mut self, name_id: StringId, position: CodeRange) -> Result<NamespaceId, ParseError> {
if let Some(&id) = self.by_name.get(&name_id) {
return Ok(id);
}
let id = NamespaceId::new(self.slots.len()).ok_or_else(|| namespace_overflow(position))?;
self.slots.push(name_id);
self.by_name.insert(name_id, id);
Ok(id)
}
pub fn push_aliased_slot(&mut self, name_id: StringId, position: CodeRange) -> Result<NamespaceId, ParseError> {
let id = NamespaceId::new(self.slots.len()).ok_or_else(|| namespace_overflow(position))?;
self.slots.push(name_id);
Ok(id)
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = (NamespaceId, StringId)> + '_ {
self.slots.iter().enumerate().map(|(i, &name)| {
let slot = NamespaceId::new(i).expect("slot index fits in NamespaceId by construction");
(slot, name)
})
}
}
#[cold]
#[inline(never)]
pub(crate) fn namespace_overflow(position: CodeRange) -> ParseError {
ParseError::syntax(
format!(
"too many distinct names in scope; maximum is {} per scope",
(u16::MAX as usize) + 1
),
position,
)
}