use std::fmt;
use std::fmt::Debug;
use std::mem;
use allocative::Allocative;
use hashbrown::HashTable;
use pagable::PagableDeserialize;
use pagable::PagableSerialize;
use starlark_derive::Trace;
use starlark_map::Hashed;
use crate as starlark;
use crate::collections::symbol::symbol::Symbol;
use crate::pagable::StarlarkDeserialize;
use crate::pagable::StarlarkDeserializeContext;
use crate::pagable::StarlarkSerialize;
use crate::pagable::StarlarkSerializeContext;
use crate::values::StringValue;
#[derive(Clone, Trace, Allocative)]
pub(crate) struct SymbolMap<T>(HashTable<(Symbol, T)>);
impl<T: Debug> Debug for SymbolMap<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(self.iter().map(|x| (&x.0, &x.1)))
.finish()
}
}
impl<T> SymbolMap<T> {
pub(crate) fn new() -> Self {
SymbolMap::with_capacity(0)
}
pub(crate) fn with_capacity(capacity: usize) -> Self {
SymbolMap(HashTable::with_capacity(capacity))
}
pub(crate) fn insert(&mut self, key: &str, value: T) -> Option<T> {
let s = Symbol::new(key);
if let Some((_, item)) = self.0.find_mut(s.hash(), |x| s == x.0) {
Some(mem::replace(item, value))
} else {
self.0.insert_unique(s.hash(), (s, value), |x| x.0.hash());
None
}
}
#[inline]
pub(crate) fn get(&self, key: &Symbol) -> Option<&T> {
self.0.find(key.hash(), |x| key == &x.0).map(|x| &x.1)
}
pub(crate) fn get_str(&self, key: &str) -> Option<&T> {
self.get_hashed_str(Hashed::new(key))
}
pub(crate) fn get_hashed_str(&self, key: Hashed<&str>) -> Option<&T> {
self.0
.find(key.hash().promote(), |x| x.0.as_str() == *key.key())
.map(|x| &x.1)
}
pub(crate) fn get_hashed_string_value(&self, key: Hashed<StringValue>) -> Option<&T> {
self.0
.find(key.hash().promote(), |x| {
x.0.as_aligned_padded_str() == key.key().as_aligned_padded_str()
})
.map(|x| &x.1)
}
pub(crate) fn len(&self) -> usize {
self.0.len()
}
pub(crate) fn iter<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a (Symbol, T)> + 'a {
self.0.iter()
}
pub(crate) fn keys<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a Symbol> + 'a {
self.iter().map(|x| &x.0)
}
pub(crate) fn values<'a>(&'a self) -> impl ExactSizeIterator<Item = &'a T> + 'a {
self.iter().map(|x| &x.1)
}
}
impl<T: PagableSerialize> PagableSerialize for SymbolMap<T> {
fn pagable_serialize(
&self,
serializer: &mut dyn pagable::PagableSerializer,
) -> pagable::Result<()> {
self.len().pagable_serialize(serializer)?;
for (symbol, value) in self.iter() {
symbol.pagable_serialize(serializer)?;
value.pagable_serialize(serializer)?;
}
Ok(())
}
}
impl<'de, T: PagableDeserialize<'de>> PagableDeserialize<'de> for SymbolMap<T> {
fn pagable_deserialize<D: pagable::PagableDeserializer<'de> + ?Sized>(
deserializer: &mut D,
) -> pagable::Result<Self> {
let len = usize::pagable_deserialize(deserializer)?;
let mut map = SymbolMap::with_capacity(len);
for _ in 0..len {
let symbol = Symbol::pagable_deserialize(deserializer)?;
let value = T::pagable_deserialize(deserializer)?;
map.insert(symbol.as_str(), value);
}
Ok(map)
}
}
impl<T: StarlarkSerialize> StarlarkSerialize for SymbolMap<T> {
fn starlark_serialize(&self, ctx: &mut dyn StarlarkSerializeContext) -> crate::Result<()> {
self.len().pagable_serialize(ctx.pagable())?;
for (symbol, value) in self.iter() {
symbol.pagable_serialize(ctx.pagable())?;
value.starlark_serialize(ctx)?;
}
Ok(())
}
}
impl<T: StarlarkDeserialize> StarlarkDeserialize for SymbolMap<T> {
fn starlark_deserialize(ctx: &mut dyn StarlarkDeserializeContext<'_>) -> crate::Result<Self> {
let len = usize::pagable_deserialize(ctx.pagable())?;
let mut map = SymbolMap::with_capacity(len);
for _ in 0..len {
let symbol = Symbol::pagable_deserialize(ctx.pagable())?;
let value = T::starlark_deserialize(ctx)?;
map.insert(symbol.as_str(), value);
}
Ok(map)
}
}