use super::Value;
use crate::prelude::*;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::ops::{Index, IndexMut};
use indexmap::IndexMap;
use indexmap::map::{IntoIter, Iter, IterMut, Keys, Values, ValuesMut};
use rustc_hash::FxBuildHasher;
use serde::{Deserialize, Serialize};
type FxIndexMap<K, V> = IndexMap<K, V, FxBuildHasher>;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Mapping(FxIndexMap<String, Value>);
impl Mapping {
#[must_use]
pub fn new() -> Self {
Self(FxIndexMap::default())
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self(FxIndexMap::with_capacity_and_hasher(
capacity,
FxBuildHasher,
))
}
#[must_use]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn clear(&mut self) {
self.0.clear();
}
pub fn insert(&mut self, key: impl Into<String>, value: Value) -> Option<Value> {
self.0.insert(key.into(), value)
}
#[must_use]
pub fn contains_key(&self, key: &str) -> bool {
self.0.contains_key(key)
}
#[must_use]
pub fn get(&self, key: &str) -> Option<&Value> {
self.0.get(key)
}
#[must_use]
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.0.get_mut(key)
}
#[must_use]
pub fn get_index(&self, index: usize) -> Option<(&String, &Value)> {
self.0.get_index(index)
}
#[must_use]
pub fn get_index_mut(&mut self, index: usize) -> Option<(&String, &mut Value)> {
self.0.get_index_mut(index)
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn remove_entry(&mut self, key: &str) -> Option<(String, Value)> {
self.0.shift_remove_entry(key)
}
pub fn swap_remove(&mut self, key: &str) -> Option<Value> {
self.0.swap_remove(key)
}
pub fn shift_remove(&mut self, key: &str) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn entry(&mut self, key: impl Into<String>) -> indexmap::map::Entry<'_, String, Value> {
self.0.entry(key.into())
}
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&String, &mut Value) -> bool,
{
self.0.retain(f);
}
#[must_use]
pub fn iter(&self) -> Iter<'_, String, Value> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, String, Value> {
self.0.iter_mut()
}
#[must_use]
pub fn keys(&self) -> Keys<'_, String, Value> {
self.0.keys()
}
#[must_use]
pub fn values(&self) -> Values<'_, String, Value> {
self.0.values()
}
pub fn values_mut(&mut self) -> ValuesMut<'_, String, Value> {
self.0.values_mut()
}
#[must_use]
pub fn first(&self) -> Option<(&String, &Value)> {
self.0.first()
}
#[must_use]
pub fn first_mut(&mut self) -> Option<(&String, &mut Value)> {
self.0.first_mut()
}
#[must_use]
pub fn last(&self) -> Option<(&String, &Value)> {
self.0.last()
}
#[must_use]
pub fn last_mut(&mut self) -> Option<(&String, &mut Value)> {
self.0.last_mut()
}
pub fn pop_first(&mut self) -> Option<(String, Value)> {
self.0.shift_remove_index(0)
}
pub fn pop_last(&mut self) -> Option<(String, Value)> {
self.0.pop()
}
pub fn sort_keys(&mut self) {
self.0.sort_keys();
}
pub fn reverse(&mut self) {
self.0.reverse();
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (String, Value)>,
{
self.0.extend(iter);
}
#[must_use]
pub fn into_inner(self) -> IndexMap<String, Value> {
self.0.into_iter().collect()
}
#[must_use]
pub fn from_inner(map: IndexMap<String, Value>) -> Self {
Self(map.into_iter().collect())
}
}
impl Index<&str> for Mapping {
type Output = Value;
#[track_caller]
fn index(&self, key: &str) -> &Self::Output {
self.0.get(key).expect("key not found in mapping")
}
}
impl IndexMut<&str> for Mapping {
#[track_caller]
fn index_mut(&mut self, key: &str) -> &mut Self::Output {
self.0.get_mut(key).expect("key not found in mapping")
}
}
impl IntoIterator for Mapping {
type Item = (String, Value);
type IntoIter = IntoIter<String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a Mapping {
type Item = (&'a String, &'a Value);
type IntoIter = Iter<'a, String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut Mapping {
type Item = (&'a String, &'a mut Value);
type IntoIter = IterMut<'a, String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl FromIterator<(String, Value)> for Mapping {
fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
Self(FxIndexMap::from_iter(iter))
}
}
impl<const N: usize> From<[(String, Value); N]> for Mapping {
fn from(arr: [(String, Value); N]) -> Self {
let mut map = FxIndexMap::with_capacity_and_hasher(N, FxBuildHasher);
for (k, v) in arr {
let _ = map.insert(k, v);
}
Self(map)
}
}
impl From<IndexMap<String, Value>> for Mapping {
fn from(map: IndexMap<String, Value>) -> Self {
Self(map.into_iter().collect())
}
}
impl From<FxIndexMap<String, Value>> for Mapping {
fn from(map: FxIndexMap<String, Value>) -> Self {
Self(map)
}
}
impl From<Mapping> for IndexMap<String, Value> {
fn from(map: Mapping) -> Self {
map.0.into_iter().collect()
}
}
impl From<Mapping> for FxIndexMap<String, Value> {
fn from(map: Mapping) -> Self {
map.0
}
}
impl From<Vec<(String, Value)>> for Mapping {
fn from(v: Vec<(String, Value)>) -> Self {
Self(v.into_iter().collect())
}
}
impl Hash for Mapping {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.len().hash(state);
for (k, v) in &self.0 {
k.hash(state);
v.hash(state);
}
}
}
impl PartialOrd for Mapping {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Mapping {
fn cmp(&self, other: &Self) -> Ordering {
self.len().cmp(&other.len()).then_with(|| {
for ((ak, av), (bk, bv)) in self.iter().zip(other.iter()) {
match ak.cmp(bk) {
Ordering::Equal => {}
ord => return ord,
}
match av.cmp(bv) {
Ordering::Equal => continue,
ord => return ord,
}
}
Ordering::Equal
})
}
}
impl fmt::Display for Mapping {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?;
for (i, (k, v)) in self.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{k}: {v}")?;
}
write!(f, "}}")
}
}
impl Serialize for Mapping {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(self.len()))?;
for (k, v) in self {
map.serialize_entry(k, v)?;
}
map.end()
}
}
impl<'de> Deserialize<'de> for Mapping {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{MapAccess, Visitor};
struct MappingVisitor;
impl<'de> Visitor<'de> for MappingVisitor {
type Value = Mapping;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a YAML mapping")
}
fn visit_map<A>(self, mut map: A) -> Result<Mapping, A::Error>
where
A: MapAccess<'de>,
{
let mut mapping = Mapping::with_capacity(map.size_hint().unwrap_or(0));
while let Some((key, value)) = map.next_entry::<String, Value>()? {
let _ = mapping.insert(key, value);
}
Ok(mapping)
}
}
deserializer.deserialize_map(MappingVisitor)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct MappingAny(FxIndexMap<Value, Value>);
impl MappingAny {
#[must_use]
pub fn new() -> Self {
Self(FxIndexMap::default())
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self(FxIndexMap::with_capacity_and_hasher(
capacity,
FxBuildHasher,
))
}
#[must_use]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.0.shrink_to_fit();
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn clear(&mut self) {
self.0.clear();
}
pub fn insert(&mut self, key: Value, value: Value) -> Option<Value> {
self.0.insert(key, value)
}
#[must_use]
pub fn contains_key(&self, key: &Value) -> bool {
self.0.contains_key(key)
}
#[must_use]
pub fn get(&self, key: &Value) -> Option<&Value> {
self.0.get(key)
}
#[must_use]
pub fn get_mut(&mut self, key: &Value) -> Option<&mut Value> {
self.0.get_mut(key)
}
#[must_use]
pub fn get_index(&self, index: usize) -> Option<(&Value, &Value)> {
self.0.get_index(index)
}
#[must_use]
pub fn get_index_mut(&mut self, index: usize) -> Option<(&Value, &mut Value)> {
self.0.get_index_mut(index)
}
pub fn remove(&mut self, key: &Value) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn remove_entry(&mut self, key: &Value) -> Option<(Value, Value)> {
self.0.shift_remove_entry(key)
}
pub fn swap_remove(&mut self, key: &Value) -> Option<Value> {
self.0.swap_remove(key)
}
pub fn shift_remove(&mut self, key: &Value) -> Option<Value> {
self.0.shift_remove(key)
}
pub fn entry(&mut self, key: Value) -> indexmap::map::Entry<'_, Value, Value> {
self.0.entry(key)
}
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&Value, &mut Value) -> bool,
{
self.0.retain(f);
}
#[must_use]
pub fn iter(&self) -> Iter<'_, Value, Value> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, Value, Value> {
self.0.iter_mut()
}
#[must_use]
pub fn keys(&self) -> Keys<'_, Value, Value> {
self.0.keys()
}
#[must_use]
pub fn values(&self) -> Values<'_, Value, Value> {
self.0.values()
}
pub fn values_mut(&mut self) -> ValuesMut<'_, Value, Value> {
self.0.values_mut()
}
#[must_use]
pub fn first(&self) -> Option<(&Value, &Value)> {
self.0.first()
}
#[must_use]
pub fn first_mut(&mut self) -> Option<(&Value, &mut Value)> {
self.0.first_mut()
}
#[must_use]
pub fn last(&self) -> Option<(&Value, &Value)> {
self.0.last()
}
#[must_use]
pub fn last_mut(&mut self) -> Option<(&Value, &mut Value)> {
self.0.last_mut()
}
pub fn pop_first(&mut self) -> Option<(Value, Value)> {
self.0.shift_remove_index(0)
}
pub fn pop_last(&mut self) -> Option<(Value, Value)> {
self.0.pop()
}
pub fn sort_keys(&mut self) {
self.0.sort_keys();
}
pub fn reverse(&mut self) {
self.0.reverse();
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (Value, Value)>,
{
self.0.extend(iter);
}
#[must_use]
pub fn into_inner(self) -> IndexMap<Value, Value> {
self.0.into_iter().collect()
}
#[must_use]
pub fn from_inner(map: IndexMap<Value, Value>) -> Self {
Self(map.into_iter().collect())
}
#[must_use]
pub fn into_mapping(self) -> Option<Mapping> {
let mut mapping = Mapping::with_capacity(self.len());
for (k, v) in self.0 {
if let Value::String(s) = k {
let _ = mapping.insert(s, v);
} else {
return None;
}
}
Some(mapping)
}
}
impl Index<&Value> for MappingAny {
type Output = Value;
#[track_caller]
fn index(&self, key: &Value) -> &Self::Output {
self.0.get(key).expect("key not found in mapping")
}
}
impl IndexMut<&Value> for MappingAny {
#[track_caller]
fn index_mut(&mut self, key: &Value) -> &mut Self::Output {
self.0.get_mut(key).expect("key not found in mapping")
}
}
impl IntoIterator for MappingAny {
type Item = (Value, Value);
type IntoIter = IntoIter<Value, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a MappingAny {
type Item = (&'a Value, &'a Value);
type IntoIter = Iter<'a, Value, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut MappingAny {
type Item = (&'a Value, &'a mut Value);
type IntoIter = IterMut<'a, Value, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl FromIterator<(Value, Value)> for MappingAny {
fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
Self(IndexMap::from_iter(iter))
}
}
impl<const N: usize> From<[(Value, Value); N]> for MappingAny {
fn from(arr: [(Value, Value); N]) -> Self {
let mut map = FxIndexMap::with_capacity_and_hasher(N, FxBuildHasher);
for (k, v) in arr {
let _ = map.insert(k, v);
}
Self(map)
}
}
impl From<IndexMap<Value, Value>> for MappingAny {
fn from(map: IndexMap<Value, Value>) -> Self {
Self(map.into_iter().collect())
}
}
impl From<FxIndexMap<Value, Value>> for MappingAny {
fn from(map: FxIndexMap<Value, Value>) -> Self {
Self(map)
}
}
impl From<MappingAny> for IndexMap<Value, Value> {
fn from(map: MappingAny) -> Self {
map.0.into_iter().collect()
}
}
impl From<MappingAny> for FxIndexMap<Value, Value> {
fn from(map: MappingAny) -> Self {
map.0
}
}
impl From<Mapping> for MappingAny {
fn from(map: Mapping) -> Self {
let mut any = MappingAny::with_capacity(map.len());
for (k, v) in map {
let _ = any.insert(Value::String(k), v);
}
any
}
}
impl Hash for MappingAny {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.len().hash(state);
for (k, v) in &self.0 {
k.hash(state);
v.hash(state);
}
}
}
impl PartialOrd for MappingAny {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MappingAny {
fn cmp(&self, other: &Self) -> Ordering {
self.len().cmp(&other.len()).then_with(|| {
for ((ak, av), (bk, bv)) in self.iter().zip(other.iter()) {
match ak.cmp(bk) {
Ordering::Equal => {}
ord => return ord,
}
match av.cmp(bv) {
Ordering::Equal => continue,
ord => return ord,
}
}
Ordering::Equal
})
}
}
impl fmt::Display for MappingAny {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?;
for (i, (k, v)) in self.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{k}: {v}")?;
}
write!(f, "}}")
}
}
impl Serialize for MappingAny {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(self.len()))?;
for (k, v) in self {
map.serialize_entry(k, v)?;
}
map.end()
}
}
impl<'de> Deserialize<'de> for MappingAny {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{MapAccess, Visitor};
struct MappingAnyVisitor;
impl<'de> Visitor<'de> for MappingAnyVisitor {
type Value = MappingAny;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a YAML mapping")
}
fn visit_map<A>(self, mut map: A) -> Result<MappingAny, A::Error>
where
A: MapAccess<'de>,
{
let mut mapping = MappingAny::with_capacity(map.size_hint().unwrap_or(0));
while let Some((key, value)) = map.next_entry::<Value, Value>()? {
let _ = mapping.insert(key, value);
}
Ok(mapping)
}
}
deserializer.deserialize_map(MappingAnyVisitor)
}
}