use num_traits::{Bounded, FromPrimitive, ToPrimitive};
#[cfg(feature = "serde")]
use serde::{Serialize, Serializer};
use shawshank::{self, ArenaSet};
use std::borrow::Borrow;
#[cfg(feature = "serde")]
use std::collections::{BTreeMap, HashMap};
use std::fmt;
#[cfg(feature = "serde")]
use std::hash::Hash;
use std::ops::Index;
#[cfg(feature = "serde")]
use std::path::PathBuf;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Symbol(usize);
impl fmt::Debug for Symbol {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Symbol({})", self.0)
}
}
#[doc(hidden)]
impl Bounded for Symbol {
fn min_value() -> Self {
Symbol(usize::min_value())
}
fn max_value() -> Self {
Symbol(usize::max_value())
}
}
#[doc(hidden)]
impl FromPrimitive for Symbol {
fn from_i64(n: i64) -> Option<Self> {
usize::from_i64(n).map(Symbol)
}
fn from_u64(n: u64) -> Option<Self> {
usize::from_u64(n).map(Symbol)
}
fn from_usize(n: usize) -> Option<Self> {
Some(Symbol(n))
}
}
impl ToPrimitive for Symbol {
fn to_i64(&self) -> Option<i64> {
self.0.to_i64()
}
fn to_u64(&self) -> Option<u64> {
self.0.to_u64()
}
fn to_usize(&self) -> Option<usize> {
Some(self.0)
}
}
impl From<Symbol> for usize {
fn from(s: Symbol) -> usize {
s.0
}
}
pub const UNKNOWN_SYMBOL: Symbol = Symbol(0);
#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
pub struct Interner(ArenaSet<Box<str>, Symbol>);
impl Interner {
pub fn new() -> Interner {
let mut si = shawshank::Builder::<Box<str>, Symbol>::new().hash().expect("build ArenaSet");
let symbol = si.intern("<unknown>").expect("intern '<unknown>'");
debug_assert_eq!(symbol, UNKNOWN_SYMBOL);
Interner(si)
}
pub fn intern<S>(&mut self, s: S) -> Symbol
where
S: Borrow<str>,
Box<str>: From<S>,
{
self.0.intern(s).expect("unbounded ArenaSet")
}
pub fn iter(&self) -> Iter {
Iter {
interner: self,
current_index: 1, }
}
}
impl fmt::Debug for Interner {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Interner {{ /* {} strings */ }}", self.0.count())
}
}
impl Default for Interner {
fn default() -> Interner {
Interner::new()
}
}
impl Index<Symbol> for Interner {
type Output = str;
fn index(&self, index: Symbol) -> &str {
self.0.resolve(index).expect("valid symbol")
}
}
#[derive(Debug)]
pub struct Iter<'a> {
interner: &'a Interner,
current_index: usize,
}
impl<'a> Iterator for Iter<'a> {
type Item = (Symbol, &'a str);
fn next(&mut self) -> Option<Self::Item> {
if self.current_index >= self.interner.0.capacity() {
None
} else {
let symbol = Symbol(self.current_index);
self.current_index += 1;
Some((symbol, &self.interner[symbol]))
}
}
}
#[cfg(feature = "serde")]
#[derive(Debug)]
pub struct WithInterner<'si, T> {
interner: &'si Interner,
value: T,
}
#[cfg(feature = "serde")]
pub trait SerializeWithInterner {
fn with_interner<'si>(&self, interner: &'si Interner) -> WithInterner<'si, &Self> {
WithInterner {
interner: interner,
value: self,
}
}
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> Result<S::Ok, S::Error>;
}
#[cfg(feature = "serde")]
impl<'si, T: SerializeWithInterner> Serialize for WithInterner<'si, T> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.value.serialize_with_interner(serializer, self.interner)
}
}
#[cfg(feature = "serde")]
impl SerializeWithInterner for Symbol {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> Result<S::Ok, S::Error> {
interner[*self].serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<K: SerializeWithInterner + Ord, V: SerializeWithInterner> SerializeWithInterner for BTreeMap<K, V> {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> Result<S::Ok, S::Error> {
serializer.collect_map(self.iter().map(|(k, v)| (k.with_interner(interner), v.with_interner(interner))))
}
}
#[cfg(feature = "serde")]
impl<K: SerializeWithInterner + Eq + Hash, V: SerializeWithInterner> SerializeWithInterner for HashMap<K, V> {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> Result<S::Ok, S::Error> {
serializer.collect_map(self.iter().map(|(k, v)| (k.with_interner(interner), v.with_interner(interner))))
}
}
#[cfg(feature = "serde")]
impl<T: SerializeWithInterner> SerializeWithInterner for Vec<T> {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> Result<S::Ok, S::Error> {
serializer.collect_seq(self.iter().map(|value| value.with_interner(interner)))
}
}
#[cfg(feature = "serde")]
impl<T: SerializeWithInterner> SerializeWithInterner for Option<T> {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> Result<S::Ok, S::Error> {
match *self {
None => serializer.serialize_none(),
Some(ref value) => serializer.serialize_some(&value.with_interner(interner)),
}
}
}
#[cfg(feature = "serde")]
impl<'a, T: 'a + SerializeWithInterner + ?Sized> SerializeWithInterner for &'a T {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> Result<S::Ok, S::Error> {
(**self).serialize_with_interner(serializer, interner)
}
}
#[cfg(feature = "serde")]
macro_rules! count_fields {
() => { 0 };
($a:ident $($tail:ident)*) => { count_fields!($($tail)*) + 1 };
}
macro_rules! derive_serialize_with_interner {
(
$(#[$struct_attr:meta])*
pub struct $struct_name:ident {
$(
$(#[$field_attr:meta])*
pub $field_name:ident: $field_ty:ty,
)+
}
) => {
$(#[$struct_attr])*
pub struct $struct_name {
$(
$(#[$field_attr])*
pub $field_name: $field_ty,
)+
}
#[cfg(feature = "serde")]
impl SerializeWithInterner for $struct_name {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> ::std::result::Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct(stringify!($struct_name), count_fields!($($field_name)*))?;
$(
state.serialize_field(stringify!($field_name), &self.$field_name.with_interner(interner))?;
)*
state.end()
}
}
};
(direct: $($ty:ty),*) => {
$(
#[cfg(feature = "serde")]
impl SerializeWithInterner for $ty {
fn serialize_with_interner<S: Serializer>(&self, serializer: S, _: &Interner) -> ::std::result::Result<S::Ok, S::Error> {
self.serialize(serializer)
}
}
)*
}
}
derive_serialize_with_interner! {
direct: u32, u64, usize, PathBuf
}