Convert {Account,Mailbox}Hash from typedef to wrapper struct

pull/170/head
Manos Pitsidianakis 2022-12-08 21:34:32 +02:00
parent 7382e30160
commit 259aeb0087
33 changed files with 245 additions and 298 deletions

View File

@ -20,16 +20,6 @@
*/
use smallvec::SmallVec;
#[macro_export]
macro_rules! tag_hash {
($tag:ident) => {{
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
hasher.write($tag.as_bytes());
hasher.finish()
}};
}
#[cfg(feature = "imap_backend")]
pub mod imap;
@ -580,8 +570,10 @@ pub trait BackendMailbox: Debug {
fn count(&self) -> Result<(usize, usize)>;
}
pub type AccountHash = u64;
pub type MailboxHash = u64;
crate::declare_u64_hash!(AccountHash);
crate::declare_u64_hash!(MailboxHash);
crate::declare_u64_hash!(TagHash);
pub type Mailbox = Box<dyn BackendMailbox + Send + Sync>;
impl Clone for Mailbox {
@ -742,10 +734,10 @@ fn test_lazy_count_set() {
new.set_not_yet_seen(10);
assert_eq!(new.len(), 10);
for i in 0..10 {
assert!(new.insert_existing(i));
assert!(new.insert_existing(EnvelopeHash(i)));
}
assert_eq!(new.len(), 10);
assert!(!new.insert_existing(10));
assert!(!new.insert_existing(EnvelopeHash(10)));
assert_eq!(new.len(), 10);
}

View File

@ -19,7 +19,6 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::get_path_hash;
use smallvec::SmallVec;
#[macro_use]
mod protocol_parser;
@ -516,7 +515,7 @@ impl MailBackend for ImapType {
let account_hash = uid_store.account_hash;
main_conn_lck.add_refresh_event(RefreshEvent {
account_hash,
mailbox_hash: 0,
mailbox_hash: MailboxHash::default(),
kind: RefreshEventKind::Failure(err.clone()),
});
return Err(err);
@ -754,7 +753,7 @@ impl MailBackend for ImapType {
return Err(MeliError::new(format!("Application error: more than one flag bit set in set_flags: {:?}", flags)).set_kind(crate::ErrorKind::Bug));
}
Err(tag) => {
let hash = tag_hash!(tag);
let hash = TagHash::from_bytes(tag.as_bytes());
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, tag.to_string());
}
@ -949,7 +948,7 @@ impl MailBackend for ImapType {
}
let ret: Result<()> = ImapResponse::try_from(response.as_slice())?.into();
ret?;
let new_hash = get_path_hash!(path.as_str());
let new_hash = MailboxHash::from_bytes(path.as_str().as_bytes());
uid_store.mailboxes.lock().await.clear();
Ok((new_hash, new_mailbox_fut?.await.map_err(|err| MeliError::new(format!("Mailbox create was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", String::from_utf8_lossy(&response), err)))?))
}))
@ -1086,7 +1085,7 @@ impl MailBackend for ImapType {
.read_response(&mut response, RequiredResponses::empty())
.await?;
}
let new_hash = get_path_hash!(new_path.as_str());
let new_hash = MailboxHash::from_bytes(new_path.as_str().as_bytes());
let ret: Result<()> = ImapResponse::try_from(response.as_slice())?.into();
ret?;
uid_store.mailboxes.lock().await.clear();
@ -1330,11 +1329,7 @@ impl ImapType {
},
timeout,
};
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(s.name.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(s.name.as_bytes());
let account_name = Arc::new(s.name().to_string());
let uid_store: Arc<UIDStore> = Arc::new(UIDStore {
keep_offline_cache,
@ -1486,7 +1481,7 @@ impl ImapType {
debug!("parse error for {:?}", l);
}
}
mailboxes.retain(|_, v| v.hash != 0);
mailboxes.retain(|_, v| !v.hash.is_null());
conn.send_command(b"LSUB \"\" \"*\"").await?;
conn.read_response(&mut res, RequiredResponses::LSUB_REQUIRED)
.await?;
@ -1824,11 +1819,11 @@ async fn fetch_hlpr(state: &mut FetchState) -> Result<Vec<Envelope>> {
our_unseen.insert(env.hash());
}
for f in keywords {
let hash = tag_hash!(f);
let hash = TagHash::from_bytes(f.as_bytes());
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, f.to_string());
}
env.labels_mut().push(hash);
env.tags_mut().push(hash);
}
}
}

View File

@ -183,7 +183,7 @@ mod sqlite3_m {
.prepare("SELECT MAX(uid) FROM envelopes WHERE mailbox_hash = ?1;")?;
let mut ret: Vec<UID> = stmt
.query_map(sqlite3::params![mailbox_hash as i64], |row| {
.query_map(sqlite3::params![mailbox_hash], |row| {
row.get(0).map(|i: Sqlite3UID| i as UID)
})?
.collect::<std::result::Result<_, _>>()?;
@ -211,7 +211,7 @@ mod sqlite3_m {
"SELECT uidvalidity, flags, highestmodseq FROM mailbox WHERE mailbox_hash = ?1;",
)?;
let mut ret = stmt.query_map(sqlite3::params![mailbox_hash as i64], |row| {
let mut ret = stmt.query_map(sqlite3::params![mailbox_hash], |row| {
Ok((
row.get(0).map(|u: Sqlite3UID| u as UID)?,
row.get(1)?,
@ -253,7 +253,7 @@ mod sqlite3_m {
.or_insert(uidvalidity);
let mut tag_lck = self.uid_store.collection.tag_index.write().unwrap();
for f in to_str!(&flags).split('\0') {
let hash = tag_hash!(f);
let hash = TagHash::from_bytes(f.as_bytes());
//debug!("hash {} flag {}", hash, &f);
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, f.to_string());
@ -277,7 +277,7 @@ mod sqlite3_m {
self.connection
.execute(
"DELETE FROM mailbox WHERE mailbox_hash = ?1",
sqlite3::params![mailbox_hash as i64],
sqlite3::params![mailbox_hash],
)
.chain_err_summary(|| {
format!(
@ -289,7 +289,7 @@ mod sqlite3_m {
if let Some(Ok(highestmodseq)) = select_response.highestmodseq {
self.connection.execute(
"INSERT OR IGNORE INTO mailbox (uidvalidity, flags, highestmodseq, mailbox_hash) VALUES (?1, ?2, ?3, ?4)",
sqlite3::params![select_response.uidvalidity as Sqlite3UID, select_response.flags.1.iter().map(|s| s.as_str()).collect::<Vec<&str>>().join("\0").as_bytes(), highestmodseq, mailbox_hash as i64],
sqlite3::params![select_response.uidvalidity as Sqlite3UID, select_response.flags.1.iter().map(|s| s.as_str()).collect::<Vec<&str>>().join("\0").as_bytes(), highestmodseq, mailbox_hash],
)
.chain_err_summary(|| {
format!(
@ -304,7 +304,7 @@ mod sqlite3_m {
sqlite3::params![
select_response.uidvalidity as Sqlite3UID,
select_response.flags.1.iter().map(|s| s.as_str()).collect::<Vec<&str>>().join("\0").as_bytes(),
mailbox_hash as i64
mailbox_hash
],
)
.chain_err_summary(|| {
@ -340,7 +340,7 @@ mod sqlite3_m {
.join("\0")
.as_bytes(),
highestmodseq,
mailbox_hash as i64
mailbox_hash
],
)
.chain_err_summary(|| {
@ -362,7 +362,7 @@ mod sqlite3_m {
.collect::<Vec<&str>>()
.join("\0")
.as_bytes(),
mailbox_hash as i64
mailbox_hash
],
)
.chain_err_summary(|| {
@ -386,7 +386,7 @@ mod sqlite3_m {
)?;
let ret: Vec<(UID, Envelope, Option<ModSequence>)> = stmt
.query_map(sqlite3::params![mailbox_hash as i64], |row| {
.query_map(sqlite3::params![mailbox_hash], |row| {
Ok((
row.get(0).map(|i: Sqlite3UID| i as UID)?,
row.get(1)?,
@ -464,7 +464,7 @@ mod sqlite3_m {
max_uid = std::cmp::max(max_uid, *uid);
tx.execute(
"INSERT OR REPLACE INTO envelopes (hash, uid, mailbox_hash, modsequence, envelope) VALUES (?1, ?2, ?3, ?4, ?5)",
sqlite3::params![envelope.hash(), *uid as Sqlite3UID, mailbox_hash as i64, modseq, &envelope],
sqlite3::params![envelope.hash(), *uid as Sqlite3UID, mailbox_hash, modseq, &envelope],
).chain_err_summary(|| format!("Could not insert envelope {} {} in header_cache of account {}", envelope.message_id(), envelope.hash(), uid_store.account_name))?;
}
}
@ -498,7 +498,7 @@ mod sqlite3_m {
hash_index_lck.remove(env_hash);
tx.execute(
"DELETE FROM envelopes WHERE mailbox_hash = ?1 AND uid = ?2;",
sqlite3::params![mailbox_hash as i64, *uid as Sqlite3UID],
sqlite3::params![mailbox_hash, *uid as Sqlite3UID],
)
.chain_err_summary(|| {
format!(
@ -513,18 +513,18 @@ mod sqlite3_m {
)?;
let mut ret: Vec<Envelope> = stmt
.query_map(
sqlite3::params![mailbox_hash as i64, *uid as Sqlite3UID],
|row| row.get(0),
)?
.query_map(sqlite3::params![mailbox_hash, *uid as Sqlite3UID], |row| {
row.get(0)
})?
.collect::<std::result::Result<_, _>>()?;
if let Some(mut env) = ret.pop() {
env.set_flags(*flags);
env.labels_mut().clear();
env.labels_mut().extend(tags.iter().map(|t| tag_hash!(t)));
env.tags_mut().clear();
env.tags_mut()
.extend(tags.iter().map(|t| TagHash::from_bytes(t.as_bytes())));
tx.execute(
"UPDATE envelopes SET envelope = ?1 WHERE mailbox_hash = ?2 AND uid = ?3;",
sqlite3::params![&env, mailbox_hash as i64, *uid as Sqlite3UID],
sqlite3::params![&env, mailbox_hash, *uid as Sqlite3UID],
)
.chain_err_summary(|| {
format!(
@ -567,16 +567,13 @@ mod sqlite3_m {
)?;
let x = stmt
.query_map(
sqlite3::params![mailbox_hash as i64, uid as Sqlite3UID],
|row| {
Ok((
row.get(0).map(|u: Sqlite3UID| u as UID)?,
row.get(1)?,
row.get(2)?,
))
},
)?
.query_map(sqlite3::params![mailbox_hash, uid as Sqlite3UID], |row| {
Ok((
row.get(0).map(|u: Sqlite3UID| u as UID)?,
row.get(1)?,
row.get(2)?,
))
})?
.collect::<std::result::Result<_, _>>()?;
x
}
@ -586,7 +583,7 @@ mod sqlite3_m {
)?;
let x = stmt
.query_map(sqlite3::params![mailbox_hash as i64, env_hash], |row| {
.query_map(sqlite3::params![mailbox_hash, env_hash], |row| {
Ok((
row.get(0).map(|u: Sqlite3UID| u as UID)?,
row.get(1)?,
@ -620,10 +617,9 @@ mod sqlite3_m {
"SELECT rfc822 FROM envelopes WHERE mailbox_hash = ?1 AND uid = ?2;",
)?;
let x = stmt
.query_map(
sqlite3::params![mailbox_hash as i64, uid as Sqlite3UID],
|row| row.get(0),
)?
.query_map(sqlite3::params![mailbox_hash, uid as Sqlite3UID], |row| {
row.get(0)
})?
.collect::<std::result::Result<_, _>>()?;
x
}
@ -632,9 +628,7 @@ mod sqlite3_m {
"SELECT rfc822 FROM envelopes WHERE mailbox_hash = ?1 AND hash = ?2;",
)?;
let x = stmt
.query_map(sqlite3::params![mailbox_hash as i64, env_hash], |row| {
row.get(0)
})?
.query_map(sqlite3::params![mailbox_hash, env_hash], |row| row.get(0))?
.collect::<std::result::Result<_, _>>()?;
x
}

View File

@ -166,11 +166,11 @@ impl ImapConnection {
new_unseen.insert(env.hash());
}
for f in keywords {
let hash = tag_hash!(f);
let hash = TagHash::from_bytes(f.as_bytes());
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, f.to_string());
}
env.labels_mut().push(hash);
env.tags_mut().push(hash);
}
}
}
@ -252,19 +252,19 @@ impl ImapConnection {
}
let (flags, tags) = flags.unwrap();
if env_lck[&env_hash].inner.flags() != flags
|| env_lck[&env_hash].inner.labels()
|| env_lck[&env_hash].inner.tags()
!= &tags
.iter()
.map(|t| tag_hash!(t))
.collect::<SmallVec<[u64; 8]>>()
.map(|t| TagHash::from_bytes(t.as_bytes()))
.collect::<SmallVec<[TagHash; 8]>>()
{
env_lck.entry(env_hash).and_modify(|entry| {
entry.inner.set_flags(flags);
entry.inner.labels_mut().clear();
entry.inner.tags_mut().clear();
entry
.inner
.labels_mut()
.extend(tags.iter().map(|t| tag_hash!(t)));
.tags_mut()
.extend(tags.iter().map(|t| TagHash::from_bytes(t.as_bytes())));
});
refresh_events.push((
uid,
@ -452,11 +452,11 @@ impl ImapConnection {
new_unseen.insert(env.hash());
}
for f in keywords {
let hash = tag_hash!(f);
let hash = TagHash::from_bytes(f.as_bytes());
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, f.to_string());
}
env.labels_mut().push(hash);
env.tags_mut().push(hash);
}
}
}
@ -540,19 +540,19 @@ impl ImapConnection {
}
let (flags, tags) = flags.unwrap();
if env_lck[&env_hash].inner.flags() != flags
|| env_lck[&env_hash].inner.labels()
|| env_lck[&env_hash].inner.tags()
!= &tags
.iter()
.map(|t| tag_hash!(t))
.collect::<SmallVec<[u64; 8]>>()
.map(|t| TagHash::from_bytes(t.as_bytes()))
.collect::<SmallVec<[TagHash; 8]>>()
{
env_lck.entry(env_hash).and_modify(|entry| {
entry.inner.set_flags(flags);
entry.inner.labels_mut().clear();
entry.inner.tags_mut().clear();
entry
.inner
.labels_mut()
.extend(tags.iter().map(|t| tag_hash!(t)));
.tags_mut()
.extend(tags.iter().map(|t| TagHash::from_bytes(t.as_bytes())));
});
refresh_events.push((
uid,

View File

@ -26,7 +26,6 @@ use crate::email::parser::{
BytesExt, IResult,
};
use crate::error::ResultIntoMeliError;
use crate::get_path_hash;
use nom::{
branch::{alt, permutation},
bytes::complete::{is_a, is_not, tag, take, take_until, take_while},
@ -479,7 +478,7 @@ pub fn list_mailbox_result(input: &[u8]) -> IResult<&[u8], ImapMailbox> {
}
}
f.imap_path = path.to_string();
f.hash = get_path_hash!(&f.imap_path);
f.hash = MailboxHash::from_bytes(f.imap_path.as_bytes());
f.path = if separator == b'/' {
f.imap_path.clone()
} else {
@ -487,7 +486,7 @@ pub fn list_mailbox_result(input: &[u8]) -> IResult<&[u8], ImapMailbox> {
};
f.name = if let Some(pos) = f.imap_path.as_bytes().iter().rposition(|&c| c == separator)
{
f.parent = Some(get_path_hash!(&f.imap_path[..pos]));
f.parent = Some(MailboxHash::from_bytes(f.imap_path[..pos].as_bytes()));
f.imap_path[pos + 1..].to_string()
} else {
f.imap_path.clone()
@ -984,7 +983,7 @@ fn test_imap_fetch_response() {
let mut address = SmallVec::new();
address.push(Address::new(None, "xx@xx.com".to_string()));
let mut env = Envelope::new(0);
let mut env = Envelope::new(EnvelopeHash::default());
env.set_subject("xxxx/xxxx".as_bytes().to_vec());
env.set_date("Fri, 24 Jun 2011 10:09:10 +0000".as_bytes());
env.set_from(address.clone());
@ -1599,7 +1598,9 @@ pub struct StatusResponse {
pub fn status_response(input: &[u8]) -> IResult<&[u8], StatusResponse> {
let (input, _) = tag("* STATUS ")(input)?;
let (input, mailbox) = take_until(" (")(input)?;
let mailbox = mailbox_token(mailbox).map(|(_, m)| get_path_hash!(m)).ok();
let mailbox = mailbox_token(mailbox)
.map(|(_, m)| MailboxHash::from_bytes(m.as_bytes()))
.ok();
let (input, _) = tag(" (")(input)?;
let (input, result) = permutation((
opt(preceded(

View File

@ -27,6 +27,7 @@ use crate::backends::BackendMailbox;
use crate::backends::{
RefreshEvent,
RefreshEventKind::{self, *},
TagHash,
};
use crate::error::*;
use std::convert::TryInto;
@ -233,11 +234,11 @@ impl ImapConnection {
mailbox.unseen.lock().unwrap().insert_new(env.hash());
}
for f in keywords {
let hash = tag_hash!(f);
let hash = TagHash::from_bytes(f.as_bytes());
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, f.to_string());
}
env.labels_mut().push(hash);
env.tags_mut().push(hash);
}
}
mailbox.exists.lock().unwrap().insert_new(env.hash());
@ -364,11 +365,11 @@ impl ImapConnection {
mailbox.unseen.lock().unwrap().insert_new(env.hash());
}
for f in keywords {
let hash = tag_hash!(f);
let hash = TagHash::from_bytes(f.as_bytes());
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, f.to_string());
}
env.labels_mut().push(hash);
env.tags_mut().push(hash);
}
}
mailbox.exists.lock().unwrap().insert_new(env.hash());

View File

@ -382,11 +382,11 @@ pub async fn examine_updates(
}
mailbox.exists.lock().unwrap().insert_new(env.hash());
for f in keywords {
let hash = tag_hash!(f);
let hash = TagHash::from_bytes(f.as_bytes());
if !tag_lck.contains_key(&hash) {
tag_lck.insert(hash, f.to_string());
}
env.labels_mut().push(hash);
env.tags_mut().push(hash);
}
}
}

View File

@ -29,26 +29,12 @@ use futures::lock::Mutex as FutureMutex;
use isahc::config::RedirectPolicy;
use isahc::{AsyncReadResponseExt, HttpClient};
use serde_json::Value;
use std::collections::{hash_map::DefaultHasher, HashMap, HashSet};
use std::collections::{HashMap, HashSet};
use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant};
macro_rules! tag_hash {
($t:ident) => {{
let mut hasher = DefaultHasher::default();
$t.hash(&mut hasher);
hasher.finish()
}};
($t:literal) => {{
let mut hasher = DefaultHasher::default();
$t.hash(&mut hasher);
hasher.finish()
}};
}
#[macro_export]
macro_rules! _impl {
($(#[$outer:meta])*$field:ident : $t:ty) => {
@ -178,29 +164,25 @@ impl Store {
.keywords()
.keys()
.map(|tag| {
let tag_hash = {
let mut hasher = DefaultHasher::default();
tag.hash(&mut hasher);
hasher.finish()
};
let tag_hash = TagHash::from_bytes(tag.as_bytes());
if !tag_lck.contains_key(&tag_hash) {
tag_lck.insert(tag_hash, tag.to_string());
}
tag_hash
})
.collect::<SmallVec<[u64; 1024]>>();
.collect::<SmallVec<[TagHash; 1024]>>();
let id = obj.id.clone();
let mailbox_ids = obj.mailbox_ids.clone();
let blob_id = obj.blob_id.clone();
drop(tag_lck);
let mut ret: Envelope = obj.into();
debug_assert_eq!(tag_hash!("$draft"), 6613915297903591176);
debug_assert_eq!(tag_hash!("$seen"), 1683863812294339685);
debug_assert_eq!(tag_hash!("$flagged"), 2714010747478170100);
debug_assert_eq!(tag_hash!("$answered"), 8940855303929342213);
debug_assert_eq!(tag_hash!("$junk"), 2656839745430720464);
debug_assert_eq!(tag_hash!("$notjunk"), 4091323799684325059);
debug_assert_eq!(TagHash::from_bytes(b"$draft").0, 6613915297903591176);
debug_assert_eq!(TagHash::from_bytes(b"$seen").0, 1683863812294339685);
debug_assert_eq!(TagHash::from_bytes(b"$flagged").0, 2714010747478170100);
debug_assert_eq!(TagHash::from_bytes(b"$answered").0, 8940855303929342213);
debug_assert_eq!(TagHash::from_bytes(b"$junk").0, 2656839745430720464);
debug_assert_eq!(TagHash::from_bytes(b"$notjunk").0, 4091323799684325059);
let mut id_store_lck = self.id_store.lock().unwrap();
let mut reverse_id_store_lck = self.reverse_id_store.lock().unwrap();
let mut blob_id_store_lck = self.blob_id_store.lock().unwrap();
@ -219,7 +201,7 @@ impl Store {
id_store_lck.insert(ret.hash(), id);
blob_id_store_lck.insert(ret.hash(), blob_id);
for t in tags {
match t {
match t.0 {
6613915297903591176 => {
ret.set_flags(ret.flags() | Flag::DRAFT);
}
@ -233,7 +215,7 @@ impl Store {
ret.set_flags(ret.flags() | Flag::REPLIED);
}
2656839745430720464 | 4091323799684325059 => { /* ignore */ }
_ => ret.labels_mut().push(t),
_ => ret.tags_mut().push(t),
}
}
ret
@ -811,7 +793,7 @@ impl MailBackend for JmapType {
Ok(_) => {}
Err(t) => {
if *value {
tag_index_lck.insert(tag_hash!(t), t.clone());
tag_index_lck.insert(TagHash::from_bytes(t.as_bytes()), t.clone());
}
}
}
@ -883,11 +865,7 @@ impl JmapType {
)));
let server_conf = JmapServerConf::new(s)?;
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(s.name.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(s.name.as_bytes());
let store = Arc::new(Store {
account_name: Arc::new(s.name.clone()),
account_hash,

View File

@ -23,9 +23,7 @@ use super::*;
impl Id<MailboxObject> {
pub fn into_hash(&self) -> MailboxHash {
let mut h = DefaultHasher::new();
h.write(self.inner.as_bytes());
h.finish()
MailboxHash::from_bytes(self.inner.as_bytes())
}
}

View File

@ -159,7 +159,7 @@ impl MaildirMailbox {
};
let ret = MaildirMailbox {
hash: h.finish(),
hash: MailboxHash(h.finish()),
name: file_name,
path: fname.unwrap().to_path_buf(),
fs_path: pathbuf,

View File

@ -222,11 +222,7 @@ impl MailBackend for MaildirType {
fn refresh(&mut self, mailbox_hash: MailboxHash) -> ResultFuture<()> {
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
let account_hash = {
let mut hasher = DefaultHasher::default();
hasher.write(self.name.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(self.name.as_bytes());
let sender = self.event_consumer.clone();
let mailbox: &MaildirMailbox = &self.mailboxes[&mailbox_hash];
@ -329,11 +325,7 @@ impl MailBackend for MaildirType {
let sender = self.event_consumer.clone();
let (tx, rx) = channel();
let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();
let account_hash = {
let mut hasher = DefaultHasher::default();
hasher.write(self.name.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(self.name.as_bytes());
let root_mailbox = self.path.to_path_buf();
watcher
.watch(&root_mailbox, RecursiveMode::Recursive)
@ -384,7 +376,7 @@ impl MailBackend for MaildirType {
}
};
}
let mailbox_hash = get_path_hash!(pathbuf);
let mailbox_hash = MailboxHash(get_path_hash!(pathbuf));
let file_name = pathbuf
.as_path()
.strip_prefix(&root_mailbox)
@ -425,7 +417,7 @@ impl MailBackend for MaildirType {
/* Update */
DebouncedEvent::NoticeWrite(pathbuf) | DebouncedEvent::Write(pathbuf) => {
debug!("DebouncedEvent::Write(path = {:?}", &pathbuf);
let mailbox_hash = get_path_hash!(pathbuf);
let mailbox_hash = MailboxHash(get_path_hash!(pathbuf));
let mut hash_indexes_lock = hash_indexes.lock().unwrap();
let index_lock =
&mut hash_indexes_lock.entry(mailbox_hash).or_default();
@ -502,7 +494,7 @@ impl MailBackend for MaildirType {
/* Remove */
DebouncedEvent::NoticeRemove(pathbuf) | DebouncedEvent::Remove(pathbuf) => {
debug!("DebouncedEvent::Remove(path = {:?}", pathbuf);
let mailbox_hash = get_path_hash!(pathbuf);
let mailbox_hash = MailboxHash(get_path_hash!(pathbuf));
let mut hash_indexes_lock = hash_indexes.lock().unwrap();
let index_lock = hash_indexes_lock.entry(mailbox_hash).or_default();
let hash: EnvelopeHash = if let Some((k, _)) =
@ -556,9 +548,9 @@ impl MailBackend for MaildirType {
/* Envelope hasn't changed */
DebouncedEvent::Rename(src, dest) => {
debug!("DebouncedEvent::Rename(src = {:?}, dest = {:?})", src, dest);
let mailbox_hash = get_path_hash!(src);
let mailbox_hash = MailboxHash(get_path_hash!(src));
let dest_mailbox = {
let dest_mailbox = get_path_hash!(dest);
let dest_mailbox = MailboxHash(get_path_hash!(dest));
if dest_mailbox == mailbox_hash {
None
} else {
@ -1018,7 +1010,7 @@ impl MailBackend for MaildirType {
.map(|item| *item.0)
});
let mailbox_hash = get_path_hash!(&path);
let mailbox_hash = MailboxHash(get_path_hash!(&path));
if let Some(parent) = parent {
self.mailboxes
.entry(parent)

View File

@ -136,9 +136,8 @@ use nom::{self, error::Error as NomError, error::ErrorKind as NomErrorKind, IRes
extern crate notify;
use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use std::collections::hash_map::{DefaultHasher, HashMap};
use std::collections::hash_map::HashMap;
use std::fs::File;
use std::hash::Hasher;
use std::io::{BufReader, Read};
use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};
@ -981,11 +980,7 @@ impl MailBackend for MboxType {
.map_err(MeliError::new)?;
debug!("watching {:?}", f.fs_path.as_path());
}
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(self.account_name.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(self.account_name.as_bytes());
let mailboxes = self.mailboxes.clone();
let mailbox_index = self.mailbox_index.clone();
let prefer_mbox_type = self.prefer_mbox_type;
@ -1005,7 +1000,7 @@ impl MailBackend for MboxType {
Ok(event) => match event {
/* Update */
DebouncedEvent::NoticeWrite(pathbuf) | DebouncedEvent::Write(pathbuf) => {
let mailbox_hash = get_path_hash!(&pathbuf);
let mailbox_hash = MailboxHash(get_path_hash!(&pathbuf));
let file = match std::fs::OpenOptions::new()
.read(true)
.write(true)
@ -1067,7 +1062,7 @@ impl MailBackend for MboxType {
.values()
.any(|f| f.fs_path == pathbuf)
{
let mailbox_hash = get_path_hash!(&pathbuf);
let mailbox_hash = MailboxHash(get_path_hash!(&pathbuf));
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
@ -1084,7 +1079,7 @@ impl MailBackend for MboxType {
}
DebouncedEvent::Rename(src, dest) => {
if mailboxes.lock().unwrap().values().any(|f| f.fs_path == src) {
let mailbox_hash = get_path_hash!(&src);
let mailbox_hash = MailboxHash(get_path_hash!(&src));
(sender)(
account_hash,
BackendEvent::Refresh(RefreshEvent {
@ -1336,7 +1331,7 @@ impl MboxType {
.file_name()
.map(|f| f.to_string_lossy().into())
.unwrap_or_default();
let hash = get_path_hash!(&ret.path);
let hash = MailboxHash(get_path_hash!(&ret.path));
let read_only = if let Ok(metadata) = std::fs::metadata(&ret.path) {
metadata.permissions().readonly()
@ -1374,7 +1369,7 @@ impl MboxType {
/* Look for other mailboxes */
for (k, f) in s.mailboxes.iter() {
if let Some(path_str) = f.extra.get("path") {
let hash = get_path_hash!(path_str);
let hash = MailboxHash(get_path_hash!(path_str));
let pathbuf: PathBuf = path_str.into();
if !pathbuf.exists() || pathbuf.is_dir() {
return Err(MeliError::new(format!(

View File

@ -589,15 +589,11 @@ impl NntpType {
deflate: get_conf_val!(s["use_deflate"], false)?,
},
};
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(s.name.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(s.name.as_bytes());
let account_name = Arc::new(s.name().to_string());
let mut mailboxes = HashMap::default();
for (k, _f) in s.mailboxes.iter() {
let mailbox_hash = get_path_hash!(&k);
let mailbox_hash = MailboxHash(get_path_hash!(&k));
mailboxes.insert(
mailbox_hash,
NntpMailbox {
@ -663,7 +659,7 @@ impl NntpType {
if s.len() != 3 {
continue;
}
let mailbox_hash = get_path_hash!(&s[0]);
let mailbox_hash = MailboxHash(get_path_hash!(&s[0]));
mailboxes_lck.entry(mailbox_hash).and_modify(|m| {
*m.high_watermark.lock().unwrap() = usize::from_str(s[1]).unwrap_or(0);
*m.low_watermark.lock().unwrap() = usize::from_str(s[2]).unwrap_or(0);

View File

@ -25,13 +25,9 @@ use crate::error::{MeliError, Result};
use crate::shellexpand::ShellExpandTrait;
use crate::{backends::*, Collection};
use smallvec::SmallVec;
use std::collections::{
hash_map::{DefaultHasher, HashMap},
BTreeMap,
};
use std::collections::{hash_map::HashMap, BTreeMap};
use std::error::Error;
use std::ffi::{CStr, CString, OsStr};
use std::hash::{Hash, Hasher};
use std::io::Read;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};
@ -91,7 +87,7 @@ impl DbConnection {
mailboxes: Arc<RwLock<HashMap<MailboxHash, NotmuchMailbox>>>,
index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>,
mailbox_index: Arc<RwLock<HashMap<EnvelopeHash, SmallVec<[MailboxHash; 16]>>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
tag_index: Arc<RwLock<BTreeMap<TagHash, String>>>,
account_hash: AccountHash,
event_consumer: BackendEventConsumer,
new_revision_uuid: u64,
@ -112,9 +108,7 @@ impl DbConnection {
let tags: (Flag, Vec<String>) = message.tags().collect_flags_and_tags();
let mut tag_lock = tag_index.write().unwrap();
for tag in tags.1.iter() {
let mut hasher = DefaultHasher::new();
hasher.write(tag.as_bytes());
let num = hasher.finish();
let num = TagHash::from_bytes(tag.as_bytes());
if !tag_lock.contains_key(&num) {
tag_lock.insert(num, tag.clone());
}
@ -366,11 +360,7 @@ impl NotmuchDb {
let mut mailboxes = HashMap::default();
for (k, f) in s.mailboxes.iter() {
if let Some(query_str) = f.extra.get("query") {
let hash = {
let mut h = DefaultHasher::new();
k.hash(&mut h);
h.finish()
};
let hash = MailboxHash::from_bytes(k.as_bytes());
mailboxes.insert(
hash,
NotmuchMailbox {
@ -395,11 +385,7 @@ impl NotmuchDb {
}
}
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(s.name().as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(s.name().as_bytes());
Ok(Box::new(NotmuchDb {
lib,
revision_uuid: Arc::new(RwLock::new(0)),
@ -535,8 +521,8 @@ impl MailBackend for NotmuchDb {
database: Arc<DbConnection>,
index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>,
mailbox_index: Arc<RwLock<HashMap<EnvelopeHash, SmallVec<[MailboxHash; 16]>>>>,
mailboxes: Arc<RwLock<HashMap<u64, NotmuchMailbox>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
mailboxes: Arc<RwLock<HashMap<MailboxHash, NotmuchMailbox>>>,
tag_index: Arc<RwLock<BTreeMap<TagHash, String>>>,
iter: std::vec::IntoIter<CString>,
}
impl FetchState {
@ -860,7 +846,7 @@ impl MailBackend for NotmuchDb {
}
for (f, v) in flags.iter() {
if let (Err(tag), true) = (f, v) {
let hash = tag_hash!(tag);
let hash = TagHash::from_bytes(tag.as_bytes());
collection
.tag_index
.write()

View File

@ -88,7 +88,7 @@ impl<'m> Message<'m> {
pub fn into_envelope(
self,
index: &RwLock<HashMap<EnvelopeHash, CString>>,
tag_index: &RwLock<BTreeMap<u64, String>>,
tag_index: &RwLock<BTreeMap<TagHash, String>>,
) -> Envelope {
let env_hash = self.env_hash();
let mut env = Envelope::new(env_hash);
@ -99,13 +99,11 @@ impl<'m> Message<'m> {
let mut tag_lock = tag_index.write().unwrap();
let (flags, tags) = TagIterator::new(&self).collect_flags_and_tags();
for tag in tags {
let mut hasher = DefaultHasher::new();
hasher.write(tag.as_bytes());
let num = hasher.finish();
let num = TagHash::from_bytes(tag.as_bytes());
if !tag_lock.contains_key(&num) {
tag_lock.insert(num, tag);
}
env.labels_mut().push(num);
env.tags_mut().push(num);
}
unsafe {
use crate::email::parser::address::rfc2822address_list;

View File

@ -20,7 +20,7 @@
*/
use super::*;
use crate::backends::MailboxHash;
use crate::backends::{MailboxHash, TagHash};
use smallvec::SmallVec;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
@ -37,7 +37,7 @@ pub struct Collection {
pub threads: Arc<RwLock<HashMap<MailboxHash, Threads>>>,
pub sent_mailbox: Arc<RwLock<Option<MailboxHash>>>,
pub mailboxes: Arc<RwLock<HashMap<MailboxHash, HashSet<EnvelopeHash>>>>,
pub tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
pub tag_index: Arc<RwLock<BTreeMap<TagHash, String>>>,
}
impl Default for Collection {

View File

@ -109,12 +109,11 @@ use crate::datetime::UnixTimestamp;
use crate::error::{MeliError, Result};
use crate::parser::BytesExt;
use crate::thread::ThreadNodeHash;
use crate::TagHash;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::hash_map::DefaultHasher;
use std::convert::TryInto;
use std::hash::Hasher;
use std::ops::Deref;
bitflags! {
@ -198,31 +197,7 @@ impl Mail {
}
}
#[derive(
Hash, Eq, PartialEq, Debug, Ord, PartialOrd, Default, Serialize, Deserialize, Copy, Clone,
)]
#[repr(transparent)]
pub struct EnvelopeHash(pub u64);
impl EnvelopeHash {
#[inline(always)]
pub fn from_bytes(bytes: &[u8]) -> Self {
let mut h = DefaultHasher::new();
h.write(bytes);
Self(h.finish())
}
#[inline(always)]
pub const fn to_be_bytes(self) -> [u8; 8] {
self.0.to_be_bytes()
}
}
impl core::fmt::Display for EnvelopeHash {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(fmt, "{}", self.0)
}
}
crate::declare_u64_hash!(EnvelopeHash);
/// `Envelope` represents all the header and structure data of an email we need to know.
///
@ -247,7 +222,7 @@ pub struct Envelope {
pub thread: ThreadNodeHash,
pub flags: Flag,
pub has_attachments: bool,
pub labels: SmallVec<[u64; 8]>,
pub tags: SmallVec<[TagHash; 8]>,
}
impl core::fmt::Debug for Envelope {
@ -290,7 +265,7 @@ impl Envelope {
thread: ThreadNodeHash::null(),
has_attachments: false,
flags: Flag::default(),
labels: SmallVec::new(),
tags: SmallVec::new(),
}
}
@ -809,12 +784,12 @@ impl Envelope {
self.has_attachments
}
pub fn labels(&self) -> &SmallVec<[u64; 8]> {
&self.labels
pub fn tags(&self) -> &SmallVec<[TagHash; 8]> {
&self.tags
}
pub fn labels_mut(&mut self) -> &mut SmallVec<[u64; 8]> {
&mut self.labels
pub fn tags_mut(&mut self) -> &mut SmallVec<[TagHash; 8]> {
&mut self.tags
}
}

View File

@ -147,6 +147,7 @@ pub extern crate uuid;
pub extern crate xdg_utils;
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Bytes(pub usize);
impl Bytes {
@ -395,3 +396,68 @@ pub mod shellexpand {
assert!(!Path::new("~").expand().complete(true).is_empty());
}
}
#[macro_export]
macro_rules! declare_u64_hash {
($type_name:ident) => {
#[derive(
Hash,
Eq,
PartialEq,
Debug,
Ord,
PartialOrd,
Default,
Serialize,
Deserialize,
Copy,
Clone,
)]
#[repr(transparent)]
pub struct $type_name(pub u64);
impl $type_name {
#[inline(always)]
pub fn from_bytes(bytes: &[u8]) -> Self {
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut h = DefaultHasher::new();
h.write(bytes);
Self(h.finish())
}
#[inline(always)]
pub const fn to_be_bytes(self) -> [u8; 8] {
self.0.to_be_bytes()
}
#[inline(always)]
pub const fn is_null(self) -> bool {
self.0 == 0
}
}
impl core::fmt::Display for $type_name {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(fmt, "{}", self.0)
}
}
#[cfg(feature = "sqlite3")]
impl rusqlite::types::ToSql for $type_name {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
Ok(rusqlite::types::ToSqlOutput::from(self.0 as i64))
}
}
#[cfg(feature = "sqlite3")]
impl rusqlite::types::FromSql for $type_name {
fn column_result(
value: rusqlite::types::ValueRef,
) -> rusqlite::types::FromSqlResult<Self> {
let b: i64 = rusqlite::types::FromSql::column_result(value)?;
Ok($type_name(b as u64))
}
}
};
}

View File

@ -19,7 +19,7 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::{error::*, logging::log, Envelope, EnvelopeHash};
use crate::{error::*, logging::log, Envelope};
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput};
pub use rusqlite::{self, params, Connection};
use std::path::PathBuf;
@ -159,17 +159,3 @@ impl FromSql for Envelope {
.map_err(|e| FromSqlError::Other(Box::new(e)))
}
}
impl ToSql for EnvelopeHash {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
Ok(ToSqlOutput::from(self.0 as i64))
}
}
impl FromSql for EnvelopeHash {
fn column_result(value: rusqlite::types::ValueRef) -> FromSqlResult<Self> {
let b: i64 = FromSql::column_result(value)?;
Ok(EnvelopeHash(b as u64))
}
}

View File

@ -150,7 +150,7 @@ impl Composer {
pager.set_show_scrollbar(true);
Composer {
reply_context: None,
account_hash: 0,
account_hash: AccountHash::default(),
cursor: Cursor::Headers,
pager,
draft: Draft::default(),
@ -2405,7 +2405,7 @@ hello world.
let envelope = Envelope::from_bytes(raw_mail.as_bytes(), None).expect("Could not parse mail");
let mut context = Context::new_mock();
let account_hash = context.accounts[0].hash();
let mailbox_hash = 0;
let mailbox_hash = MailboxHash::default();
let envelope_hash = envelope.hash();
context.accounts[0]
.collection

View File

@ -628,7 +628,7 @@ pub trait MailListingTrait: ListingTrait {
let tags_lck = collection.tag_index.read().unwrap();
if let Some((env, ref bytes)) = iter.next() {
let tags: Vec<&str> = env
.labels()
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
@ -645,7 +645,7 @@ pub trait MailListingTrait: ListingTrait {
}
for (env, bytes) in iter {
let tags: Vec<&str> = env
.labels()
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
@ -929,7 +929,8 @@ impl Component for Listing {
if context.is_online(account_hash).is_err()
&& !matches!(self.component, ListingComponent::Offline(_))
{
self.component = Offline(OfflineListing::new((account_hash, 0)));
self.component =
Offline(OfflineListing::new((account_hash, MailboxHash::default())));
}
if let Some(s) = self.status.as_mut() {
@ -948,7 +949,8 @@ impl Component for Listing {
if context.is_online(account_hash).is_err()
&& !matches!(self.component, ListingComponent::Offline(_))
{
self.component = Offline(OfflineListing::new((account_hash, 0)));
self.component =
Offline(OfflineListing::new((account_hash, MailboxHash::default())));
}
if let Some(s) = self.status.as_mut() {
s.draw(grid, (set_x(upper_left, mid + 1), bottom_right), context);
@ -2044,7 +2046,10 @@ impl Listing {
.collect();
let first_account_hash = account_entries[0].hash;
let mut ret = Listing {
component: Offline(OfflineListing::new((first_account_hash, 0))),
component: Offline(OfflineListing::new((
first_account_hash,
MailboxHash::default(),
))),
accounts: account_entries,
status: None,
dirty: true,
@ -2567,7 +2572,8 @@ impl Listing {
mailbox_settings!(context[account_hash][mailbox_hash].listing.index_style);
self.component.set_style(*index_style);
} else if !matches!(self.component, ListingComponent::Offline(_)) {
self.component = Offline(OfflineListing::new((account_hash, 0)));
self.component =
Offline(OfflineListing::new((account_hash, MailboxHash::default())));
}
self.status = None;
context

View File

@ -815,7 +815,7 @@ impl CompactListing {
pub const DESCRIPTION: &'static str = "compact listing";
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
Box::new(CompactListing {
cursor_pos: (coordinates.0, 1, 0),
cursor_pos: (coordinates.0, MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0,
sort: (Default::default(), Default::default()),
@ -854,7 +854,7 @@ impl CompactListing {
let account = &context.accounts[&self.cursor_pos.0];
if account.backend_capabilities.supports_tags {
let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() {
for t in e.tags().iter() {
if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1]
.tags

View File

@ -603,7 +603,7 @@ impl ConversationsListing {
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
Box::new(Self {
cursor_pos: (coordinates.0, 1, 0),
cursor_pos: (coordinates.0, MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0,
sort: (Default::default(), Default::default()),
@ -641,7 +641,7 @@ impl ConversationsListing {
let account = &context.accounts[&self.cursor_pos.0];
if account.backend_capabilities.supports_tags {
let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() {
for t in e.tags().iter() {
if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1]
.tags

View File

@ -607,7 +607,7 @@ impl fmt::Display for PlainListing {
impl PlainListing {
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
Box::new(PlainListing {
cursor_pos: (0, 1, 0),
cursor_pos: (AccountHash::default(), MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0,
sort: (Default::default(), Default::default()),
@ -637,7 +637,7 @@ impl PlainListing {
let account = &context.accounts[&self.cursor_pos.0];
if account.backend_capabilities.supports_tags {
let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() {
for t in e.tags().iter() {
if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1]
.tags

View File

@ -692,7 +692,7 @@ impl fmt::Display for ThreadListing {
impl ThreadListing {
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
Box::new(ThreadListing {
cursor_pos: (coordinates.0, 0, 0),
cursor_pos: (coordinates.0, MailboxHash::default(), 0),
new_cursor_pos: (coordinates.0, coordinates.1, 0),
length: 0,
sort: (Default::default(), Default::default()),
@ -792,7 +792,7 @@ impl ThreadListing {
let account = &context.accounts[&self.cursor_pos.0];
if account.backend_capabilities.supports_tags {
let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() {
for t in e.tags().iter() {
if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1]
.tags

View File

@ -1658,7 +1658,7 @@ impl Component for MailView {
}
fn process_event(&mut self, mut event: &mut UIEvent, context: &mut Context) -> bool {
if self.coordinates.0 == 0 || self.coordinates.1 == 0 {
if self.coordinates.0.is_null() || self.coordinates.1.is_null() {
return false;
}
let shortcuts = self.get_shortcuts(context);

View File

@ -28,6 +28,7 @@ extern crate xdg;
use crate::conf::deserializers::non_empty_string;
use crate::terminal::Color;
use melib::backends::TagHash;
use melib::search::Query;
use std::collections::HashSet;
mod overrides;
@ -952,6 +953,7 @@ mod dotaddressable {
impl DotAddressable for char {}
impl DotAddressable for IndexStyle {}
impl DotAddressable for u64 {}
impl DotAddressable for TagHash {}
impl DotAddressable for crate::terminal::Color {}
impl DotAddressable for crate::terminal::Attr {}
impl DotAddressable for crate::terminal::Key {}

View File

@ -766,10 +766,10 @@ impl Account {
.unwrap()
.entry(env_hash)
.and_modify(|entry| {
entry.labels_mut().clear();
entry
.labels_mut()
.extend(tags.into_iter().map(|h| tag_hash!(h)));
entry.tags_mut().clear();
entry.tags_mut().extend(
tags.into_iter().map(|h| TagHash::from_bytes(h.as_bytes())),
);
entry.set_flags(flags);
});
#[cfg(feature = "sqlite3")]
@ -1128,7 +1128,7 @@ impl Account {
}
pub fn load(&mut self, mailbox_hash: MailboxHash) -> result::Result<(), usize> {
if mailbox_hash == 0 {
if mailbox_hash.is_null() {
return Err(0);
}
match self.mailbox_entries[&mailbox_hash].status {

View File

@ -378,10 +378,10 @@ impl Default for ComposingSettingsOverride {
pub struct TagsSettingsOverride {
#[serde(deserialize_with = "tag_color_de")]
#[serde(default)]
pub colors: Option<HashMap<u64, Color>>,
pub colors: Option<HashMap<TagHash, Color>>,
#[serde(deserialize_with = "tag_set_de", alias = "ignore-tags")]
#[serde(default)]
pub ignore_tags: Option<HashSet<u64>>,
pub ignore_tags: Option<HashSet<TagHash>>,
}
impl Default for TagsSettingsOverride {
fn default() -> Self {

View File

@ -23,21 +23,20 @@
use super::DotAddressable;
use crate::terminal::Color;
use melib::{MeliError, Result};
use melib::{MeliError, Result, TagHash};
use serde::{Deserialize, Deserializer};
use std::collections::{hash_map::DefaultHasher, HashMap, HashSet};
use std::hash::Hasher;
use std::collections::{HashMap, HashSet};
#[derive(Default, Debug, Deserialize, Clone, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TagsSettings {
#[serde(default, deserialize_with = "tag_color_de")]
pub colors: HashMap<u64, Color>,
pub colors: HashMap<TagHash, Color>,
#[serde(default, deserialize_with = "tag_set_de", alias = "ignore-tags")]
pub ignore_tags: HashSet<u64>,
pub ignore_tags: HashSet<TagHash>,
}
pub fn tag_set_de<'de, D, T: std::convert::From<HashSet<u64>>>(
pub fn tag_set_de<'de, D, T: std::convert::From<HashSet<TagHash>>>(
deserializer: D,
) -> std::result::Result<T, D::Error>
where
@ -45,16 +44,12 @@ where
{
Ok(<Vec<String>>::deserialize(deserializer)?
.into_iter()
.map(|tag| {
let mut hasher = DefaultHasher::new();
hasher.write(tag.as_bytes());
hasher.finish()
})
.collect::<HashSet<u64>>()
.map(|tag| TagHash::from_bytes(tag.as_bytes()))
.collect::<HashSet<TagHash>>()
.into())
}
pub fn tag_color_de<'de, D, T: std::convert::From<HashMap<u64, Color>>>(
pub fn tag_color_de<'de, D, T: std::convert::From<HashMap<TagHash, Color>>>(
deserializer: D,
) -> std::result::Result<T, D::Error>
where
@ -70,17 +65,15 @@ where
Ok(<HashMap<String, _Color>>::deserialize(deserializer)?
.into_iter()
.map(|(tag, color)| {
let mut hasher = DefaultHasher::new();
hasher.write(tag.as_bytes());
(
hasher.finish(),
TagHash::from_bytes(tag.as_bytes()),
match color {
_Color::B(b) => Color::Byte(b),
_Color::C(c) => c,
},
)
})
.collect::<HashMap<u64, Color>>()
.collect::<HashMap<TagHash, Color>>()
.into())
}

View File

@ -319,7 +319,12 @@ fn run_app(opt: Opt) -> Result<()> {
sender,
receiver.clone(),
)?;
state.register_component(Box::new(EnvelopeView::new(wrapper, None, None, 0)));
state.register_component(Box::new(EnvelopeView::new(
wrapper,
None,
None,
AccountHash::default(),
)));
} else {
state = State::new(None, sender, receiver.clone())?;
#[cfg(feature = "svgscreenshot")]

View File

@ -99,7 +99,7 @@ fn main() -> Result<()> {
}
let account = &settings.accounts[&account_name].account;
let mut conn = ManageSieveConnection::new(
0,
AccountHash::default(),
account_name.clone(),
account,
melib::backends::BackendEventConsumer::new(std::sync::Arc::new(|_, _| {})),

View File

@ -182,13 +182,7 @@ impl Context {
account_conf.account.format = "maildir".to_string();
account_conf.account.root_mailbox = "/tmp/".to_string();
let sender = sender.clone();
let account_hash = {
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
hasher.write(name.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(name.as_bytes());
Account::new(
account_hash,
name,
@ -328,13 +322,7 @@ impl State {
.iter()
.map(|(n, a_s)| {
let sender = sender.clone();
let account_hash = {
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
hasher.write(n.as_bytes());
hasher.finish()
};
let account_hash = AccountHash::from_bytes(n.as_bytes());
Account::new(
account_hash,
n.to_string(),