use std::collections::HashMap; use std::fmt::Debug; use std::hash::Hash; use std::vec; use async_trait::async_trait; pub trait Msg { type Id: Clone + Debug + Hash + Eq + Ord; fn id(&self) -> Self::Id; fn parent(&self) -> Option; fn seen(&self) -> bool; fn last_possible_id() -> Self::Id; } #[derive(PartialEq, Eq, PartialOrd, Ord)] pub struct Path(Vec); impl Path { pub fn new(segments: Vec) -> Self { assert!(!segments.is_empty(), "segments must not be empty"); Self(segments) } pub fn parent_segments(&self) -> impl Iterator { self.0.iter().take(self.0.len() - 1) } pub fn push(&mut self, segment: I) { self.0.push(segment) } pub fn first(&self) -> &I { self.0.first().expect("path is not empty") } } impl IntoIterator for Path { type Item = I; type IntoIter = vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } pub struct Tree { root: M::Id, msgs: HashMap, children: HashMap>, } impl Tree { pub fn new(root: M::Id, msgs: Vec) -> Self { let msgs: HashMap = msgs.into_iter().map(|m| (m.id(), m)).collect(); let mut children: HashMap> = HashMap::new(); for msg in msgs.values() { children.entry(msg.id()).or_default(); if let Some(parent) = msg.parent() { children.entry(parent).or_default().push(msg.id()); } } for list in children.values_mut() { list.sort_unstable(); } Self { root, msgs, children, } } pub fn len(&self) -> usize { self.msgs.len() } pub fn root(&self) -> &M::Id { &self.root } pub fn msg(&self, id: &M::Id) -> Option<&M> { self.msgs.get(id) } pub fn parent(&self, id: &M::Id) -> Option { self.msg(id).and_then(|m| m.parent()) } pub fn children(&self, id: &M::Id) -> Option<&[M::Id]> { self.children.get(id).map(|c| c as &[M::Id]) } pub fn subtree_size(&self, id: &M::Id) -> usize { let children = self.children(id).unwrap_or_default(); let mut result = children.len(); for child in children { result += self.subtree_size(child); } result } pub fn siblings(&self, id: &M::Id) -> Option<&[M::Id]> { if let Some(parent) = self.parent(id) { self.children(&parent) } else { None } } pub fn prev_sibling(&self, id: &M::Id) -> Option { let siblings = self.siblings(id)?; siblings .iter() .zip(siblings.iter().skip(1)) .find(|(_, s)| *s == id) .map(|(s, _)| s.clone()) } pub fn next_sibling(&self, id: &M::Id) -> Option { let siblings = self.siblings(id)?; siblings .iter() .zip(siblings.iter().skip(1)) .find(|(s, _)| *s == id) .map(|(_, s)| s.clone()) } } #[async_trait] pub trait MsgStore { async fn path(&self, id: &M::Id) -> Path; async fn tree(&self, tree_id: &M::Id) -> Tree; async fn first_tree_id(&self) -> Option; async fn last_tree_id(&self) -> Option; async fn prev_tree_id(&self, tree_id: &M::Id) -> Option; async fn next_tree_id(&self, tree_id: &M::Id) -> Option; async fn oldest_msg_id(&self) -> Option; async fn newest_msg_id(&self) -> Option; async fn older_msg_id(&self, id: &M::Id) -> Option; async fn newer_msg_id(&self, id: &M::Id) -> Option; async fn oldest_unseen_msg_id(&self) -> Option; async fn newest_unseen_msg_id(&self) -> Option; async fn older_unseen_msg_id(&self, id: &M::Id) -> Option; async fn newer_unseen_msg_id(&self, id: &M::Id) -> Option; async fn unseen_msgs_count(&self) -> usize; async fn set_seen(&self, id: &M::Id, seen: bool); async fn set_older_seen(&self, id: &M::Id, seen: bool); }