Convert {Account,Mailbox}Hash from typedef to wrapper struct
parent
7382e30160
commit
259aeb0087
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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(|_, _| {})),
|
||||
|
|
16
src/state.rs
16
src/state.rs
|
@ -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(),
|
||||
|
|
Loading…
Reference in New Issue