use std::fmt;
use std::hash::BuildHasherDefault;
use std::iter::FusedIterator;
use compact_str::CompactString;
use fnv::FnvHasher;
use indexmap::IndexMap;
use super::ElementProperty;
pub(crate) type PropertyMapInner =
IndexMap<CompactString, ElementProperty, BuildHasherDefault<FnvHasher>>;
#[repr(transparent)]
#[derive(Default, Eq)]
pub struct PropertyMap(pub(crate) PropertyMapInner);
impl Clone for PropertyMap {
#[inline(always)]
fn clone(&self) -> Self {
Self(self.0.clone())
}
#[inline(always)]
fn clone_from(&mut self, source: &Self) {
self.0.clone_from(&source.0);
}
}
impl PartialEq for PropertyMap {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl PropertyMap {
#[inline]
pub fn new() -> Self {
Self(PropertyMapInner::default())
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self(PropertyMapInner::with_capacity_and_hasher(
capacity,
BuildHasherDefault::default(),
))
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn get(&self, key: &str) -> Option<&ElementProperty> {
self.0.get(key)
}
#[inline]
pub fn get_mut(&mut self, key: &str) -> Option<&mut ElementProperty> {
self.0.get_mut(key)
}
#[inline]
pub fn contains_key(&self, key: &str) -> bool {
self.0.contains_key(key)
}
#[inline]
pub fn insert(
&mut self,
key: impl Into<CompactString>,
value: ElementProperty,
) -> Option<ElementProperty> {
self.0.insert(key.into(), value)
}
#[inline]
pub fn shift_remove(&mut self, key: &str) -> Option<ElementProperty> {
self.0.shift_remove(key)
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter(self.0.iter())
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_> {
IterMut(self.0.iter_mut())
}
#[inline]
pub fn keys(&self) -> Keys<'_> {
Keys(self.0.keys())
}
#[inline]
pub fn values(&self) -> Values<'_> {
Values(self.0.values())
}
#[inline]
pub fn values_mut(&mut self) -> ValuesMut<'_> {
ValuesMut(self.0.values_mut())
}
#[inline]
pub fn clear(&mut self) {
self.0.clear();
}
}
impl fmt::Debug for PropertyMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl std::ops::Index<&str> for PropertyMap {
type Output = ElementProperty;
#[inline]
fn index(&self, key: &str) -> &ElementProperty {
&self.0[key]
}
}
impl<K: Into<CompactString>> FromIterator<(K, ElementProperty)> for PropertyMap {
#[inline]
fn from_iter<I: IntoIterator<Item = (K, ElementProperty)>>(iter: I) -> Self {
Self(iter.into_iter().map(|(k, v)| (k.into(), v)).collect())
}
}
impl<K: Into<CompactString>> Extend<(K, ElementProperty)> for PropertyMap {
#[inline]
fn extend<I: IntoIterator<Item = (K, ElementProperty)>>(&mut self, iter: I) {
self.0.extend(iter.into_iter().map(|(k, v)| (k.into(), v)));
}
}
impl<K: Into<CompactString>, const N: usize> From<[(K, ElementProperty); N]> for PropertyMap {
#[inline]
fn from(entries: [(K, ElementProperty); N]) -> Self {
entries.into_iter().collect()
}
}
impl IntoIterator for PropertyMap {
type Item = (CompactString, ElementProperty);
type IntoIter = IntoIter;
#[inline]
fn into_iter(self) -> IntoIter {
IntoIter(self.0.into_iter())
}
}
impl<'a> IntoIterator for &'a PropertyMap {
type Item = (&'a CompactString, &'a ElementProperty);
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Iter<'a> {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut PropertyMap {
type Item = (&'a CompactString, &'a mut ElementProperty);
type IntoIter = IterMut<'a>;
#[inline]
fn into_iter(self) -> IterMut<'a> {
self.iter_mut()
}
}
macro_rules! wrap_iter {
($name:ident<$lt:lifetime>, $item:ty) => {
impl<$lt> Iterator for $name<$lt> {
type Item = $item;
#[inline]
fn next(&mut self) -> Option<$item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<$lt> DoubleEndedIterator for $name<$lt> {
#[inline]
fn next_back(&mut self) -> Option<$item> {
self.0.next_back()
}
}
impl<$lt> ExactSizeIterator for $name<$lt> {}
impl<$lt> FusedIterator for $name<$lt> {}
};
}
#[derive(Clone)]
pub struct Iter<'a>(indexmap::map::Iter<'a, CompactString, ElementProperty>);
wrap_iter!(Iter<'a>, (&'a CompactString, &'a ElementProperty));
impl fmt::Debug for Iter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.clone()).finish()
}
}
pub struct IterMut<'a>(indexmap::map::IterMut<'a, CompactString, ElementProperty>);
wrap_iter!(IterMut<'a>, (&'a CompactString, &'a mut ElementProperty));
impl fmt::Debug for IterMut<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IterMut")
.field("remaining", &self.0.len())
.finish()
}
}
#[derive(Clone)]
pub struct Keys<'a>(indexmap::map::Keys<'a, CompactString, ElementProperty>);
wrap_iter!(Keys<'a>, &'a CompactString);
impl fmt::Debug for Keys<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.clone()).finish()
}
}
#[derive(Clone)]
pub struct Values<'a>(indexmap::map::Values<'a, CompactString, ElementProperty>);
wrap_iter!(Values<'a>, &'a ElementProperty);
impl fmt::Debug for Values<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.clone()).finish()
}
}
pub struct ValuesMut<'a>(indexmap::map::ValuesMut<'a, CompactString, ElementProperty>);
wrap_iter!(ValuesMut<'a>, &'a mut ElementProperty);
impl fmt::Debug for ValuesMut<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ValuesMut")
.field("remaining", &self.0.len())
.finish()
}
}
pub struct IntoIter(indexmap::map::IntoIter<CompactString, ElementProperty>);
impl Iterator for IntoIter {
type Item = (CompactString, ElementProperty);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl DoubleEndedIterator for IntoIter {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for IntoIter {}
impl FusedIterator for IntoIter {}
impl fmt::Debug for IntoIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IntoIter")
.field("remaining", &self.0.len())
.finish()
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::{PropertyMap, PropertyMapInner};
impl Serialize for PropertyMap {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for PropertyMap {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
PropertyMapInner::deserialize(deserializer).map(PropertyMap)
}
}
}
#[cfg(test)]
mod tests {
use super::{PropertyMap, PropertyMapInner};
use crate::value::ElementProperty;
#[test]
fn the_newtype_costs_nothing() {
assert_eq!(size_of::<PropertyMap>(), size_of::<PropertyMapInner>());
assert_eq!(align_of::<PropertyMap>(), align_of::<PropertyMapInner>());
assert_eq!(size_of::<ElementProperty>(), 32);
}
#[test]
fn keeps_insertion_order_and_compares_unordered() {
let mut a = PropertyMap::new();
a.insert("b", ElementProperty::from(1));
a.insert("a", ElementProperty::from(2));
a.insert("b", ElementProperty::from(3));
assert_eq!(a.keys().map(|k| k.as_str()).collect::<Vec<_>>(), ["b", "a"]);
assert_eq!(a["b"], ElementProperty::from(3));
let b: PropertyMap = [
("a", ElementProperty::from(2)),
("b", ElementProperty::from(3)),
]
.into_iter()
.collect();
assert_eq!(a, b);
assert_eq!(a.shift_remove("b"), Some(ElementProperty::from(3)));
assert!(!a.contains_key("b"));
a.extend([("c", ElementProperty::Null)]);
for value in a.values_mut() {
*value = ElementProperty::Null;
}
let owned: Vec<_> = a.clone().into_iter().collect();
assert_eq!(owned.len(), 2);
assert_eq!((&a).into_iter().len(), 2);
a.clear();
assert!(a.is_empty());
}
}