use super::PathSegment;
use std::collections::HashMap;
#[derive(Debug, Clone, Default)]
pub(crate) struct Children {
keys: HashMap<String, Vec<Option<usize>>>,
elements: HashMap<usize, usize>,
}
impl Children {
pub(crate) fn key(&self, key: &str, index: usize) -> Option<usize> {
self.keys.get(key)?.get(index).copied().flatten()
}
pub(crate) fn element(&self, index: usize) -> Option<usize> {
self.elements.get(&index).copied()
}
pub(crate) fn get(&self, segment: &PathSegment) -> Option<usize> {
match segment {
PathSegment::Key { key, index } => self.key(key, *index),
PathSegment::Index(index) => self.element(*index),
}
}
pub(crate) fn insert(&mut self, segment: &PathSegment, child: usize) {
match segment {
PathSegment::Key { key, index } => {
let values = self.keys.entry(key.clone()).or_default();
if values.len() <= *index {
values.resize(*index + 1, None);
}
values[*index] = Some(child);
}
PathSegment::Index(index) => {
self.elements.insert(*index, child);
}
}
}
pub(crate) fn take_value(&mut self, key: &str, index: usize) -> Option<usize> {
self.keys.get_mut(key)?.get_mut(index)?.take()
}
pub(crate) fn take_values(&mut self, key: &str) -> Vec<(usize, usize)> {
self.keys.remove(key).map_or_else(Vec::new, |values| {
values
.into_iter()
.enumerate()
.filter_map(|(index, child)| Some((index, child?)))
.collect()
})
}
pub(crate) fn iter(&self) -> impl Iterator<Item = (PathSegment, usize)> + '_ {
let keyed = self.keys.iter().flat_map(|(key, values)| {
values.iter().enumerate().filter_map(move |(index, child)| {
Some((
PathSegment::Key {
key: key.clone(),
index,
},
(*child)?,
))
})
});
let elements = self
.elements
.iter()
.map(|(&index, &child)| (PathSegment::Index(index), child));
keyed.chain(elements)
}
pub(crate) fn take_all(&mut self) -> Vec<usize> {
let keyed = self.keys.drain().flat_map(|(_, values)| values).flatten();
let mut all: Vec<usize> = keyed.collect();
all.extend(self.elements.drain().map(|(_, child)| child));
all
}
}