Browse Source

Replace StackVec with smallvec::SmallVec

SmallVec has a less buggy and better implementation.
async
Manos Pitsidianakis 2 years ago
parent
commit
a365a846b8
Signed by: epilys GPG Key ID: 73627C2F690DF710
  1. 11
      Cargo.lock
  2. 1
      melib/Cargo.toml
  3. 5
      melib/src/backends/imap.rs
  4. 6
      melib/src/backends/jmap/protocol.rs
  5. 27
      melib/src/backends/notmuch.rs
  6. 5
      melib/src/collection.rs
  7. 2
      melib/src/datetime.rs
  8. 9
      melib/src/email.rs
  9. 18
      melib/src/email/list_management.rs
  10. 2
      melib/src/lib.rs
  11. 253
      melib/src/structs.rs
  12. 11
      melib/src/thread.rs
  13. 2
      src/bin.rs
  14. 9
      testing/src/linebreak.rs
  15. 1
      ui/Cargo.toml
  16. 4
      ui/src/cache.rs
  17. 9
      ui/src/components/mail/listing.rs
  18. 32
      ui/src/components/mail/listing/compact.rs
  19. 18
      ui/src/components/mail/listing/conversations.rs
  20. 18
      ui/src/components/mail/listing/plain.rs
  21. 10
      ui/src/components/mail/listing/thread.rs
  22. 7
      ui/src/components/mail/view.rs
  23. 2
      ui/src/components/mail/view/thread.rs
  24. 11
      ui/src/conf/accounts.rs
  25. 1
      ui/src/lib.rs
  26. 7
      ui/src/sqlite3.rs
  27. 8
      ui/src/state.rs
  28. 20
      ui/src/types.rs

11
Cargo.lock

