melib: add ThreadTree
parent
2fcd014bfe
commit
630330f632
|
@ -80,6 +80,55 @@ impl FromStr for SortOrder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
struct ThreadTree {
|
||||||
|
id: usize,
|
||||||
|
children: Vec<ThreadTree>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThreadTree {
|
||||||
|
fn new(id: usize) -> Self {
|
||||||
|
ThreadTree {
|
||||||
|
id,
|
||||||
|
children: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ThreadIterator<'a> {
|
||||||
|
pos: usize,
|
||||||
|
stack: Vec<usize>,
|
||||||
|
tree: Ref<'a, Vec<ThreadTree>>,
|
||||||
|
}
|
||||||
|
impl<'a> Iterator for ThreadIterator<'a> {
|
||||||
|
type Item = usize;
|
||||||
|
fn next(&mut self) -> Option<usize> {
|
||||||
|
{
|
||||||
|
let mut tree = &(*self.tree);
|
||||||
|
for i in &self.stack {
|
||||||
|
tree = &tree[*i].children;
|
||||||
|
}
|
||||||
|
if self.pos == tree.len() {
|
||||||
|
if self.stack.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.pos = self.stack.pop().unwrap() + 1;
|
||||||
|
} else {
|
||||||
|
debug_assert!(self.pos < tree.len());
|
||||||
|
let ret = tree[self.pos].id;
|
||||||
|
if !tree[self.pos].children.is_empty() {
|
||||||
|
self.stack.push(self.pos);
|
||||||
|
self.pos = 0;
|
||||||
|
return Some(ret);
|
||||||
|
}
|
||||||
|
self.pos += 1;
|
||||||
|
return Some(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct ThreadNode {
|
pub struct ThreadNode {
|
||||||
message: Option<EnvelopeHash>,
|
message: Option<EnvelopeHash>,
|
||||||
|
@ -163,6 +212,7 @@ impl ThreadNode {
|
||||||
pub struct Threads {
|
pub struct Threads {
|
||||||
thread_nodes: Vec<ThreadNode>,
|
thread_nodes: Vec<ThreadNode>,
|
||||||
root_set: RefCell<Vec<usize>>,
|
root_set: RefCell<Vec<usize>>,
|
||||||
|
tree: RefCell<Vec<ThreadTree>>,
|
||||||
|
|
||||||
message_ids: FnvHashMap<String, usize>,
|
message_ids: FnvHashMap<String, usize>,
|
||||||
hash_set: FnvHashSet<EnvelopeHash>,
|
hash_set: FnvHashSet<EnvelopeHash>,
|
||||||
|
@ -221,6 +271,7 @@ impl Threads {
|
||||||
/* Walk over the elements of message_ids, and gather a list of the ThreadNode objects that have
|
/* Walk over the elements of message_ids, and gather a list of the ThreadNode objects that have
|
||||||
* no parents. These are the root messages of each thread */
|
* no parents. These are the root messages of each thread */
|
||||||
let mut root_set: Vec<usize> = Vec::with_capacity(collection.len());
|
let mut root_set: Vec<usize> = Vec::with_capacity(collection.len());
|
||||||
|
|
||||||
'root_set: for v in message_ids.values() {
|
'root_set: for v in message_ids.values() {
|
||||||
/* update length */
|
/* update length */
|
||||||
fn set_length(id: usize, thread_nodes: &mut Vec<ThreadNode>) -> usize {
|
fn set_length(id: usize, thread_nodes: &mut Vec<ThreadNode>) -> usize {
|
||||||
|
@ -256,6 +307,14 @@ impl Threads {
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn thread_iter(&self, index: usize) -> ThreadIterator {
|
||||||
|
ThreadIterator {
|
||||||
|
pos: index,
|
||||||
|
stack: Vec::new(),
|
||||||
|
tree: self.tree.borrow(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, collection: &mut FnvHashMap<EnvelopeHash, Envelope>) {
|
pub fn update(&mut self, collection: &mut FnvHashMap<EnvelopeHash, Envelope>) {
|
||||||
let new_hash_set = FnvHashSet::from_iter(collection.keys().cloned());
|
let new_hash_set = FnvHashSet::from_iter(collection.keys().cloned());
|
||||||
|
|
||||||
|
@ -276,14 +335,20 @@ impl Threads {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_collection(&mut self, collection: &FnvHashMap<EnvelopeHash, Envelope>) {
|
fn build_collection(&mut self, collection: &FnvHashMap<EnvelopeHash, Envelope>) {
|
||||||
for i in self.root_set.borrow().iter() {
|
{
|
||||||
node_build(
|
let tree = self.tree.get_mut();
|
||||||
*i,
|
for i in self.root_set.borrow().iter() {
|
||||||
&mut self.thread_nodes,
|
let mut tree_node = ThreadTree::new(*i);
|
||||||
0, /* indentation */
|
node_build(
|
||||||
*i, /* root_subject_idx */
|
&mut tree_node,
|
||||||
collection,
|
*i,
|
||||||
);
|
&mut self.thread_nodes,
|
||||||
|
0, /* indentation */
|
||||||
|
*i, /* root_subject_idx */
|
||||||
|
collection,
|
||||||
|
);
|
||||||
|
tree.push(tree_node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.inner_sort_by(*self.sort.borrow(), collection);
|
self.inner_sort_by(*self.sort.borrow(), collection);
|
||||||
self.inner_subsort_by(*self.subsort.borrow(), collection);
|
self.inner_subsort_by(*self.subsort.borrow(), collection);
|
||||||
|
@ -294,6 +359,43 @@ impl Threads {
|
||||||
subsort: (SortField, SortOrder),
|
subsort: (SortField, SortOrder),
|
||||||
collection: &FnvHashMap<EnvelopeHash, Envelope>,
|
collection: &FnvHashMap<EnvelopeHash, Envelope>,
|
||||||
) {
|
) {
|
||||||
|
let tree = &mut self.tree.borrow_mut();
|
||||||
|
for mut t in tree.iter_mut() {
|
||||||
|
t.children.sort_by(|a, b| match subsort {
|
||||||
|
(SortField::Date, SortOrder::Desc) => {
|
||||||
|
let a = &self.thread_nodes[a.id];
|
||||||
|
let b = &self.thread_nodes[b.id];
|
||||||
|
b.date.cmp(&a.date)
|
||||||
|
}
|
||||||
|
(SortField::Date, SortOrder::Asc) => {
|
||||||
|
let a = &self.thread_nodes[a.id];
|
||||||
|
let b = &self.thread_nodes[b.id];
|
||||||
|
a.date.cmp(&b.date)
|
||||||
|
}
|
||||||
|
(SortField::Subject, SortOrder::Desc) => {
|
||||||
|
let a = &self.thread_nodes[a.id].message();
|
||||||
|
let b = &self.thread_nodes[b.id].message();
|
||||||
|
|
||||||
|
if a.is_none() || b.is_none() {
|
||||||
|
return Ordering::Equal;
|
||||||
|
}
|
||||||
|
let ma = &collection[&a.unwrap()];
|
||||||
|
let mb = &collection[&b.unwrap()];
|
||||||
|
ma.subject().cmp(&mb.subject())
|
||||||
|
}
|
||||||
|
(SortField::Subject, SortOrder::Asc) => {
|
||||||
|
let a = &self.thread_nodes[a.id].message();
|
||||||
|
let b = &self.thread_nodes[b.id].message();
|
||||||
|
|
||||||
|
if a.is_none() || b.is_none() {
|
||||||
|
return Ordering::Equal;
|
||||||
|
}
|
||||||
|
let ma = &collection[&a.unwrap()];
|
||||||
|
let mb = &collection[&b.unwrap()];
|
||||||
|
mb.subject().cmp(&ma.subject())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_sort_by(
|
fn inner_sort_by(
|
||||||
|
@ -301,21 +403,21 @@ impl Threads {
|
||||||
sort: (SortField, SortOrder),
|
sort: (SortField, SortOrder),
|
||||||
collection: &FnvHashMap<EnvelopeHash, Envelope>,
|
collection: &FnvHashMap<EnvelopeHash, Envelope>,
|
||||||
) {
|
) {
|
||||||
let root_set = &mut self.root_set.borrow_mut();
|
let tree = &mut self.tree.borrow_mut();
|
||||||
root_set.sort_by(|a, b| match sort {
|
tree.sort_by(|a, b| match sort {
|
||||||
(SortField::Date, SortOrder::Desc) => {
|
(SortField::Date, SortOrder::Desc) => {
|
||||||
let a = &self.thread_nodes[*a];
|
let a = &self.thread_nodes[a.id];
|
||||||
let b = &self.thread_nodes[*b];
|
let b = &self.thread_nodes[b.id];
|
||||||
b.date.cmp(&a.date)
|
b.date.cmp(&a.date)
|
||||||
}
|
}
|
||||||
(SortField::Date, SortOrder::Asc) => {
|
(SortField::Date, SortOrder::Asc) => {
|
||||||
let a = &self.thread_nodes[*a];
|
let a = &self.thread_nodes[a.id];
|
||||||
let b = &self.thread_nodes[*b];
|
let b = &self.thread_nodes[b.id];
|
||||||
a.date.cmp(&b.date)
|
a.date.cmp(&b.date)
|
||||||
}
|
}
|
||||||
(SortField::Subject, SortOrder::Desc) => {
|
(SortField::Subject, SortOrder::Desc) => {
|
||||||
let a = &self.thread_nodes[*a].message();
|
let a = &self.thread_nodes[a.id].message();
|
||||||
let b = &self.thread_nodes[*b].message();
|
let b = &self.thread_nodes[b.id].message();
|
||||||
|
|
||||||
if a.is_none() || b.is_none() {
|
if a.is_none() || b.is_none() {
|
||||||
return Ordering::Equal;
|
return Ordering::Equal;
|
||||||
|
@ -325,8 +427,8 @@ impl Threads {
|
||||||
ma.subject().cmp(&mb.subject())
|
ma.subject().cmp(&mb.subject())
|
||||||
}
|
}
|
||||||
(SortField::Subject, SortOrder::Asc) => {
|
(SortField::Subject, SortOrder::Asc) => {
|
||||||
let a = &self.thread_nodes[*a].message();
|
let a = &self.thread_nodes[a.id].message();
|
||||||
let b = &self.thread_nodes[*b].message();
|
let b = &self.thread_nodes[b.id].message();
|
||||||
|
|
||||||
if a.is_none() || b.is_none() {
|
if a.is_none() || b.is_none() {
|
||||||
return Ordering::Equal;
|
return Ordering::Equal;
|
||||||
|
@ -514,12 +616,13 @@ impl Index<usize> for Threads {
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &ThreadNode {
|
fn index(&self, index: usize) -> &ThreadNode {
|
||||||
self.thread_nodes
|
self.thread_nodes
|
||||||
.get(index)
|
.get(self.tree.borrow()[index].id)
|
||||||
.expect("thread index out of bounds")
|
.expect("thread index out of bounds")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_build(
|
fn node_build(
|
||||||
|
tree: &mut ThreadTree,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
thread_nodes: &mut Vec<ThreadNode>,
|
thread_nodes: &mut Vec<ThreadNode>,
|
||||||
indentation: usize,
|
indentation: usize,
|
||||||
|
@ -557,9 +660,20 @@ fn node_build(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut has_unseen = thread_nodes[idx].has_unseen;
|
let mut has_unseen = thread_nodes[idx].has_unseen;
|
||||||
|
let mut child_vec: Vec<ThreadTree> = Vec::new();
|
||||||
for c in thread_nodes[idx].children.clone().iter() {
|
for c in thread_nodes[idx].children.clone().iter() {
|
||||||
node_build(*c, thread_nodes, indentation, idx, collection);
|
let mut new_tree = ThreadTree::new(*c);
|
||||||
|
node_build(
|
||||||
|
&mut new_tree,
|
||||||
|
*c,
|
||||||
|
thread_nodes,
|
||||||
|
indentation,
|
||||||
|
idx,
|
||||||
|
collection,
|
||||||
|
);
|
||||||
has_unseen |= thread_nodes[*c].has_unseen;
|
has_unseen |= thread_nodes[*c].has_unseen;
|
||||||
|
child_vec.push(new_tree);
|
||||||
}
|
}
|
||||||
|
tree.children = child_vec;
|
||||||
thread_nodes[idx].has_unseen = has_unseen;
|
thread_nodes[idx].has_unseen = has_unseen;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue