use std::{cmp, fmt, iter::Iterator};
pub use num_traits::bounds::{LowerBounded, UpperBounded};
use num_traits::{Bounded, CheckedAdd, CheckedSub, One};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct GranularId<T> {
id: Vec<T>,
}
impl<T: fmt::Display> fmt::Display for GranularId<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut iter = self.id.iter();
if let Some(x) = iter.next() {
write!(f, "{x}")?;
for x in iter {
write!(f, ".{x}")?;
}
} else {
write!(f, "<root>")?;
}
Ok(())
}
}
impl<T> PartialOrd for GranularId<T>
where
T: Ord,
{
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T> Ord for GranularId<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> cmp::Ordering {
Iterator::zip(self.id.iter(), &other.id)
.map(|(a, b)| a.cmp(b))
.find(|x| *x != cmp::Ordering::Equal)
.unwrap_or_else(|| self.id.len().cmp(&other.id.len()))
}
}
impl<T> LowerBounded for GranularId<T> {
fn min_value() -> Self {
Self { id: vec![] }
}
}
impl<T> UpperBounded for GranularId<T>
where
T: UpperBounded,
{
fn max_value() -> Self {
Self {
id: vec![T::max_value()],
}
}
}
impl<T> From<Vec<T>> for GranularId<T>
where
T: PartialEq + UpperBounded,
{
fn from(other: Vec<T>) -> Self {
if other.first().map_or(false, |x| x == &T::max_value()) {
Self {
id: vec![T::max_value()],
}
} else {
Self { id: other }
}
}
}
impl<T> From<&[T]> for GranularId<T>
where
T: PartialEq + UpperBounded + Clone,
{
fn from(other: &[T]) -> Self {
if other.first().map_or(false, |x| x == &T::max_value()) {
Self {
id: vec![T::max_value()],
}
} else {
Self { id: other.to_vec() }
}
}
}
impl<T> From<GranularId<T>> for Vec<T> {
fn from(other: GranularId<T>) -> Vec<T> {
other.id
}
}
impl<T> GranularId<T>
where
T: SequentialId,
{
#[must_use]
pub fn all_siblings(&self) -> SequentialIds<T>
where
T: LowerBounded,
{
let mut id = self.id.clone();
id.pop();
SequentialIds {
current: Some(T::min_value()),
base: id,
}
}
#[must_use]
pub fn next_siblings(&self) -> SequentialIds<T>
where
T: CheckedAdd,
{
let mut id = self.id.clone();
let current = id.pop().and_then(|x| x.checked_add(&T::one()));
SequentialIds { current, base: id }
}
#[must_use]
pub fn children(&self) -> SequentialIds<T>
where
T: LowerBounded,
{
SequentialIds {
current: Some(T::min_value()),
base: self.id.clone(),
}
}
}
impl<T> GranularId<T>
where
T: BackSequentialId,
{
#[must_use]
pub fn previous_siblings(&self) -> BackSequentialIds<T>
where
T: Bounded + One + Clone + CheckedSub,
{
let mut id = self.id.clone();
let current = id.pop().and_then(|x| x.checked_sub(&T::one()));
BackSequentialIds { current, base: id }
}
}
impl<T> GranularId<T> {
#[must_use]
pub fn is_max_value(&self) -> bool
where
T: UpperBounded + PartialEq,
{
self == &Self::max_value()
}
#[must_use]
pub fn granularity(&self) -> usize {
self.id.len()
}
#[must_use]
pub fn is_root(&self) -> bool {
self.id.is_empty()
}
#[must_use]
pub fn into_parent(mut self) -> Option<Self> {
if self.id.is_empty() {
return None;
}
self.id.pop();
Some(self)
}
#[must_use]
pub fn parent(&self) -> Option<Self>
where
T: Clone,
{
if self.id.is_empty() {
return None;
}
let mut id = self.id.clone();
id.pop();
Some(Self { id })
}
#[must_use]
pub fn into_ancestors(self) -> Ancestors<T> {
Ancestors {
current: Some(self),
}
}
#[must_use]
pub fn ancestors(&self) -> Ancestors<T>
where
T: Clone,
{
Ancestors {
current: Some(self.clone()),
}
}
pub fn pop(&mut self) -> Option<T> {
self.id.pop()
}
pub fn push(&mut self, component: T)
where
T: UpperBounded + PartialEq,
{
if self != &Self::max_value() {
self.id.push(component);
}
}
#[must_use]
pub fn pushing(&self, component: T) -> Self
where
T: UpperBounded + PartialEq + Clone,
{
if self == &Self::max_value() {
self.clone()
} else {
let mut id = self.id.clone();
id.push(component);
Self { id }
}
}
pub fn append(&mut self, mut other: GranularId<T>)
where
T: UpperBounded + PartialEq,
{
if self != &Self::max_value() {
self.id.append(&mut other.id);
}
}
#[must_use]
pub fn appending(&self, mut other: GranularId<T>) -> GranularId<T>
where
T: UpperBounded + PartialEq + Clone,
{
if self == &Self::max_value() {
self.clone()
} else {
let mut id = self.id.clone();
id.append(&mut other.id);
Self { id }
}
}
pub fn append_vec(&mut self, mut other: Vec<T>)
where
T: UpperBounded + PartialEq,
{
if self.id.is_empty() {
let other_id: GranularId<T> = other.into();
self.id = other_id.id;
} else if self != &Self::max_value() {
self.id.append(&mut other);
}
}
#[must_use]
pub fn appending_vec(&self, mut other: Vec<T>) -> GranularId<T>
where
T: UpperBounded + PartialEq + Clone,
{
if self.id.is_empty() {
other.into()
} else if self != &Self::max_value() {
let mut id = self.id.clone();
id.append(&mut other);
Self { id }
} else {
self.clone()
}
}
#[must_use]
pub fn root() -> Self {
Self { id: vec![] }
}
}
impl<T> IntoIterator for GranularId<T> {
type Item = T;
type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.id.into_iter()
}
}
pub struct SequentialIds<T> {
current: Option<T>,
base: Vec<T>,
}
pub trait SequentialId: UpperBounded + One + Clone + PartialEq + Ord + CheckedAdd {}
impl<T: UpperBounded + One + Clone + PartialEq + Ord + CheckedAdd> SequentialId for T {}
impl<T> Iterator for SequentialIds<T>
where
T: SequentialId,
{
type Item = GranularId<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.base.first().map_or(false, |x| x >= &T::max_value()) {
return None;
}
let x = self.current.as_ref()?;
let mut id = self.base.clone();
id.push(x.clone());
self.current = x.checked_add(&T::one());
Some(GranularId { id })
}
}
pub trait BackSequentialId: Bounded + One + Clone + CheckedSub {}
impl<T: Bounded + One + Clone + CheckedSub> BackSequentialId for T {}
pub struct BackSequentialIds<T> {
current: Option<T>,
base: Vec<T>,
}
impl<T> Iterator for BackSequentialIds<T>
where
T: BackSequentialId,
{
type Item = GranularId<T>;
fn next(&mut self) -> Option<Self::Item> {
let x = self.current.as_ref()?;
let mut id = self.base.clone();
id.push(x.clone());
self.current = x.checked_sub(&T::one());
Some(GranularId { id })
}
}
pub struct Ancestors<T> {
current: Option<GranularId<T>>,
}
impl<T> Iterator for Ancestors<T>
where
T: Clone,
{
type Item = GranularId<T>;
fn next(&mut self) -> Option<Self::Item> {
self.current = self.current.as_ref().and_then(GranularId::parent);
self.current.clone()
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use super::*;
#[test]
fn keys_in_hm() {
let mut hm: HashMap<GranularId<u8>, &'static str> = HashMap::new();
let id_1: GranularId<u8> = vec![1].into();
let id_1_1: GranularId<u8> = vec![1, 1].into();
let id_2: GranularId<u8> = vec![2].into();
hm.insert(id_1.clone(), "abc");
hm.insert(id_1_1.clone(), "def");
hm.insert(id_2.clone(), "ghi");
assert_eq!(hm.get(&id_1).unwrap(), &"abc");
assert_eq!(hm.get(&id_1_1).unwrap(), &"def");
assert_eq!(hm.get(&id_2).unwrap(), &"ghi");
}
#[test]
fn readme_example() {
let id: GranularId<u8> = vec![1, 2, 3].into();
let parent = id.parent().unwrap();
assert_eq!(parent, vec![1, 2].into());
let mut next_siblings = id.next_siblings();
assert_eq!(next_siblings.next().unwrap(), vec![1, 2, 4].into());
assert_eq!(next_siblings.next().unwrap(), vec![1, 2, 5].into());
assert_eq!(next_siblings.next().unwrap(), vec![1, 2, 6].into());
let mut children = id.children();
assert_eq!(children.next().unwrap(), vec![1, 2, 3, 0].into());
assert_eq!(children.next().unwrap(), vec![1, 2, 3, 1].into());
assert_eq!(children.next().unwrap(), vec![1, 2, 3, 2].into());
assert!(parent < id);
}
}