@ -771,6 +771,7 @@ dependencies = [
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"text_processing 0.4.1",
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1553,8 +1554,11 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.0.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sourcefile"
@ -1860,6 +1864,7 @@ dependencies = [
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"text_processing 0.4.1",
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1889,7 +1894,7 @@ name = "unicode-normalization"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2298,7 +2303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1797d48f38f91643908bb14e35e79928f9f4b3cefb2420a564dde0991b4358dc"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
"checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86"
"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4"
"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"

1
melib/Cargo.toml

@ -27,6 +27,7 @@ text_processing = { path = "../text_processing", version = "*", optional= true }
libc = {version = "0.2.59", features = ["extra_traits",]}
reqwest = { version ="0.10.0-alpha.2", optional=true, features = ["json", "blocking" ]}
serde_json = { version = "1.0", optional = true, features = ["raw_value",] }
smallvec = { version = "1.1.0", features = ["serde", ] }
[features]
default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard"]

5
melib/src/backends/imap.rs

@ -19,6 +19,7 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use smallvec::SmallVec;
#[macro_use]
mod protocol_parser;
pub use protocol_parser::{UntaggedResponse::*, *};
@ -677,7 +678,7 @@ impl ImapType {
&self,
query: String,
folder_hash: FolderHash,
) -> Result<crate::structs::StackVec<EnvelopeHash>> {
) -> Result<SmallVec<[EnvelopeHash; 512]>> {
let folders_lck = self.folders.read()?;
let mut response = String::with_capacity(8 * 1024);
let mut conn = self.connection.lock()?;
@ -692,7 +693,7 @@ impl ImapType {
if l.starts_with("* SEARCH") {
use std::iter::FromIterator;
let uid_index = self.uid_store.uid_index.lock()?;
return Ok(crate::structs::StackVec::from_iter(
return Ok(SmallVec::from_iter(
l["* SEARCH".len()..]
.trim()
.split_whitespace()

6
melib/src/backends/jmap/protocol.rs

@ -21,9 +21,9 @@
use super::folder::JmapFolder;
use super::*;
use crate::structs::StackVec;
use serde::Serialize;
use serde_json::{json, Value};
use smallvec::SmallVec;
use std::collections::hash_map::DefaultHasher;
use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
@ -327,10 +327,10 @@ pub fn get(
}
tag_hash
})
.collect::<StackVec<u64>>();
.collect::<SmallVec<[u64; 1024]>>();
(tags, obj.id.clone(), obj.blob_id.clone())
})
.collect::<Vec<(StackVec<u64>, Id, Id)>>();
.collect::<Vec<(SmallVec<[u64; 1024]>, Id, Id)>>();
drop(tag_lck);
let mut ret = list
.into_iter()

27
melib/src/backends/notmuch.rs

@ -1,3 +1,24 @@
/*
* meli - notmuch backend
*
* Copyright 2019 - 2020 Manos Pitsidianakis
*
* This file is part of meli.
*
* meli is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* meli is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::FolderHash;
use crate::backends::{
@ -8,8 +29,8 @@ use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result};
use crate::shellexpand::ShellExpandTrait;
use crate::structs::StackVec;
use fnv::FnvHashMap;
use smallvec::SmallVec;
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::ffi::{CStr, CString};
@ -229,7 +250,7 @@ impl NotmuchDb {
Ok(())
}
pub fn search(&self, query_s: &str) -> Result<crate::structs::StackVec<EnvelopeHash>> {
pub fn search(&self, query_s: &str) -> Result<SmallVec<[EnvelopeHash; 512]>> {
let database_lck = self.database.inner.read().unwrap();
let query_str = std::ffi::CString::new(query_s).unwrap();
let query: *mut notmuch_query_t =
@ -247,7 +268,7 @@ impl NotmuchDb {
}
assert!(!messages.is_null());
let iter = MessageIterator { messages };
let mut ret = StackVec::new();
let mut ret = SmallVec::new();
for message in iter {
let fs_path = unsafe { notmuch_message_get_filename(message) };
let c_str = unsafe { CStr::from_ptr(fs_path) };

5
melib/src/collection.rs

@ -1,5 +1,6 @@
use super::*;
use crate::backends::FolderHash;
use smallvec::SmallVec;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
@ -160,7 +161,7 @@ impl Collection {
mut new_envelopes: FnvHashMap<EnvelopeHash, Envelope>,
folder_hash: FolderHash,
sent_folder: Option<FolderHash>,
) -> Option<StackVec<FolderHash>> {
) -> Option<SmallVec<[FolderHash; 8]>> {
self.sent_folder = sent_folder;
for (h, e) in new_envelopes.iter() {
self.message_ids.insert(e.message_id().raw().to_vec(), *h);
@ -198,7 +199,7 @@ impl Collection {
});
}
let mut ret = StackVec::new();
let mut ret = SmallVec::new();
let keys = threads.keys().cloned().collect::<Vec<FolderHash>>();
for t_fh in keys {
if t_fh == folder_hash {

2
melib/src/datetime.rs

@ -61,7 +61,7 @@ pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>) -> Strin
};
let s: CString;
unsafe {
let mut vec: Vec<u8> = vec![0; 256];
let mut vec: [u8; 256] = [0; 256];
let ret = strftime(
vec.as_mut_ptr() as *mut _,
256,

9
melib/src/email.rs

@ -43,6 +43,7 @@ use crate::datetime::UnixTimestamp;
use crate::error::{MeliError, Result};
use crate::thread::ThreadHash;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
@ -132,7 +133,7 @@ pub struct Envelope {
flags: Flag,
has_attachments: bool,
labels: crate::structs::StackVec<u64>,
labels: SmallVec<[u64; 8]>,
}
impl fmt::Debug for Envelope {
@ -170,7 +171,7 @@ impl Envelope {
hash,
has_attachments: false,
flags: Flag::default(),
labels: crate::structs::StackVec::new(),
labels: SmallVec::new(),
}
}
@ -609,11 +610,11 @@ impl Envelope {
self.has_attachments
}
pub fn labels(&self) -> &crate::structs::StackVec<u64> {
pub fn labels(&self) -> &SmallVec<[u64; 8]> {
&self.labels
}
pub fn labels_mut(&mut self) -> &mut crate::structs::StackVec<u64> {
pub fn labels_mut(&mut self) -> &mut SmallVec<[u64; 8]> {
&mut self.labels
}
}

18
melib/src/email/list_management.rs

@ -18,9 +18,10 @@
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use super::parser;
use super::Envelope;
use crate::StackVec;
use smallvec::SmallVec;
use std::convert::From;
#[derive(Debug, Copy)]
@ -46,7 +47,7 @@ impl<'a> From<&'a [u8]> for ListAction<'a> {
}
impl<'a> ListAction<'a> {
pub fn parse_options_list(input: &'a [u8]) -> Option<StackVec<ListAction<'a>>> {
pub fn parse_options_list(input: &'a [u8]) -> Option<SmallVec<[ListAction<'a>; 4]>> {
parser::angle_bracket_delimeted_list(input)
.map(|mut vec| {
/* Prefer email options first, since this _is_ a mail client after all and it's
@ -61,20 +62,13 @@ impl<'a> ListAction<'a> {
vec.into_iter()
.map(|elem| ListAction::from(elem))
.collect::<StackVec<ListAction<'a>>>()
.collect::<SmallVec<[ListAction<'a>; 4]>>()
})
.to_full_result()
.ok()
}
}
/* Required for StackVec's place holder elements, never actually used */
impl<'a> Default for ListAction<'a> {
fn default() -> Self {
ListAction::Email(b"")
}
}
impl<'a> Clone for ListAction<'a> {
fn clone(&self) -> Self {
match self {
@ -88,8 +82,8 @@ impl<'a> Clone for ListAction<'a> {
pub struct ListActions<'a> {
pub id: Option<&'a str>,
pub archive: Option<&'a str>,
pub post: Option<StackVec<ListAction<'a>>>,
pub unsubscribe: Option<StackVec<ListAction<'a>>>,
pub post: Option<SmallVec<[ListAction<'a>; 4]>>,
pub unsubscribe: Option<SmallVec<[ListAction<'a>; 4]>>,
}
pub fn list_id_header<'a>(envelope: &'a Envelope) -> Option<&'a str> {

2
melib/src/lib.rs

@ -123,8 +123,6 @@ pub mod mailbox;
pub mod thread;
pub use crate::email::*;
pub use crate::thread::*;
mod structs;
pub use self::structs::*;
pub mod parsec;
#[macro_use]

253
melib/src/structs.rs

@ -1,253 +0,0 @@
/*
* meli - melib crate.
*
* Copyright 2019 Manos Pitsidianakis
*
* This file is part of meli.
*
* meli is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* meli is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use std::iter::{Extend, FromIterator};
use std::ops::Index;
use std::ops::IndexMut;
const STACK_VEC_CAPACITY: usize = 32;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct StackVec<T: Default + Copy + std::fmt::Debug> {
len: usize,
array: [T; STACK_VEC_CAPACITY],
heap_vec: Vec<T>,
}
impl<T: Default + Copy + std::fmt::Debug> StackVec<T> {
pub fn new() -> Self {
StackVec {
len: 0,
array: [T::default(); STACK_VEC_CAPACITY],
heap_vec: Vec::new(),
}
}
pub fn push(&mut self, ind: T) {
if self.len == self.array.len() {
if self.heap_vec.is_empty() {
self.heap_vec.reserve(STACK_VEC_CAPACITY);
for _ in 0..STACK_VEC_CAPACITY {
self.heap_vec.push(T::default());
}
}
self.heap_vec[0..STACK_VEC_CAPACITY].copy_from_slice(&self.array);
self.heap_vec.push(ind);
} else if self.len > self.array.len() {
self.heap_vec.push(ind);
} else {
self.array[self.len] = ind;
}
self.len += 1;
}
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
if self.len > self.array.len() {
self.len -= 1;
self.heap_vec.pop()
} else {
let ret = self.array[self.len - 1];
self.len -= 1;
Some(ret)
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn iter(&self) -> StackVecIter<T> {
StackVecIter {
stack: &self,
range: 0..self.len,
}
}
pub fn remove(&mut self, i: usize) -> T {
if self.len > self.array.len() {
self.len -= 1;
self.heap_vec.remove(i)
} else {
let ret = std::mem::replace(&mut self.array[i], T::default());
self.len -= 1;
for i in i..self.len {
self.array[i] = self.array[i + 1];
}
ret
}
}
pub fn set(&mut self, i: usize, val: T) {
debug_assert!(i < self.len);
if self.len > self.array.len() {
self.heap_vec[i] = val;
if i < self.array.len() {
self.array[i] = val;
}
} else {
self.array[i] = val;
}
}
pub fn clear(&mut self) {
self.len = 0;
}
}
pub struct StackVecIter<'a, T: Default + Copy + std::fmt::Debug> {
stack: &'a StackVec<T>,
range: std::ops::Range<usize>,
}
impl<'a, T: Default + Copy + std::fmt::Debug> Iterator for StackVecIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
if self.range.len() == 0 {
None
} else {
let idx = self.range.start;
self.range.start += 1;
Some(&self.stack[idx])
}
}
}
impl<'a, T: Default + Copy + std::fmt::Debug> std::iter::DoubleEndedIterator
for StackVecIter<'a, T>
{
fn next_back(&mut self) -> Option<&'a T> {
if self.range.len() == 0 {
None
} else {
let idx = self.range.end - 1;
self.range.end -= 1;
Some(&self.stack[idx])
}
}
}
impl<T: Default + Copy + std::fmt::Debug> Index<usize> for StackVec<T> {
type Output = T;
fn index(&self, idx: usize) -> &T {
if self.len > self.array.len() {
&self.heap_vec[idx]
} else {
&self.array[idx]
}
}
}
impl<T: Default + Copy + std::fmt::Debug> IndexMut<usize> for StackVec<T> {
fn index_mut(&mut self, idx: usize) -> &mut T {
if self.len > self.array.len() {
&mut self.heap_vec[idx]
} else {
&mut self.array[idx]
}
}
}
impl<T: Default + Copy + std::fmt::Debug> Extend<T> for StackVec<T> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
for elem in iter {
self.push(elem);
}
}
}
impl<T: Default + Copy + std::fmt::Debug> FromIterator<T> for StackVec<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut c = StackVec::new();
for i in iter {
c.push(i);
}
c
}
}
pub struct StackVecIterOwned<T: Default + Copy + std::fmt::Debug>(StackVec<T>);
impl<T: Default + Copy + std::fmt::Debug> IntoIterator for StackVec<T> {
type Item = T;
type IntoIter = StackVecIterOwned<T>;
fn into_iter(self) -> Self::IntoIter {
StackVecIterOwned(self)
}
}
impl<'a, T: Default + Copy + std::fmt::Debug> IntoIterator for &'a StackVec<T> {
type Item = &'a T;
type IntoIter = StackVecIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T: Default + Copy + std::fmt::Debug> Iterator for StackVecIterOwned<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.0.is_empty() {
None
} else {
Some(self.0.remove(0))
}
}
}
impl<T: Default + Copy + std::fmt::Debug> std::iter::DoubleEndedIterator for StackVecIterOwned<T> {
fn next_back(&mut self) -> Option<T> {
if self.0.is_empty() {
None
} else {
self.0.pop()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stackvec() {
let mut stack = StackVec::from_iter(0..4 * STACK_VEC_CAPACITY);
let mut ctr = 0;
assert!(stack.iter().all(|&x| {
let ret = x == ctr;
ctr += 1;
ret
}));
for _ in 0..(3 * STACK_VEC_CAPACITY) + 1 {
stack.pop();
}
ctr = 0;
assert!(stack.iter().all(|&x| {
let ret = x == ctr;
ctr += 1;
ret
}));
}
}

11
melib/src/thread.rs

@ -35,7 +35,6 @@
use crate::datetime::UnixTimestamp;
use crate::email::parser::BytesExt;
use crate::email::*;
use crate::structs::StackVec;
#[cfg(feature = "unicode_algorithms")]
use text_processing::grapheme_clusters::*;
@ -53,6 +52,8 @@ use std::str::FromStr;
use std::string::ToString;
use std::sync::{Arc, RwLock};
use smallvec::SmallVec;
type Envelopes = Arc<RwLock<FnvHashMap<EnvelopeHash, Envelope>>>;
#[derive(PartialEq, Hash, Eq, Copy, Clone, Serialize, Deserialize, Default)]
@ -279,7 +280,7 @@ impl FromStr for SortOrder {
pub struct ThreadsIterator<'a> {
pos: usize,
stack: StackVec<usize>,
stack: SmallVec<[usize; 16]>,
root_tree: Ref<'a, Vec<ThreadHash>>,
thread_nodes: &'a FnvHashMap<ThreadHash, ThreadNode>,
}
@ -332,7 +333,7 @@ impl<'a> Iterator for ThreadsIterator<'a> {
pub struct ThreadIterator<'a> {
init_pos: usize,
pos: usize,
stack: StackVec<usize>,
stack: SmallVec<[usize; 16]>,
root_tree: Ref<'a, Vec<ThreadHash>>,
thread_nodes: &'a FnvHashMap<ThreadHash, ThreadNode>,
}
@ -724,7 +725,7 @@ impl Threads {
pub fn threads_iter(&self) -> ThreadsIterator {
ThreadsIterator {
pos: 0,
stack: StackVec::new(),
stack: SmallVec::new(),
root_tree: self.tree_index.borrow(),
thread_nodes: &self.thread_nodes,
}
@ -734,7 +735,7 @@ impl Threads {
ThreadIterator {
init_pos: index,
pos: index,
stack: StackVec::new(),
stack: SmallVec::new(),
root_tree: self.tree_index.borrow(),
thread_nodes: &self.thread_nodes,
}

2
src/bin.rs

@ -256,7 +256,7 @@ fn run_app() -> Result<()> {
'inner: loop {
/* Check if any components have sent reply events to State. */
let events: Vec<UIEvent> = state.context.replies();
let events: ui::smallvec::SmallVec<[UIEvent; 8]> = state.context.replies();
for e in events {
state.rcv_event(e);
}

9
testing/src/linebreak.rs

@ -1,6 +1,5 @@
extern crate melib;
use melib::Result;
use melib::StackVec;
extern crate text_processing;
use text_processing::line_break::*;
@ -14,14 +13,14 @@ fn cost(i: usize, j: usize, width: usize, minima: &Vec<usize>, offsets: &Vec<usi
}
fn smawk(
rows: &mut StackVec<usize>,
columns: &mut StackVec<usize>,
rows: &mut Vec<usize>,
columns: &mut Vec<usize>,
minima: &mut Vec<usize>,
breaks: &mut Vec<usize>,
width: usize,
offsets: &Vec<usize>,
) {
let mut stack = StackVec::new();
let mut stack = Vec::new();
let mut i = 0;
while i < rows.len() {
if stack.len() > 0 {
@ -46,7 +45,7 @@ fn smawk(
let mut odd_columns = columns.iter().skip(1).step_by(2).cloned().collect();
smawk(rows, &mut odd_columns, minima, breaks, width, offsets);
for (i, o) in odd_columns.into_iter().enumerate() {
columns.set(2 * i + 1, o);
columns[2 * i + 1] = o;
}
}
let mut i = 0;

1
ui/Cargo.toml

@ -30,6 +30,7 @@ rusqlite = {version = "0.20.0", optional =true }
rmp = "^0.8"
rmpv = { version = "^0.4.2", features=["with-serde",] }
rmp-serde = "^0.14.0"
smallvec = { version = "1.1.0", features = ["serde", ] }
[features]
default = ["sqlite3"]

4
ui/src/cache.rs

@ -25,7 +25,7 @@ use melib::{
backends::{FolderHash, MailBackend},
email::EnvelopeHash,
thread::{SortField, SortOrder},
Result, StackVec,
Result,
};
use std::sync::{Arc, RwLock};
@ -429,7 +429,7 @@ pub fn imap_search(
(_sort_field, _sort_order): (SortField, SortOrder),
folder_hash: FolderHash,
backend: &Arc<RwLock<Box<dyn MailBackend>>>,
) -> Result<StackVec<EnvelopeHash>> {
) -> Result<smallvec::SmallVec<[EnvelopeHash; 512]>> {
let query = query().parse(term)?.1;
let backend_lck = backend.read().unwrap();

9
ui/src/components/mail/listing.rs

@ -21,6 +21,7 @@
use super::*;
use crate::types::segment_tree::SegmentTree;
use smallvec::SmallVec;
mod conversations;
pub use self::conversations::*;
@ -56,10 +57,10 @@ pub trait MailListingTrait: ListingTrait {
a: &ListingAction,
) {
let account = &mut context.accounts[self.coordinates().0];
let mut envs_to_set: StackVec<EnvelopeHash> = StackVec::new();
let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new();
let folder_hash = account[self.coordinates().1].unwrap().folder.hash();
{
let mut stack = StackVec::new();
let mut stack: SmallVec<[ThreadHash; 8]> = SmallVec::new();
stack.push(thread_hash);
while let Some(thread_iter) = stack.pop() {
{
@ -138,8 +139,8 @@ pub trait MailListingTrait: ListingTrait {
}
}
fn row_updates(&mut self) -> &mut StackVec<ThreadHash>;
fn get_focused_items(&self, _context: &Context) -> StackVec<ThreadHash>;
fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]>;
fn get_focused_items(&self, _context: &Context) -> SmallVec<[ThreadHash; 8]>;
}
pub trait ListingTrait: Component {

32
ui/src/components/mail/listing/compact.rs

@ -69,18 +69,18 @@ pub struct CompactListing {
/// If `self.view` exists or not.
unfocused: bool,
view: ThreadView,
row_updates: StackVec<ThreadHash>,
row_updates: SmallVec<[ThreadHash; 8]>,
movement: Option<PageMovement>,
id: ComponentId,
}
impl MailListingTrait for CompactListing {
fn row_updates(&mut self) -> &mut StackVec<ThreadHash> {
fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]> {
&mut self.row_updates
}
fn get_focused_items(&self, context: &Context) -> StackVec<ThreadHash> {
fn get_focused_items(&self, context: &Context) -> SmallVec<[ThreadHash; 8]> {
let is_selection_empty = self.selection.values().cloned().any(std::convert::identity);
let i = [self.get_thread_under_cursor(self.cursor_pos.2, context)];
let cursor_iter;
@ -96,7 +96,7 @@ impl MailListingTrait for CompactListing {
.flatten()
.chain(cursor_iter.into_iter().flatten())
.cloned();
StackVec::from_iter(iter.into_iter())
SmallVec::from_iter(iter.into_iter())
}
}
@ -530,7 +530,7 @@ impl CompactListing {
filtered_selection: Vec::new(),
filtered_order: FnvHashMap::default(),
selection: FnvHashMap::default(),
row_updates: StackVec::new(),
row_updates: SmallVec::new(),
data_columns: DataColumns::default(),
dirty: true,
force_draw: true,
@ -554,7 +554,7 @@ impl CompactListing {
.hash();
let folder = &context.accounts[self.cursor_pos.0].folder_confs[&folder_hash];
let mut tags = String::new();
let mut colors = StackVec::new();
let mut colors: SmallVec<[_; 8]> = SmallVec::new();
let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap();
if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap();
@ -681,17 +681,17 @@ impl CompactListing {
let mut rows = Vec::with_capacity(1024);
let mut min_width = (0, 0, 0, 0, 0);
let mut row_widths: (
StackVec<u8>,
StackVec<u8>,
StackVec<u8>,
StackVec<u8>,
StackVec<u8>,
SmallVec<[u8; 1024]>,
SmallVec<[u8; 1024]>,
SmallVec<[u8; 1024]>,
SmallVec<[u8; 1024]>,
SmallVec<[u8; 1024]>,
) = (
StackVec::new(),
StackVec::new(),
StackVec::new(),
StackVec::new(),
StackVec::new(),
SmallVec::new(),
SmallVec::new(),
SmallVec::new(),
SmallVec::new(),
SmallVec::new(),
);
threads.sort_by(self.sort, self.subsort, &account.collection.envelopes);

18
ui/src/components/mail/listing/conversations.rs

@ -73,7 +73,7 @@ column_str!(struct DateString(String));
column_str!(struct FromString(String));
column_str!(struct SubjectString(String));
column_str!(struct FlagString(String));
column_str!(struct TagString(String, StackVec<Color>));
column_str!(struct TagString(String, SmallVec<[Color; 8]>));
/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a
/// `ThreadView`.
@ -100,18 +100,18 @@ pub struct ConversationsListing {
/// If `self.view` exists or not.
unfocused: bool,
view: ThreadView,
row_updates: StackVec<ThreadHash>,
row_updates: SmallVec<[ThreadHash; 8]>,
movement: Option<PageMovement>,
id: ComponentId,
}
impl MailListingTrait for ConversationsListing {
fn row_updates(&mut self) -> &mut StackVec<ThreadHash> {
fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]> {
&mut self.row_updates
}
fn get_focused_items(&self, context: &Context) -> StackVec<ThreadHash> {
fn get_focused_items(&self, context: &Context) -> SmallVec<[ThreadHash; 8]> {
let is_selection_empty = self.selection.values().cloned().any(std::convert::identity);
let i = [self.get_thread_under_cursor(self.cursor_pos.2, context)];
let cursor_iter;
@ -127,7 +127,7 @@ impl MailListingTrait for ConversationsListing {
.flatten()
.chain(cursor_iter.into_iter().flatten())
.cloned();
StackVec::from_iter(iter.into_iter())
SmallVec::from_iter(iter.into_iter())
}
}
@ -500,7 +500,7 @@ impl ConversationsListing {
filtered_selection: Vec::new(),
filtered_order: FnvHashMap::default(),
selection: FnvHashMap::default(),
row_updates: StackVec::new(),
row_updates: SmallVec::new(),
content: Default::default(),
dirty: true,
force_draw: true,
@ -525,7 +525,7 @@ impl ConversationsListing {
.hash();
let folder = &context.accounts[self.cursor_pos.0].folder_confs[&folder_hash];
let mut tags = String::new();
let mut colors = StackVec::new();
let mut colors = SmallVec::new();
let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap();
if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap();
@ -690,7 +690,7 @@ impl ConversationsListing {
}
from_address_list.clear();
from_address_set.clear();
let mut stack = StackVec::new();
let mut stack: SmallVec<[ThreadHash; 8]> = SmallVec::new();
stack.push(root_idx);
while let Some(h) = stack.pop() {
let env_hash = if let Some(h) = threads.thread_nodes()[&h].message() {
@ -952,7 +952,7 @@ impl ConversationsListing {
let mut from_address_list = Vec::new();
let mut from_address_set: std::collections::HashSet<Vec<u8>> =
std::collections::HashSet::new();
let mut stack = StackVec::new();
let mut stack: SmallVec<[ThreadHash; 8]> = SmallVec::new();
stack.push(thread_hash);
while let Some(h) = stack.pop() {
let env_hash = if let Some(h) = threads.thread_nodes()[&h].message() {

18
ui/src/components/mail/listing/plain.rs

@ -70,19 +70,19 @@ pub struct PlainListing {
/// If `self.view` exists or not.
unfocused: bool,
view: MailView,
row_updates: StackVec<EnvelopeHash>,
_row_updates: StackVec<ThreadHash>,
row_updates: SmallVec<[EnvelopeHash; 8]>,
_row_updates: SmallVec<[ThreadHash; 8]>,
movement: Option<PageMovement>,
id: ComponentId,
}
impl MailListingTrait for PlainListing {
fn row_updates(&mut self) -> &mut StackVec<ThreadHash> {
fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]> {
&mut self._row_updates
}
fn get_focused_items(&self, context: &Context) -> StackVec<ThreadHash> {
fn get_focused_items(&self, context: &Context) -> SmallVec<[ThreadHash; 8]> {
let is_selection_empty = self.selection.values().cloned().any(std::convert::identity);
if is_selection_empty {
self.selection
@ -91,7 +91,7 @@ impl MailListingTrait for PlainListing {
.map(|(k, _)| self.thread_hashes[k])
.collect()
} else {
let mut ret = StackVec::new();
let mut ret = SmallVec::new();
ret.push(self.get_thread_under_cursor(self.cursor_pos.2, context));
ret
}
@ -484,8 +484,8 @@ impl PlainListing {
filtered_selection: Vec::new(),
filtered_order: FnvHashMap::default(),
selection: FnvHashMap::default(),
row_updates: StackVec::new(),
_row_updates: StackVec::new(),
row_updates: SmallVec::new(),
_row_updates: SmallVec::new(),
data_columns: DataColumns::default(),
dirty: true,
force_draw: true,
@ -503,7 +503,7 @@ impl PlainListing {
.hash();
let folder = &context.accounts[self.cursor_pos.0].folder_confs[&folder_hash];
let mut tags = String::new();
let mut colors = StackVec::new();
let mut colors = SmallVec::new();
let backend_lck = context.accounts[self.cursor_pos.0].backend.read().unwrap();
if let Some(t) = backend_lck.tags() {
let tags_lck = t.read().unwrap();
@ -1086,7 +1086,7 @@ impl Component for PlainListing {
.flatten()
.chain(cursor_iter.into_iter().flatten())
.cloned();
let stack = StackVec::from_iter(iter.into_iter());
let stack: SmallVec<[_; 8]> = SmallVec::from_iter(iter.into_iter());
for i in stack {
self.perform_action(context, i, a);
}

10
ui/src/components/mail/listing/thread.rs

@ -37,7 +37,7 @@ pub struct ThreadListing {
/// Cache current view.
content: CellBuffer,
row_updates: StackVec<ThreadHash>,
row_updates: SmallVec<[ThreadHash; 8]>,
locations: Vec<EnvelopeHash>,
/// If we must redraw on next redraw event
dirty: bool,
@ -50,12 +50,12 @@ pub struct ThreadListing {
}
impl MailListingTrait for ThreadListing {
fn row_updates(&mut self) -> &mut StackVec<ThreadHash> {
fn row_updates(&mut self) -> &mut SmallVec<[ThreadHash; 8]> {
&mut self.row_updates
}
fn get_focused_items(&self, _context: &Context) -> StackVec<ThreadHash> {
StackVec::new()
fn get_focused_items(&self, _context: &Context) -> SmallVec<[ThreadHash; 8]> {
SmallVec::new()
}
}
@ -242,7 +242,7 @@ impl ThreadListing {
sort: (Default::default(), Default::default()),
subsort: (Default::default(), Default::default()),
content,
row_updates: StackVec::new(),
row_updates: SmallVec::new(),
locations: Vec::new(),
dirty: true,
unfocused: false,

7
ui/src/components/mail/view.rs

@ -22,6 +22,7 @@
use super::*;
use melib::list_management;
use melib::parser::BytesExt;
use smallvec::SmallVec;
use std::convert::TryFrom;
use std::process::{Command, Stdio};
@ -229,7 +230,7 @@ impl MailView {
if body.count_attachments() > 1 {
fn attachment_tree(
(idx, (depth, att)): (&mut usize, (usize, &Attachment)),
branches: &mut StackVec<bool>,
branches: &mut SmallVec<[bool; 8]>,
has_sibling: bool,
s: &mut String,
) {
@ -286,7 +287,7 @@ impl MailView {
_ => {}
}
}
attachment_tree((&mut 0, (0, &body)), &mut StackVec::new(), false, &mut t);
attachment_tree((&mut 0, (0, &body)), &mut SmallVec::new(), false, &mut t);
}
t
}
@ -1385,7 +1386,7 @@ impl Component for MailView {
}
_ => { /* error print message to user */ }
}
}
};
}
UIEvent::Action(Listing(OpenInNewTab)) => {
context

2
ui/src/components/mail/view/thread.rs

@ -848,7 +848,7 @@ impl ThreadView {
.iter()
.enumerate()
.fold(
(vec![Vec::new()], StackVec::new(), false),
(vec![Vec::new()], SmallVec::<[_; 8]>::new(), false),
|(mut visies, mut stack, is_prev_hidden), (idx, e)| {
match (e.hidden, is_prev_hidden) {
(true, false) => {

11
ui/src/conf/accounts.rs

@ -34,7 +34,7 @@ use melib::error::{MeliError, Result};
use melib::mailbox::*;
use melib::thread::{SortField, SortOrder, ThreadHash, ThreadNode, Threads};
use melib::AddressBook;
use melib::StackVec;
use smallvec::SmallVec;
use text_processing::GlobMatch;
use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification};
@ -384,7 +384,7 @@ impl Account {
folder_names.insert(f.hash(), f.path().to_string());
}
let mut stack: StackVec<FolderHash> = StackVec::new();
let mut stack: SmallVec<[FolderHash; 8]> = SmallVec::new();
let mut tree: Vec<FolderNode> = Vec::new();
let mut collection: Collection = Collection::new(Default::default());
for (h, f) in ref_folders.iter() {
@ -442,7 +442,7 @@ impl Account {
}
});
let mut stack: StackVec<Option<&FolderNode>> = StackVec::new();
let mut stack: SmallVec<[Option<&FolderNode>; 8]> = SmallVec::new();
for n in tree.iter_mut() {
folders_order.push(n.hash);
n.kids.sort_unstable_by(|a, b| {
@ -462,6 +462,7 @@ impl Account {
stack.extend(next.kids.iter().rev().map(Some));
}
}
drop(stack);
self.folders = folders;
self.ref_folders = ref_folders;
@ -1053,7 +1054,7 @@ impl Account {
search_term: &str,
sort: (SortField, SortOrder),
folder_hash: FolderHash,
) -> Result<StackVec<EnvelopeHash>> {
) -> Result<SmallVec<[EnvelopeHash; 512]>> {
if self.settings.account().format() == "imap" {
return crate::cache::imap_search(search_term, sort, folder_hash, &self.backend);
}
@ -1081,7 +1082,7 @@ impl Account {
#[cfg(not(feature = "sqlite3"))]
{
let mut ret = StackVec::new();
let mut ret = SmallVec::new();
let envelopes = self.collection.envelopes.clone().read();
let envelopes = envelopes.unwrap();

1
ui/src/lib.rs

@ -40,6 +40,7 @@ extern crate termion;
extern crate nom;
extern crate serde_json;
pub extern crate smallvec;
use melib::*;
use std::collections::VecDeque;

7
ui/src/sqlite3.rs

@ -19,6 +19,7 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use smallvec::SmallVec;
use crate::cache::query;
use crate::cache::Query::{self, *};
use crate::melib::parsec::Parser;
@ -27,7 +28,7 @@ use melib::{
email::{Envelope, EnvelopeHash},
log,
thread::{SortField, SortOrder},
MeliError, Result, StackVec, ERROR,
MeliError, Result, ERROR,
};
use rusqlite::{params, Connection};
use std::borrow::Cow;
@ -389,7 +390,7 @@ pub fn index(context: &mut crate::state::Context, account_name: &str) -> Result<
pub fn search(
term: &str,
(sort_field, sort_order): (SortField, SortOrder),
) -> Result<StackVec<EnvelopeHash>> {
) -> Result<SmallVec<[EnvelopeHash; 512]>> {
let conn = open_db()?;
let sort_field = match debug!(sort_field) {
@ -425,7 +426,7 @@ pub fn search(
.map_err(|e: std::array::TryFromSliceError| MeliError::new(e.to_string()))?,
))
})
.collect::<Result<StackVec<EnvelopeHash>>>();
.collect::<Result<SmallVec<[EnvelopeHash; 512]>>>();
results
}

8
ui/src/state.rs

@ -103,7 +103,7 @@ pub struct Context {
}
impl Context {
pub fn replies(&mut self) -> Vec<UIEvent> {
pub fn replies(&mut self) -> smallvec::SmallVec<[UIEvent; 8]> {
self.replies.drain(0..).collect()
}
@ -437,7 +437,8 @@ impl State {
for i in 0..self.components.len() {
self.draw_component(i);
}
let