use std::{
hash::{BuildHasher, Hasher},
ops::{Index, IndexMut},
};
use hashlink::LinkedHashMap;
use saphyr_parser::{ScalarStyle, Tag};
use crate::{annotated::AnnotatedNodeOwned, ScalarOwned};
#[derive(Clone, PartialEq, PartialOrd, Debug, Eq, Ord, Hash)]
pub enum YamlDataOwned<Node>
where
Node: std::hash::Hash + std::cmp::Eq + From<Self> + AnnotatedNodeOwned,
{
Representation(String, ScalarStyle, Option<Tag>),
Value(ScalarOwned),
Sequence(AnnotatedSequenceOwned<Node>),
Mapping(AnnotatedMappingOwned<Node>),
Tagged(Tag, Box<Node>),
Alias(usize),
BadValue,
}
define_yaml_object_impl!(
YamlDataOwned<Node>,
< Node>,
where {
Node: std::hash::Hash
+ std::cmp::Eq
+ From<Self>
+ AnnotatedNodeOwned
+ std::cmp::PartialEq<Node::HashKey>,
},
mappingtype = AnnotatedMappingOwned<Node>,
sequencetype = AnnotatedSequenceOwned<Node>,
nodetype = Node,
scalartype = { ScalarOwned },
selfname = "YamlDataOwned",
owned
);
impl<Node> YamlDataOwned<Node>
where
Node: std::hash::Hash
+ std::cmp::Eq
+ From<Self>
+ AnnotatedNodeOwned
+ std::cmp::PartialEq<Node::HashKey>,
{
#[must_use]
pub fn take(&mut self) -> Self {
let mut taken_out = Self::BadValue;
std::mem::swap(self, &mut taken_out);
taken_out
}
fn as_mapping_get_impl(&self, key: &str) -> Option<&Node> {
use std::hash::Hash;
match self {
Self::Mapping(mapping) => {
let needle =
Node::HashKey::from(YamlDataOwned::Value(ScalarOwned::String(key.into())));
let mut hasher = mapping.hasher().build_hasher();
needle.hash(&mut hasher);
let hash = hasher.finish();
mapping
.raw_entry()
.from_hash(hash, |candidate| *candidate == needle)
.map(|(_, v)| v)
}
_ => None,
}
}
#[must_use]
fn as_mapping_get_mut_impl(&mut self, key: &str) -> Option<&mut Node> {
match self.as_mapping_mut() {
Some(mapping) => {
use hashlink::linked_hash_map::RawEntryMut::{Occupied, Vacant};
use std::hash::Hash;
let needle =
Node::HashKey::from(YamlDataOwned::Value(ScalarOwned::String(key.to_string())));
let mut hasher = mapping.hasher().build_hasher();
needle.hash(&mut hasher);
let hash = hasher.finish();
match mapping
.raw_entry_mut()
.from_hash(hash, |candidate| *candidate == needle)
{
Occupied(entry) => Some(entry.into_mut()),
Vacant(_) => None,
}
}
_ => None,
}
}
}
impl<Node> IntoIterator for YamlDataOwned<Node>
where
Node: std::hash::Hash
+ std::cmp::Eq
+ From<Self>
+ AnnotatedNodeOwned
+ std::cmp::PartialEq<Node::HashKey>,
{
type Item = Node;
type IntoIter = AnnotatedYamlOwnedIter<Node>;
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter {
yaml: self.into_vec().unwrap_or_default().into_iter(),
}
}
}
#[allow(clippy::module_name_repetitions)]
pub struct AnnotatedYamlOwnedIter<Node>
where
Node: std::hash::Hash + std::cmp::Eq + From<YamlDataOwned<Node>> + AnnotatedNodeOwned,
{
yaml: std::vec::IntoIter<Node>,
}
impl<Node> Iterator for AnnotatedYamlOwnedIter<Node>
where
Node: std::hash::Hash + std::cmp::Eq + From<YamlDataOwned<Node>> + AnnotatedNodeOwned,
{
type Item = Node;
fn next(&mut self) -> Option<Node> {
self.yaml.next()
}
}
#[allow(clippy::module_name_repetitions)]
pub type AnnotatedSequenceOwned<Node> = Vec<Node>;
#[allow(clippy::module_name_repetitions)]
pub type AnnotatedMappingOwned<Node> = LinkedHashMap<Node, Node>;