diff --git a/Makefile b/Makefile index b4406806..96fbbf5d 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,12 @@ # along with meli. If not, see . .POSIX: .SUFFIXES: +CARGO_TARGET_DIR ?= target +MIN_RUSTC ?= 1.65.0 +CARGO_BIN ?= cargo +CARGO_ARGS ?= +CARGO_SORT_BIN = cargo-sort +PRINTF = /usr/bin/printf # Options PREFIX ?= /usr/local @@ -25,11 +31,6 @@ EXPANDED_PREFIX := `cd ${PREFIX} && pwd -P` BINDIR ?= ${EXPANDED_PREFIX}/bin MANDIR ?= ${EXPANDED_PREFIX}/share/man -CARGO_TARGET_DIR ?= target -MIN_RUSTC ?= 1.39.0 -CARGO_BIN ?= cargo -CARGO_ARGS ?= - # Installation parameters DOCS_SUBDIR ?= docs/ MANPAGES ?= meli.1 meli.conf.5 meli-themes.5 @@ -96,6 +97,15 @@ help: check: @${CARGO_BIN} check ${CARGO_ARGS} ${CARGO_COLOR}--target-dir="${CARGO_TARGET_DIR}" ${FEATURES} --all --tests --examples --benches --bins +.PHONY: fmt +fmt: + @$(CARGO_BIN) +nightly fmt --all || $(CARGO_BIN) fmt --all + @OUT=$$($(CARGO_SORT_BIN) -w 2>&1) || $(PRINTF) "WARN: %s cargo-sort failed or binary not found in PATH.\n" "$$OUT" + +.PHONY: lint +lint: + @$(CARGO_BIN) clippy --no-deps --all-features --all --tests --examples --benches --bins + .PHONY: test test: @${CARGO_BIN} test ${CARGO_ARGS} ${CARGO_COLOR}--target-dir="${CARGO_TARGET_DIR}" --all --tests --examples --benches --bins diff --git a/melib/build.rs b/melib/build.rs index 659e6ebd..56b4a166 100644 --- a/melib/build.rs +++ b/melib/build.rs @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +#![allow(clippy::needless_range_loop)] + #[cfg(feature = "unicode_algorithms")] include!("src/text_processing/types.rs"); diff --git a/melib/src/addressbook.rs b/melib/src/addressbook.rs index 427b8968..6fbf19b8 100644 --- a/melib/src/addressbook.rs +++ b/melib/src/addressbook.rs @@ -41,22 +41,37 @@ pub enum CardId { Hash(u64), } -impl Into for CardId { - fn into(self) -> String { +impl std::fmt::Display for CardId { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - CardId::Uuid(u) => u.to_string(), - CardId::Hash(u) => u.to_string(), + Self::Uuid(u) => u.as_hyphenated().fmt(fmt), + Self::Hash(u) => u.fmt(fmt), } } } +impl From for String { + fn from(val: CardId) -> Self { + val.to_string() + } +} + impl From for CardId { - fn from(s: String) -> CardId { - if let Ok(u) = uuid::Uuid::parse_str(s.as_str()) { - CardId::Uuid(u) + fn from(s: String) -> Self { + use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, + str::FromStr, + }; + + if let Ok(u) = Uuid::parse_str(s.as_str()) { + Self::Uuid(u) + } else if let Ok(num) = u64::from_str(s.trim()) { + Self::Hash(num) } else { - use std::str::FromStr; - CardId::Hash(u64::from_str(&s).unwrap()) + let mut hasher = DefaultHasher::default(); + s.hash(&mut hasher); + Self::Hash(hasher.finish()) } } } @@ -93,8 +108,8 @@ pub struct Card { } impl AddressBook { - pub fn new(display_name: String) -> AddressBook { - AddressBook { + pub fn new(display_name: String) -> Self { + Self { display_name, created: datetime::now(), last_edited: datetime::now(), @@ -102,8 +117,8 @@ impl AddressBook { } } - pub fn with_account(s: &crate::conf::AccountSettings) -> AddressBook { - let mut ret = AddressBook::new(s.name.clone()); + pub fn with_account(s: &crate::conf::AccountSettings) -> Self { + let mut ret = Self::new(s.name.clone()); if let Some(mutt_alias_file) = s.extra.get("mutt_alias_file").map(String::as_str) { match std::fs::read_to_string(std::path::Path::new(mutt_alias_file)) .map_err(|err| err.to_string()) @@ -171,8 +186,8 @@ impl Deref for AddressBook { } impl Card { - pub fn new() -> Card { - Card { + pub fn new() -> Self { + Self { id: CardId::Uuid(Uuid::new_v4()), title: String::new(), name: String::new(), @@ -293,8 +308,8 @@ impl Card { } impl From> for Card { - fn from(mut map: HashMap) -> Card { - let mut card = Card::new(); + fn from(mut map: HashMap) -> Self { + let mut card = Self::new(); if let Some(val) = map.remove("TITLE") { card.title = val; } diff --git a/melib/src/addressbook/vcard.rs b/melib/src/addressbook/vcard.rs index fdfb0294..20fae379 100644 --- a/melib/src/addressbook/vcard.rs +++ b/melib/src/addressbook/vcard.rs @@ -84,7 +84,7 @@ pub struct ContentLine { } impl CardDeserializer { - pub fn from_str(mut input: &str) -> Result> { + pub fn try_from_str(mut input: &str) -> Result> { input = if (!input.starts_with(HEADER_CRLF) || !input.ends_with(FOOTER_CRLF)) && (!input.starts_with(HEADER_LF) || !input.ends_with(FOOTER_LF)) { @@ -270,7 +270,7 @@ fn test_load_cards() { for s in parse_card().parse(contents.as_str()).unwrap().1 { println!(""); println!("{}", s); - println!("{:?}", CardDeserializer::from_str(s)); + println!("{:?}", CardDeserializer::try_from_str(s)); println!(""); } */ @@ -295,7 +295,7 @@ pub fn load_cards(p: &std::path::Path) -> Result> { Ok((_, c)) => { for s in c { ret.push( - CardDeserializer::from_str(s) + CardDeserializer::try_from_str(s) .and_then(TryInto::try_into) .map(|mut card| { Card::set_external_resource(&mut card, true); @@ -326,7 +326,13 @@ pub fn load_cards(p: &std::path::Path) -> Result> { #[test] fn test_card() { let j = "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Gump;Forrest;;Mr.;\r\nFN:Forrest Gump\r\nORG:Bubba Gump Shrimp Co.\r\nTITLE:Shrimp Man\r\nPHOTO;MEDIATYPE=image/gif:http://www.example.com/dir_photos/my_photo.gif\r\nTEL;TYPE=work,voice;VALUE=uri:tel:+1-111-555-1212\r\nTEL;TYPE=home,voice;VALUE=uri:tel:+1-404-555-1212\r\nADR;TYPE=WORK;PREF=1;LABEL=\"100 Waters Edge\\nBaytown\\, LA 30314\\nUnited States of America\":;;100 Waters Edge;Baytown;LA;30314;United States of America\r\nADR;TYPE=HOME;LABEL=\"42 Plantation St.\\nBaytown\\, LA 30314\\nUnited States of America\":;;42 Plantation St.;Baytown;LA;30314;United States of America\r\nEMAIL:forrestgump@example.com\r\nREV:20080424T195243Z\r\nx-qq:21588891\r\nEND:VCARD\r\n"; - println!("results = {:#?}", CardDeserializer::from_str(j).unwrap()); + println!( + "results = {:#?}", + CardDeserializer::try_from_str(j).unwrap() + ); let j = "BEGIN:VCARD\nVERSION:4.0\nN:Gump;Forrest;;Mr.;\nFN:Forrest Gump\nORG:Bubba Gump Shrimp Co.\nTITLE:Shrimp Man\nPHOTO;MEDIATYPE=image/gif:http://www.example.com/dir_photos/my_photo.gif\nTEL;TYPE=work,voice;VALUE=uri:tel:+1-111-555-1212\nTEL;TYPE=home,voice;VALUE=uri:tel:+1-404-555-1212\nADR;TYPE=WORK;PREF=1;LABEL=\"100 Waters Edge\\nBaytown\\, LA 30314\\nUnited States of America\":;;100 Waters Edge;Baytown;LA;30314;United States of America\nADR;TYPE=HOME;LABEL=\"42 Plantation St.\\nBaytown\\, LA 30314\\nUnited States of America\":;;42 Plantation St.;Baytown;LA;30314;United States of America\nEMAIL:forrestgump@example.com\nREV:20080424T195243Z\nx-qq:21588891\nEND:VCARD\n"; - println!("results = {:#?}", CardDeserializer::from_str(j).unwrap()); + println!( + "results = {:#?}", + CardDeserializer::try_from_str(j).unwrap() + ); } diff --git a/melib/src/backends.rs b/melib/src/backends.rs index 89533e00..6c673c90 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -86,6 +86,8 @@ pub type BackendCreator = Box< ) -> Result>, >; +pub type BackendValidateConfigFn = Box Result<()>>; + /// A hashmap containing all available mail backends. /// An abstraction over any available backends. pub struct Backends { @@ -94,12 +96,12 @@ pub struct Backends { pub struct Backend { pub create_fn: Box BackendCreator>, - pub validate_conf_fn: Box Result<()>>, + pub validate_conf_fn: BackendValidateConfigFn, } impl Default for Backends { fn default() -> Self { - Backends::new() + Self::new() } } @@ -149,7 +151,7 @@ pub const NOTMUCH_ERROR_DETAILS: &str = r#"If notmuch is installed but the libra impl Backends { pub fn new() -> Self { - let mut b = Backends { + let mut b = Self { map: HashMap::with_capacity_and_hasher(1, Default::default()), }; #[cfg(feature = "maildir_backend")] @@ -272,8 +274,8 @@ pub enum BackendEvent { } impl From for BackendEvent { - fn from(val: Error) -> BackendEvent { - BackendEvent::Notice { + fn from(val: Error) -> Self { + Self::Notice { description: val.summary.to_string(), content: Some(val.to_string()), level: LogLevel::ERROR, @@ -310,9 +312,10 @@ pub struct RefreshEvent { #[derive(Clone)] pub struct BackendEventConsumer(Arc); + impl BackendEventConsumer { pub fn new(b: Arc) -> Self { - BackendEventConsumer(b) + Self(b) } } @@ -355,6 +358,7 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync { Ok(Box::pin(async { Ok(()) })) } + #[allow(clippy::type_complexity)] fn fetch( &mut self, mailbox_hash: MailboxHash, @@ -493,8 +497,9 @@ pub struct ReadOnlyOp { } impl ReadOnlyOp { + #[allow(clippy::new_ret_no_self)] pub fn new(op: Box) -> Box { - Box::new(ReadOnlyOp { op }) + Box::new(Self { op }) } } @@ -507,8 +512,9 @@ impl BackendOp for ReadOnlyOp { } } -#[derive(Debug, Copy, Hash, Eq, Clone, Serialize, Deserialize, PartialEq)] +#[derive(Default, Debug, Copy, Hash, Eq, Clone, Serialize, Deserialize, PartialEq)] pub enum SpecialUsageMailbox { + #[default] Normal, Inbox, Archive, @@ -539,28 +545,22 @@ impl std::fmt::Display for SpecialUsageMailbox { } } -impl Default for SpecialUsageMailbox { - fn default() -> Self { - SpecialUsageMailbox::Normal - } -} - impl SpecialUsageMailbox { - pub fn detect_usage(name: &str) -> Option { + pub fn detect_usage(name: &str) -> Option { if name.eq_ignore_ascii_case("inbox") { - Some(SpecialUsageMailbox::Inbox) + Some(Self::Inbox) } else if name.eq_ignore_ascii_case("archive") { - Some(SpecialUsageMailbox::Archive) + Some(Self::Archive) } else if name.eq_ignore_ascii_case("drafts") { - Some(SpecialUsageMailbox::Drafts) + Some(Self::Drafts) } else if name.eq_ignore_ascii_case("junk") || name.eq_ignore_ascii_case("spam") { - Some(SpecialUsageMailbox::Junk) + Some(Self::Junk) } else if name.eq_ignore_ascii_case("sent") { - Some(SpecialUsageMailbox::Sent) + Some(Self::Sent) } else if name.eq_ignore_ascii_case("trash") { - Some(SpecialUsageMailbox::Trash) + Some(Self::Trash) } else { - Some(SpecialUsageMailbox::Normal) + Some(Self::Normal) } } } @@ -608,7 +608,7 @@ pub struct MailboxPermissions { impl Default for MailboxPermissions { fn default() -> Self { - MailboxPermissions { + Self { create_messages: false, remove_messages: false, set_flags: false, @@ -635,7 +635,7 @@ pub struct EnvelopeHashBatch { impl From for EnvelopeHashBatch { fn from(value: EnvelopeHash) -> Self { - EnvelopeHashBatch { + Self { first: value, rest: SmallVec::new(), } @@ -649,16 +649,16 @@ impl std::convert::TryFrom<&[EnvelopeHash]> for EnvelopeHashBatch { if value.is_empty() { return Err(()); } - Ok(EnvelopeHashBatch { + Ok(Self { first: value[0], rest: value[1..].iter().cloned().collect(), }) } } -impl Into> for &EnvelopeHashBatch { - fn into(self) -> BTreeSet { - self.iter().collect::>() +impl From<&EnvelopeHashBatch> for BTreeSet { + fn from(val: &EnvelopeHashBatch) -> Self { + val.iter().collect() } } @@ -667,6 +667,10 @@ impl EnvelopeHashBatch { std::iter::once(self.first).chain(self.rest.iter().cloned()) } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn len(&self) -> usize { 1 + self.rest.len() } @@ -715,6 +719,10 @@ impl LazyCountSet { self.not_yet_seen = self.not_yet_seen.saturating_sub(self.set.len() - old_len); } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + #[inline(always)] pub fn len(&self) -> usize { self.set.len() + self.not_yet_seen diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index eb76bc9d..37c5ef06 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -146,7 +146,7 @@ macro_rules! get_conf_val { #[derive(Debug)] pub struct UIDStore { account_hash: AccountHash, - account_name: Arc, + account_name: Arc, keep_offline_cache: bool, capabilities: Arc>, hash_index: Arc>>, @@ -171,11 +171,11 @@ pub struct UIDStore { impl UIDStore { fn new( account_hash: AccountHash, - account_name: Arc, + account_name: Arc, event_consumer: BackendEventConsumer, timeout: Option, ) -> Self { - UIDStore { + Self { account_hash, account_name, keep_offline_cache: false, @@ -422,7 +422,7 @@ impl MailBackend for ImapType { .collect()); } } - let new_mailboxes = ImapType::imap_mailboxes(&connection).await?; + let new_mailboxes = Self::imap_mailboxes(&connection).await?; let mut mailboxes = uid_store.mailboxes.lock().await; *mailboxes = new_mailboxes; /* @@ -776,9 +776,7 @@ impl MailBackend for ImapType { } Err(tag) => { let hash = TagHash::from_bytes(tag.as_bytes()); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, tag.to_string()); - } + tag_lck.entry(hash).or_insert_with(|| tag.to_string()); cmd.push_str(tag); cmd.push(' '); } @@ -1242,6 +1240,7 @@ impl MailBackend for ImapType { } impl ImapType { + #[allow(clippy::new_ret_no_self)] pub fn new( s: &AccountSettings, is_subscribed: Box bool + Send + Sync>, @@ -1302,7 +1301,7 @@ impl ImapType { timeout, }; let account_hash = AccountHash::from_bytes(s.name.as_bytes()); - let account_name = Arc::new(s.name.to_string()); + let account_name = s.name.to_string().into(); let uid_store: Arc = Arc::new(UIDStore { keep_offline_cache, ..UIDStore::new( @@ -1319,7 +1318,7 @@ impl ImapType { uid_store.clone(), ); - Ok(Box::new(ImapType { + Ok(Box::new(Self { server_conf, _is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)), connection: Arc::new(FutureMutex::new(connection)), @@ -1423,29 +1422,27 @@ impl ImapType { } if let Ok(mut mailbox) = protocol_parser::list_mailbox_result(l).map(|(_, v)| v) { if let Some(parent) = mailbox.parent { - if mailboxes.contains_key(&parent) { - mailboxes - .entry(parent) - .and_modify(|e| e.children.push(mailbox.hash)); - } else { + if let std::collections::hash_map::Entry::Vacant(e) = mailboxes.entry(parent) { /* Insert dummy parent entry, populating only the children field. Later * when we encounter the parent entry we will swap its children with * dummy's */ - mailboxes.insert( - parent, - ImapMailbox { - children: vec![mailbox.hash], - ..ImapMailbox::default() - }, - ); + e.insert(ImapMailbox { + children: vec![mailbox.hash], + ..ImapMailbox::default() + }); + } else { + mailboxes + .entry(parent) + .and_modify(|e| e.children.push(mailbox.hash)); } } - if mailboxes.contains_key(&mailbox.hash) { + if let std::collections::hash_map::Entry::Vacant(e) = mailboxes.entry(mailbox.hash) + { + e.insert(mailbox); + } else { let entry = mailboxes.entry(mailbox.hash).or_default(); std::mem::swap(&mut entry.children, &mut mailbox.children); *entry = mailbox; - } else { - mailboxes.insert(mailbox.hash, mailbox); } } else if let Ok(status) = protocol_parser::status_response(l).map(|(_, v)| v) { if let Some(mailbox_hash) = status.mailbox { @@ -1828,9 +1825,7 @@ async fn fetch_hlpr(state: &mut FetchState) -> Result> { } for f in keywords { let hash = TagHash::from_bytes(f.as_bytes()); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, f.to_string()); - } + tag_lck.entry(hash).or_insert_with(|| f.to_string()); env.tags_mut().push(hash); } } diff --git a/melib/src/backends/imap/cache.rs b/melib/src/backends/imap/cache.rs index 36daf95a..df8b224e 100644 --- a/melib/src/backends/imap/cache.rs +++ b/melib/src/backends/imap/cache.rs @@ -34,9 +34,9 @@ pub struct ModSequence(pub std::num::NonZeroU64); impl TryFrom for ModSequence { type Error = (); - fn try_from(val: i64) -> std::result::Result { + fn try_from(val: i64) -> std::result::Result { std::num::NonZeroU64::new(val as u64) - .map(|u| Ok(ModSequence(u))) + .map(|u| Ok(Self(u))) .unwrap_or(Err(())) } } @@ -163,7 +163,7 @@ mod sqlite3_m { if i == 0 { return Err(FromSqlError::OutOfRange(0)); } - Ok(ModSequence::try_from(i).unwrap()) + Ok(Self::try_from(i).unwrap()) } } @@ -172,7 +172,7 @@ mod sqlite3_m { Ok(Box::new(Self { connection: sqlite3::open_or_create_db( &DB_DESCRIPTION, - Some(uid_store.account_name.as_str()), + Some(&uid_store.account_name), )?, loaded_mailboxes: BTreeSet::default(), uid_store, @@ -195,13 +195,13 @@ mod sqlite3_m { impl ImapCacheReset for Sqlite3Cache { fn reset_db(uid_store: &UIDStore) -> Result<()> { - sqlite3::reset_db(&DB_DESCRIPTION, Some(uid_store.account_name.as_str())) + sqlite3::reset_db(&DB_DESCRIPTION, Some(&uid_store.account_name)) } } impl ImapCache for Sqlite3Cache { fn reset(&mut self) -> Result<()> { - Sqlite3Cache::reset_db(&self.uid_store) + Self::reset_db(&self.uid_store) } fn mailbox_state(&mut self, mailbox_hash: MailboxHash) -> Result> { @@ -256,10 +256,7 @@ mod sqlite3_m { let mut tag_lck = self.uid_store.collection.tag_index.write().unwrap(); for f in to_str!(&flags).split('\0') { 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()); - } + tag_lck.entry(hash).or_insert_with(|| f.to_string()); } self.loaded_mailboxes.insert(mailbox_hash); Ok(Some(())) @@ -410,6 +407,8 @@ mod sqlite3_m { "SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1;", )?; + #[allow(clippy::let_and_return)] // false positive, the let binding is needed + // for the temporary to live long enough let x = stmt .query_map(sqlite3::params![mailbox_hash], |row| { Ok(( @@ -619,6 +618,8 @@ mod sqlite3_m { AND uid = ?2;", )?; + #[allow(clippy::let_and_return)] // false positive, the let binding is needed + // for the temporary to live long enough let x = stmt .query_map(sqlite3::params![mailbox_hash, uid as Sqlite3UID], |row| { Ok(( @@ -636,6 +637,8 @@ mod sqlite3_m { AND hash = ?2;", )?; + #[allow(clippy::let_and_return)] // false positive, the let binding is needed + // for the temporary to live long enough let x = stmt .query_map(sqlite3::params![mailbox_hash, env_hash], |row| { Ok(( @@ -670,6 +673,8 @@ mod sqlite3_m { let mut stmt = self.connection.prepare( "SELECT rfc822 FROM envelopes WHERE mailbox_hash = ?1 AND uid = ?2;", )?; + #[allow(clippy::let_and_return)] // false positive, the let binding is needed + // for the temporary to live long enough let x = stmt .query_map(sqlite3::params![mailbox_hash, uid as Sqlite3UID], |row| { row.get(0) @@ -681,6 +686,8 @@ mod sqlite3_m { let mut stmt = self.connection.prepare( "SELECT rfc822 FROM envelopes WHERE mailbox_hash = ?1 AND hash = ?2;", )?; + #[allow(clippy::let_and_return)] // false positive, the let binding is needed + // for the temporary to live long enough let x = stmt .query_map(sqlite3::params![mailbox_hash, env_hash], |row| row.get(0))? .collect::>()?; diff --git a/melib/src/backends/imap/cache/sync.rs b/melib/src/backends/imap/cache/sync.rs index a8cfe8af..84d1ff90 100644 --- a/melib/src/backends/imap/cache/sync.rs +++ b/melib/src/backends/imap/cache/sync.rs @@ -32,7 +32,7 @@ impl ImapConnection { pub async fn resync(&mut self, mailbox_hash: MailboxHash) -> Result>> { debug!("resync mailbox_hash {}", mailbox_hash); debug!(&self.sync_policy); - if let SyncPolicy::None = self.sync_policy { + if matches!(self.sync_policy, SyncPolicy::None) { return Ok(None); } @@ -107,7 +107,7 @@ impl ImapConnection { .unwrap() .get(&mailbox_hash) .cloned(); - // 3. tag2 UID FETCH 1: FLAGS + // 3. tag2 UID FETCH 1: FLAGS //if cached_uidvalidity.is_none() || cached_max_uid.is_none() { // return Ok(None); //} @@ -134,7 +134,7 @@ impl ImapConnection { } cache_handle.update_mailbox(mailbox_hash, &select_response)?; - // 2. tag1 UID FETCH :* + // 2. tag1 UID FETCH :* self.send_command(CommandBody::fetch( max_uid + 1.., common_attributes(), @@ -172,9 +172,7 @@ impl ImapConnection { } for f in keywords { let hash = TagHash::from_bytes(f.as_bytes()); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, f.to_string()); - } + tag_lck.entry(hash).or_insert_with(|| f.to_string()); env.tags_mut().push(hash); } } @@ -232,7 +230,7 @@ impl ImapConnection { unseen_lck.insert_set(new_unseen); } mailbox_exists.lock().unwrap().insert_set(payload_hash_set); - // 3. tag2 UID FETCH 1: FLAGS + // 3. tag2 UID FETCH 1: FLAGS let sequence_set = if max_uid == 0 { SequenceSet::from(..) } else { @@ -246,9 +244,9 @@ impl ImapConnection { .await?; self.read_response(&mut response, RequiredResponses::FETCH_REQUIRED) .await?; - //1) update cached flags for old messages; - //2) find out which old messages got expunged; and - //3) build a mapping between message numbers and UIDs (for old messages). + // 1) update cached flags for old messages; + // 2) find out which old messages got expunged; and + // 3) build a mapping between message numbers and UIDs (for old messages). let mut valid_envs = BTreeSet::default(); let mut env_lck = self.uid_store.envelopes.lock().unwrap(); let (_, v, _) = protocol_parser::fetch_responses(&response)?; @@ -422,7 +420,7 @@ impl ImapConnection { // "FETCH 1:* (FLAGS) (CHANGEDSINCE )" or // "SEARCH MODSEQ ". - // 2. tag1 UID FETCH :* + // 2. tag1 UID FETCH :* self.send_command_raw( format!( "UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \ @@ -464,9 +462,7 @@ impl ImapConnection { } for f in keywords { let hash = TagHash::from_bytes(f.as_bytes()); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, f.to_string()); - } + tag_lck.entry(hash).or_insert_with(|| f.to_string()); env.tags_mut().push(hash); } } @@ -518,7 +514,7 @@ impl ImapConnection { unseen_lck.insert_set(new_unseen); } mailbox_exists.lock().unwrap().insert_set(payload_hash_set); - // 3. tag2 UID FETCH 1: FLAGS + // 3. tag2 UID FETCH 1: FLAGS if cached_max_uid == 0 { self.send_command_raw( format!( @@ -540,7 +536,7 @@ impl ImapConnection { } self.read_response(&mut response, RequiredResponses::FETCH_REQUIRED) .await?; - //1) update cached flags for old messages; + // 1) update cached flags for old messages; let mut env_lck = self.uid_store.envelopes.lock().unwrap(); let (_, v, _) = protocol_parser::fetch_responses(&response)?; for FetchResponse { uid, flags, .. } in v { @@ -588,14 +584,14 @@ impl ImapConnection { .await?; self.read_response(&mut response, RequiredResponses::SEARCH) .await?; - //1) update cached flags for old messages; + // 1) update cached flags for old messages; let (_, v) = protocol_parser::search_results(response.as_slice())?; for uid in v { valid_envs.insert(generate_envelope_hash(&mailbox_path, &uid)); } { let mut env_lck = self.uid_store.envelopes.lock().unwrap(); - for env_hash in env_lck + let olds = env_lck .iter() .filter_map(|(h, cenv)| { if cenv.mailbox_hash == mailbox_hash { @@ -604,9 +600,8 @@ impl ImapConnection { None } }) - .collect::>() - .difference(&valid_envs) - { + .collect::>(); + for env_hash in olds.difference(&valid_envs) { refresh_events.push(( env_lck[env_hash].uid, RefreshEvent { diff --git a/melib/src/backends/imap/connection.rs b/melib/src/backends/imap/connection.rs index 2f0cdc77..e311d4c3 100644 --- a/melib/src/backends/imap/connection.rs +++ b/melib/src/backends/imap/connection.rs @@ -134,7 +134,7 @@ pub enum MailboxSelection { impl MailboxSelection { pub fn take(&mut self) -> Self { - std::mem::replace(self, MailboxSelection::None) + std::mem::replace(self, Self::None) } } @@ -157,7 +157,7 @@ impl ImapStream { server_conf: &ImapServerConf, #[cfg(debug_assertions)] id: Cow<'static, str>, uid_store: &UIDStore, - ) -> Result<(Capabilities, ImapStream)> { + ) -> Result<(Capabilities, Self)> { use std::net::TcpStream; let path = &server_conf.server_hostname; @@ -293,7 +293,7 @@ impl ImapStream { log::warn!("Could not set TCP keepalive in IMAP connection: {}", err); } let mut res = Vec::with_capacity(8 * 1024); - let mut ret = ImapStream { + let mut ret = Self { cmd_id, #[cfg(debug_assertions)] id, @@ -302,7 +302,7 @@ impl ImapStream { current_mailbox: MailboxSelection::None, timeout: server_conf.timeout, }; - if let ImapProtocol::ManageSieve = server_conf.protocol { + if matches!(server_conf.protocol, ImapProtocol::ManageSieve) { ret.read_response(&mut res).await?; let credentials = format!( "\0{}\0{}", @@ -530,7 +530,7 @@ impl ImapStream { pub async fn send_command(&mut self, body: CommandBody<'_>) -> Result<()> { timeout(self.timeout, async { let command = { - let tag = Tag::unchecked(format!("M{}", self.cmd_id.to_string())); + let tag = Tag::unchecked(format!("M{}", self.cmd_id)); Command { tag, body } }; @@ -629,8 +629,8 @@ impl ImapConnection { server_conf: &ImapServerConf, #[cfg(debug_assertions)] id: Cow<'static, str>, uid_store: Arc, - ) -> ImapConnection { - ImapConnection { + ) -> Self { + Self { stream: Err(Error::new("Offline".to_string())), #[cfg(debug_assertions)] id, @@ -1167,7 +1167,7 @@ pub struct ImapBlockingConnection { impl From for ImapBlockingConnection { fn from(conn: ImapConnection) -> Self { - ImapBlockingConnection { + Self { buf: vec![0; Connection::IO_BUF_SIZE], conn, prev_res_length: 0, @@ -1186,7 +1186,7 @@ impl ImapBlockingConnection { self.err.take() } - pub fn as_stream<'a>(&'a mut self) -> impl Future>> + 'a { + pub fn as_stream(&mut self) -> impl Future>> + '_ { self.result.drain(0..self.prev_res_length); self.prev_res_length = 0; let mut break_flag = false; diff --git a/melib/src/backends/imap/error.rs b/melib/src/backends/imap/error.rs index 7effdbb8..7565b913 100644 --- a/melib/src/backends/imap/error.rs +++ b/melib/src/backends/imap/error.rs @@ -32,8 +32,8 @@ use crate::error::{Error, ErrorKind}; impl From for Error { #[inline] - fn from(error: LiteralError) -> Error { - Error { + fn from(error: LiteralError) -> Self { + Self { summary: error.to_string().into(), details: None, source: Some(Arc::new(error)), @@ -44,8 +44,8 @@ impl From for Error { impl From for Error { #[inline] - fn from(error: SequenceSetError) -> Error { - Error { + fn from(error: SequenceSetError) -> Self { + Self { summary: error.to_string().into(), details: None, source: Some(Arc::new(error)), @@ -59,8 +59,8 @@ where AppendError: fmt::Debug + fmt::Display + Sync + Send + 'static, { #[inline] - fn from(error: AppendError) -> Error { - Error { + fn from(error: AppendError) -> Self { + Self { summary: error.to_string().into(), details: None, source: Some(Arc::new(error)), @@ -74,8 +74,8 @@ where CopyError: fmt::Debug + fmt::Display + Sync + Send + 'static, { #[inline] - fn from(error: CopyError) -> Error { - Error { + fn from(error: CopyError) -> Self { + Self { summary: error.to_string().into(), details: None, source: Some(Arc::new(error)), @@ -89,8 +89,8 @@ where MoveError: fmt::Debug + fmt::Display + Sync + Send + 'static, { #[inline] - fn from(error: MoveError) -> Error { - Error { + fn from(error: MoveError) -> Self { + Self { summary: error.to_string().into(), details: None, source: Some(Arc::new(error)), @@ -104,8 +104,8 @@ where ListError: fmt::Debug + fmt::Display + Sync + Send + 'static, { #[inline] - fn from(error: ListError) -> Error { - Error { + fn from(error: ListError) -> Self { + Self { summary: error.to_string().into(), details: None, source: Some(Arc::new(error)), diff --git a/melib/src/backends/imap/managesieve.rs b/melib/src/backends/imap/managesieve.rs index 4f92f33c..ab7499e6 100644 --- a/melib/src/backends/imap/managesieve.rs +++ b/melib/src/backends/imap/managesieve.rs @@ -328,7 +328,7 @@ impl ManageSieveConnection { ))), ..UIDStore::new( account_hash, - Arc::new(account_name), + account_name.into(), event_consumer, server_conf.timeout, ) diff --git a/melib/src/backends/imap/operations.rs b/melib/src/backends/imap/operations.rs index 80296b77..eba1513f 100644 --- a/melib/src/backends/imap/operations.rs +++ b/melib/src/backends/imap/operations.rs @@ -42,7 +42,7 @@ impl ImapOp { connection: Arc>, uid_store: Arc, ) -> Self { - ImapOp { + Self { uid, connection, mailbox_hash, diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index eba1bb98..d045fa2e 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +#![allow(clippy::type_complexity)] + use std::{convert::TryFrom, str::FromStr}; use nom::{ @@ -78,49 +80,49 @@ impl RequiredResponses { } let line = &line[b"* ".len()..]; let mut ret = false; - if self.intersects(RequiredResponses::CAPABILITY) { + if self.intersects(Self::CAPABILITY) { ret |= line.starts_with(b"CAPABILITY"); } - if self.intersects(RequiredResponses::BYE) { + if self.intersects(Self::BYE) { ret |= line.starts_with(b"BYE"); } - if self.intersects(RequiredResponses::FLAGS) { + if self.intersects(Self::FLAGS) { ret |= line.starts_with(b"FLAGS"); } - if self.intersects(RequiredResponses::EXISTS) { + if self.intersects(Self::EXISTS) { ret |= line.ends_with(b"EXISTS\r\n"); } - if self.intersects(RequiredResponses::RECENT) { + if self.intersects(Self::RECENT) { ret |= line.ends_with(b"RECENT\r\n"); } - if self.intersects(RequiredResponses::UNSEEN) { + if self.intersects(Self::UNSEEN) { ret |= line.starts_with(b"UNSEEN"); } - if self.intersects(RequiredResponses::PERMANENTFLAGS) { + if self.intersects(Self::PERMANENTFLAGS) { ret |= line.starts_with(b"PERMANENTFLAGS"); } - if self.intersects(RequiredResponses::UIDNEXT) { + if self.intersects(Self::UIDNEXT) { ret |= line.starts_with(b"UIDNEXT"); } - if self.intersects(RequiredResponses::UIDVALIDITY) { + if self.intersects(Self::UIDVALIDITY) { ret |= line.starts_with(b"UIDVALIDITY"); } - if self.intersects(RequiredResponses::LIST) { + if self.intersects(Self::LIST) { ret |= line.starts_with(b"LIST"); } - if self.intersects(RequiredResponses::LSUB) { + if self.intersects(Self::LSUB) { ret |= line.starts_with(b"LSUB"); } - if self.intersects(RequiredResponses::STATUS) { + if self.intersects(Self::STATUS) { ret |= line.starts_with(b"STATUS"); } - if self.intersects(RequiredResponses::EXPUNGE) { + if self.intersects(Self::EXPUNGE) { ret |= line.ends_with(b"EXPUNGE\r\n"); } - if self.intersects(RequiredResponses::SEARCH) { + if self.intersects(Self::SEARCH) { ret |= line.starts_with(b"SEARCH"); } - if self.intersects(RequiredResponses::FETCH) { + if self.intersects(Self::FETCH) { let mut ptr = 0; for (i, l) in line.iter().enumerate() { if !l.is_ascii_digit() { @@ -134,7 +136,7 @@ impl RequiredResponses { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub struct Alert(String); pub type ImapParseResult<'a, T> = Result<(&'a [u8], T, Option)>; @@ -142,7 +144,7 @@ pub struct ImapLineIterator<'a> { slice: &'a [u8], } -#[derive(Debug, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub enum ResponseCode { ///The human-readable text contains a special alert that MUST be presented /// to the user in a fashion that calls the user's attention to the message. @@ -229,7 +231,7 @@ impl std::fmt::Display for ResponseCode { } impl ResponseCode { - fn from(val: &[u8]) -> ResponseCode { + fn from(val: &[u8]) -> Self { use ResponseCode::*; if !val.starts_with(b"[") { let msg = val.trim(); @@ -280,7 +282,7 @@ impl ResponseCode { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub enum ImapResponse { Ok(ResponseCode), No(ResponseCode), @@ -291,7 +293,7 @@ pub enum ImapResponse { impl TryFrom<&'_ [u8]> for ImapResponse { type Error = Error; - fn try_from(val: &'_ [u8]) -> Result { + fn try_from(val: &'_ [u8]) -> Result { let val: &[u8] = val.split_rn().last().unwrap_or(val); let mut val = val[val.find(b" ").ok_or_else(|| { Error::new(format!( @@ -330,16 +332,15 @@ impl TryFrom<&'_ [u8]> for ImapResponse { } } -impl Into> for ImapResponse { - fn into(self) -> Result<()> { - match self { - Self::Ok(_) | Self::Preauth(_) | Self::Bye(_) => Ok(()), - Self::No(ResponseCode::Alert(msg)) | Self::Bad(ResponseCode::Alert(msg)) => { - Err(Error::new(msg)) - } - Self::No(err) => Err(Error::new(format!("{:?}", err))) +impl From for Result<()> { + fn from(resp: ImapResponse) -> Self { + match resp { + ImapResponse::Ok(_) | ImapResponse::Preauth(_) | ImapResponse::Bye(_) => Ok(()), + ImapResponse::No(ResponseCode::Alert(msg)) + | ImapResponse::Bad(ResponseCode::Alert(msg)) => Err(Error::new(msg)), + ImapResponse::No(err) => Err(Error::new(format!("{:?}", err))) .chain_err_summary(|| "IMAP NO Response.".to_string()), - Self::Bad(err) => Err(Error::new(format!("{:?}", err))) + ImapResponse::Bad(err) => Err(Error::new(format!("{:?}", err))) .chain_err_summary(|| "IMAP BAD Response.".to_string()), } } @@ -428,9 +429,11 @@ pub fn list_mailbox_result(input: &[u8]) -> IResult<&[u8], ImapMailbox> { input, ({ let separator: u8 = separator[0]; - let mut f = ImapMailbox::default(); - f.no_select = false; - f.is_subscribed = false; + let mut f = ImapMailbox { + no_select: false, + is_subscribed: false, + ..ImapMailbox::default() + }; if path.eq_ignore_ascii_case("INBOX") { f.is_subscribed = true; @@ -478,7 +481,7 @@ pub fn list_mailbox_result(input: &[u8]) -> IResult<&[u8], ImapMailbox> { )) } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct FetchResponse<'a> { pub uid: Option, pub message_sequence_number: MessageSequenceNumber, @@ -788,7 +791,7 @@ pub fn capabilities(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { /// This enum represents the server's untagged responses detailed in `7. Server /// Responses` of RFC 3501 INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1 -#[derive(Debug, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub enum UntaggedResponse<'s> { /// ```text /// 7.4.1. EXPUNGE Response @@ -926,7 +929,7 @@ pub fn search_results_raw<'a>(input: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { ))(input) } -#[derive(Debug, Default, PartialEq, Clone)] +#[derive(Debug, Default, Eq, PartialEq, Clone)] pub struct SelectResponse { pub exists: ImapNum, pub recent: ImapNum, @@ -1705,11 +1708,11 @@ mod tests { let mut address = SmallVec::new(); address.push(Address::new(None, "xx@xx.com".to_string())); 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_subject(b"xxxx/xxxx".to_vec()); + env.set_date(b"Fri, 24 Jun 2011 10:09:10 +0000"); env.set_from(address.clone()); env.set_to(address); - env.set_message_id("".as_bytes()); + env.set_message_id(b""); assert_eq!( fetch_response(input).unwrap(), ( diff --git a/melib/src/backends/imap/untagged.rs b/melib/src/backends/imap/untagged.rs index 744346eb..8ff362fd 100644 --- a/melib/src/backends/imap/untagged.rs +++ b/melib/src/backends/imap/untagged.rs @@ -115,7 +115,7 @@ impl ImapConnection { ); } let mut events = vec![]; - for (deleted_uid, deleted_hash) in self + let deleteds = self .uid_store .uid_index .lock() @@ -125,8 +125,8 @@ impl ImapConnection { *mailbox_hash_ == mailbox_hash && !results.contains(u) }) .map(|((_, uid), hash)| (*uid, *hash)) - .collect::>() - { + .collect::>(); + for (deleted_uid, deleted_hash) in deleteds { mailbox.exists.lock().unwrap().remove(deleted_hash); mailbox.unseen.lock().unwrap().remove(deleted_hash); self.uid_store @@ -246,9 +246,7 @@ impl ImapConnection { } for f in keywords { let hash = TagHash::from_bytes(f.as_bytes()); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, f.to_string()); - } + tag_lck.entry(hash).or_insert_with(|| f.to_string()); env.tags_mut().push(hash); } } @@ -381,9 +379,7 @@ impl ImapConnection { } for f in keywords { let hash = TagHash::from_bytes(f.as_bytes()); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, f.to_string()); - } + tag_lck.entry(hash).or_insert_with(|| f.to_string()); env.tags_mut().push(hash); } } diff --git a/melib/src/backends/imap/watch.rs b/melib/src/backends/imap/watch.rs index 4fe0ca20..562435fc 100644 --- a/melib/src/backends/imap/watch.rs +++ b/melib/src/backends/imap/watch.rs @@ -377,9 +377,7 @@ pub async fn examine_updates( mailbox.exists.lock().unwrap().insert_new(env.hash()); for f in keywords { let hash = TagHash::from_bytes(f.as_bytes()); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, f.to_string()); - } + tag_lck.entry(hash).or_insert_with(|| f.to_string()); env.tags_mut().push(hash); } } diff --git a/melib/src/backends/jmap.rs b/melib/src/backends/jmap.rs index 38af6beb..8b1814f8 100644 --- a/melib/src/backends/jmap.rs +++ b/melib/src/backends/jmap.rs @@ -142,7 +142,7 @@ impl JmapServerConf { s.name, ))); } - Ok(JmapServerConf { + Ok(Self { server_url: get_conf_val!(s["server_url"])?.to_string(), server_username: get_conf_val!(s["server_username"])?.to_string(), server_password: s.server_password()?, @@ -199,9 +199,7 @@ impl Store { "$junk" | "$notjunk" => { /* ignore */ } _ => { let tag_hash = TagHash::from_bytes(t.as_bytes()); - if !tag_lck.contains_key(&tag_hash) { - tag_lck.insert(tag_hash, t.to_string()); - } + tag_lck.entry(tag_hash).or_insert_with(|| t.to_string()); labels.push(tag_hash); } } @@ -244,9 +242,12 @@ impl Store { self.blob_id_store.lock().unwrap().remove(&env_hash); self.byte_cache.lock().unwrap().remove(&env_hash); let mut mailbox_hashes = SmallVec::new(); - for (k, set) in self.mailboxes_index.write().unwrap().iter_mut() { - if set.remove(&env_hash) { - mailbox_hashes.push(*k); + { + let mut mailboxes_lck = self.mailboxes_index.write().unwrap(); + for (k, set) in mailboxes_lck.iter_mut() { + if set.remove(&env_hash) { + mailbox_hashes.push(*k); + } } } Some((env_hash, mailbox_hashes)) @@ -448,7 +449,7 @@ impl MailBackend for JmapType { ); let import_call: ImportCall = ImportCall::new() - .account_id(conn.mail_account_id().clone()) + .account_id(conn.mail_account_id()) .emails(email_imports); req.add_call(&import_call); @@ -472,13 +473,13 @@ impl MailBackend for JmapType { } Ok(s) => s, }; - let m = ImportResponse::try_from(v.method_responses.remove(0)).or_else(|err| { + let m = ImportResponse::try_from(v.method_responses.remove(0)).map_err(|err| { let ierr: Result = serde_json::from_str(&res_text).map_err(|err| err.into()); if let Ok(err) = ierr { - Err(Error::new(format!("Could not save message: {:?}", err))) + Error::new(format!("Could not save message: {:?}", err)) } else { - Err(err.into()) + err } })?; @@ -529,7 +530,7 @@ impl MailBackend for JmapType { conn.connect().await?; let email_call: EmailQuery = EmailQuery::new( Query::new() - .account_id(conn.mail_account_id().clone()) + .account_id(conn.mail_account_id()) .filter(Some(filter)) .position(0), ) @@ -646,8 +647,6 @@ impl MailBackend for JmapType { ) }; let mut update_map: HashMap, Value> = HashMap::default(); - let mut ids: Vec> = Vec::with_capacity(env_hashes.rest.len() + 1); - let mut id_map: HashMap, EnvelopeHash> = HashMap::default(); let mut update_keywords: HashMap = HashMap::default(); update_keywords.insert( format!("mailboxIds/{}", &destination_mailbox_id), @@ -662,8 +661,8 @@ impl MailBackend for JmapType { { for env_hash in env_hashes.iter() { if let Some(id) = store.id_store.lock().unwrap().get(&env_hash) { - ids.push(id.clone()); - id_map.insert(id.clone(), env_hash); + // ids.push(id.clone()); + // id_map.insert(id.clone(), env_hash); update_map.insert(id.clone(), serde_json::json!(update_keywords.clone())); } } @@ -673,7 +672,7 @@ impl MailBackend for JmapType { let email_set_call: EmailSet = EmailSet::new( Set::::new() - .account_id(conn.mail_account_id().clone()) + .account_id(conn.mail_account_id()) .update(Some(update_map)), ); @@ -779,7 +778,7 @@ impl MailBackend for JmapType { let email_set_call: EmailSet = EmailSet::new( Set::::new() - .account_id(conn.mail_account_id().clone()) + .account_id(conn.mail_account_id()) .update(Some(update_map)), ); @@ -788,7 +787,7 @@ impl MailBackend for JmapType { let email_call: EmailGet = EmailGet::new( Get::new() .ids(Some(JmapArgument::Value(ids))) - .account_id(conn.mail_account_id().clone()) + .account_id(conn.mail_account_id()) .properties(Some(vec!["keywords".to_string()])), ); @@ -902,6 +901,7 @@ impl MailBackend for JmapType { } impl JmapType { + #[allow(clippy::new_ret_no_self)] pub fn new( s: &AccountSettings, is_subscribed: Box bool + Send + Sync>, @@ -932,7 +932,7 @@ impl JmapType { mailbox_state: Default::default(), }); - Ok(Box::new(JmapType { + Ok(Box::new(Self { connection: Arc::new(FutureMutex::new(JmapConnection::new( &server_conf, store.clone(), @@ -975,7 +975,8 @@ impl JmapType { get_conf_val!(s["use_token"], false)?; // either of these two needed - get_conf_val!(s["server_password"]).or(get_conf_val!(s["server_password_command"]))?; + get_conf_val!(s["server_password"]) + .or_else(|_| get_conf_val!(s["server_password_command"]))?; get_conf_val!(s["danger_accept_invalid_certs"], false)?; Ok(()) diff --git a/melib/src/backends/jmap/connection.rs b/melib/src/backends/jmap/connection.rs index 795fdaae..fddae5c4 100644 --- a/melib/src/backends/jmap/connection.rs +++ b/melib/src/backends/jmap/connection.rs @@ -59,7 +59,7 @@ impl JmapConnection { }; let client = client.build()?; let server_conf = server_conf.clone(); - Ok(JmapConnection { + Ok(Self { session: Arc::new(Mutex::new(Default::default())), request_no: Arc::new(Mutex::new(0)), client: Arc::new(client), @@ -80,16 +80,15 @@ impl JmapConnection { .get_async(&jmap_session_resource_url) .await .map_err(|err| { - let err = Error::new(format!( + //*self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); + Error::new(format!( "Could not connect to JMAP server endpoint for {}. Is your server url setting \ correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource \ discovery via /.well-known/jmap is supported. DNS SRV records are not \ suppported.)\nError connecting to server: {}", &self.server_conf.server_url, &err )) - .set_source(Some(Arc::new(err))); - //*self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); - err + .set_source(Some(Arc::new(err))) })?; if !req.status().is_success() { diff --git a/melib/src/backends/jmap/mailbox.rs b/melib/src/backends/jmap/mailbox.rs index 54aed08b..ed43a09c 100644 --- a/melib/src/backends/jmap/mailbox.rs +++ b/melib/src/backends/jmap/mailbox.rs @@ -76,7 +76,7 @@ impl BackendMailbox for JmapMailbox { } fn special_usage(&self) -> SpecialUsageMailbox { - match self.role.as_ref().map(String::as_str) { + match self.role.as_deref() { Some("inbox") => SpecialUsageMailbox::Inbox, Some("archive") => SpecialUsageMailbox::Archive, Some("junk") => SpecialUsageMailbox::Junk, diff --git a/melib/src/backends/jmap/objects/email.rs b/melib/src/backends/jmap/objects/email.rs index 2e45d99c..9b88d285 100644 --- a/melib/src/backends/jmap/objects/email.rs +++ b/melib/src/backends/jmap/objects/email.rs @@ -211,7 +211,7 @@ where T: Deserialize<'de> + Default, { let v = Option::::deserialize(deserializer)?; - Ok(v.unwrap_or(T::default())) + Ok(v.unwrap_or_default()) } impl EmailObject { @@ -242,9 +242,9 @@ pub struct EmailAddress { pub name: Option, } -impl Into for EmailAddress { - fn into(self) -> crate::email::Address { - let Self { email, mut name } = self; +impl From for crate::email::Address { + fn from(val: EmailAddress) -> Self { + let EmailAddress { email, mut name } = val; crate::make_address!((name.take().unwrap_or_default()), email) } } @@ -260,15 +260,15 @@ impl std::fmt::Display for EmailAddress { } impl std::convert::From for crate::Envelope { - fn from(mut t: EmailObject) -> crate::Envelope { - let mut env = crate::Envelope::new(t.id.into_hash()); + fn from(mut t: EmailObject) -> Self { + let mut env = Self::new(t.id.into_hash()); if let Ok(d) = crate::email::parser::dates::rfc5322_date(env.date_as_str().as_bytes()) { env.set_datetime(d); } if let Some(ref mut sent_at) = t.sent_at { let unix = datetime::rfc3339_to_timestamp(sent_at.as_bytes().to_vec()).unwrap_or(0); env.set_datetime(unix); - env.set_date(std::mem::replace(sent_at, String::new()).as_bytes()); + env.set_date(std::mem::take(sent_at).as_bytes()); } if let Some(v) = t.message_id.get(0) { @@ -293,12 +293,12 @@ impl std::convert::From for crate::Envelope { } env.set_has_attachments(t.has_attachment); if let Some(ref mut subject) = t.subject { - env.set_subject(std::mem::replace(subject, String::new()).into_bytes()); + env.set_subject(std::mem::take(subject).into_bytes()); } if let Some(ref mut from) = t.from { env.set_from( - std::mem::replace(from, SmallVec::new()) + std::mem::take(from) .into_iter() .map(|addr| addr.into()) .collect::>(), @@ -306,7 +306,7 @@ impl std::convert::From for crate::Envelope { } if let Some(ref mut to) = t.to { env.set_to( - std::mem::replace(to, SmallVec::new()) + std::mem::take(to) .into_iter() .map(|addr| addr.into()) .collect::>(), @@ -315,7 +315,7 @@ impl std::convert::From for crate::Envelope { if let Some(ref mut cc) = t.cc { env.set_cc( - std::mem::replace(cc, SmallVec::new()) + std::mem::take(cc) .into_iter() .map(|addr| addr.into()) .collect::>(), @@ -324,17 +324,15 @@ impl std::convert::From for crate::Envelope { if let Some(ref mut bcc) = t.bcc { env.set_bcc( - std::mem::replace(bcc, Vec::new()) + std::mem::take(bcc) .into_iter() .map(|addr| addr.into()) .collect::>(), ); } - if let Some(ref r) = env.references { - if let Some(pos) = r.refs.iter().position(|r| r == env.message_id()) { - env.references.as_mut().unwrap().refs.remove(pos); - } + if let (Some(ref mut r), message_id) = (&mut env.references, &env.message_id) { + r.refs.retain(|r| r != message_id); } env @@ -413,14 +411,13 @@ impl Method for EmailQuery { } impl EmailQuery { - pub const RESULT_FIELD_IDS: ResultField = - ResultField:: { - field: "/ids", - _ph: PhantomData, - }; + pub const RESULT_FIELD_IDS: ResultField = ResultField:: { + field: "/ids", + _ph: PhantomData, + }; pub fn new(query_call: Query, EmailObject>) -> Self { - EmailQuery { + Self { query_call, collapse_threads: false, } @@ -454,7 +451,7 @@ impl Method for EmailGet { impl EmailGet { pub fn new(get_call: Get) -> Self { - EmailGet { + Self { get_call, body_properties: Vec::new(), fetch_text_body_values: false, @@ -548,8 +545,8 @@ impl EmailFilterCondition { impl FilterTrait for EmailFilterCondition {} impl From for FilterCondition { - fn from(val: EmailFilterCondition) -> FilterCondition { - FilterCondition { + fn from(val: EmailFilterCondition) -> Self { + Self { cond: val, _ph: PhantomData, } @@ -586,7 +583,7 @@ pub enum MessageProperty { impl From for Filter { fn from(val: crate::search::Query) -> Self { - let mut ret = Filter::Condition(EmailFilterCondition::new().into()); + let mut ret = Self::Condition(EmailFilterCondition::new().into()); fn rec(q: &crate::search::Query, f: &mut Filter) { use datetime::{formats::RFC3339_DATE, timestamp_to_string}; @@ -813,7 +810,7 @@ impl Method for EmailSet { impl EmailSet { pub fn new(set_call: Set) -> Self { - EmailSet { set_call } + Self { set_call } } } @@ -830,7 +827,7 @@ impl Method for EmailChanges { impl EmailChanges { pub fn new(changes_call: Changes) -> Self { - EmailChanges { changes_call } + Self { changes_call } } } @@ -849,7 +846,7 @@ impl EmailQueryChanges { pub fn new( query_changes_call: QueryChanges, EmailObject>, ) -> Self { - EmailQueryChanges { query_changes_call } + Self { query_changes_call } } } @@ -864,17 +861,16 @@ pub struct EmailQueryChangesResponse { impl std::convert::TryFrom<&RawValue> for EmailQueryChangesResponse { type Error = crate::error::Error; - fn try_from(t: &RawValue) -> Result { - let res: (String, EmailQueryChangesResponse, String) = serde_json::from_str(t.get()) - .map_err(|err| { - crate::error::Error::new(format!( - "BUG: Could not deserialize server JSON response properly, please report \ - this!\nReply from server: {}", - &t - )) - .set_source(Some(Arc::new(err))) - .set_kind(ErrorKind::Bug) - })?; + fn try_from(t: &RawValue) -> Result { + let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug) + })?; assert_eq!(&res.0, "Email/queryChanges"); Ok(res.1) } diff --git a/melib/src/backends/jmap/objects/email/import.rs b/melib/src/backends/jmap/objects/email/import.rs index 475b9d3f..6bdb8f8c 100644 --- a/melib/src/backends/jmap/objects/email/import.rs +++ b/melib/src/backends/jmap/objects/email/import.rs @@ -90,6 +90,12 @@ impl ImportCall { _impl!(emails: HashMap, EmailImport>); } +impl Default for ImportCall { + fn default() -> Self { + Self::new() + } +} + impl Method for ImportCall { const NAME: &'static str = "Email/import"; } @@ -110,6 +116,12 @@ impl EmailImport { _impl!(received_at: Option); } +impl Default for EmailImport { + fn default() -> Self { + Self::new() + } +} + #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] #[serde(tag = "type")] @@ -184,17 +196,16 @@ pub struct ImportResponse { impl std::convert::TryFrom<&RawValue> for ImportResponse { type Error = crate::error::Error; - fn try_from(t: &RawValue) -> Result { - let res: (String, ImportResponse, String) = - serde_json::from_str(t.get()).map_err(|err| { - crate::error::Error::new(format!( - "BUG: Could not deserialize server JSON response properly, please report \ - this!\nReply from server: {}", - &t - )) - .set_source(Some(Arc::new(err))) - .set_kind(ErrorKind::Bug) - })?; + fn try_from(t: &RawValue) -> Result { + let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug) + })?; assert_eq!(&res.0, &ImportCall::NAME); Ok(res.1) } diff --git a/melib/src/backends/jmap/objects/mailbox.rs b/melib/src/backends/jmap/objects/mailbox.rs index 2a38e94c..118143ed 100644 --- a/melib/src/backends/jmap/objects/mailbox.rs +++ b/melib/src/backends/jmap/objects/mailbox.rs @@ -68,7 +68,7 @@ pub struct MailboxGet { } impl MailboxGet { pub fn new(get_call: Get) -> Self { - MailboxGet { get_call } + Self { get_call } } } diff --git a/melib/src/backends/jmap/operations.rs b/melib/src/backends/jmap/operations.rs index b0fb0f32..17245a83 100644 --- a/melib/src/backends/jmap/operations.rs +++ b/melib/src/backends/jmap/operations.rs @@ -37,7 +37,7 @@ impl JmapOp { connection: Arc>, store: Arc, ) -> Self { - JmapOp { + Self { hash, connection, store, diff --git a/melib/src/backends/jmap/protocol.rs b/melib/src/backends/jmap/protocol.rs index e8c27096..b3a954e4 100644 --- a/melib/src/backends/jmap/protocol.rs +++ b/melib/src/backends/jmap/protocol.rs @@ -63,7 +63,7 @@ pub struct Request { impl Request { pub fn new(request_no: Arc>) -> Self { - Request { + Self { using: USING, method_calls: Vec::new(), request_no, @@ -177,7 +177,7 @@ pub async fn get_mailboxes(conn: &JmapConnection) -> Result>() { - if let Some(parent_hash) = ret[&key].parent_hash.clone() { + if let Some(parent_hash) = ret[&key].parent_hash { ret.entry(parent_hash).and_modify(|e| e.children.push(key)); } } @@ -190,7 +190,7 @@ pub async fn get_message_list( ) -> Result>> { let email_call: EmailQuery = EmailQuery::new( Query::new() - .account_id(conn.mail_account_id().clone()) + .account_id(conn.mail_account_id()) .filter(Some(Filter::Condition( EmailFilterCondition::new() .in_mailbox(Some(mailbox.id.clone())) @@ -264,7 +264,7 @@ pub async fn fetch( let mailbox_id = store.mailboxes.read().unwrap()[&mailbox_hash].id.clone(); let email_query_call: EmailQuery = EmailQuery::new( Query::new() - .account_id(conn.mail_account_id().clone()) + .account_id(conn.mail_account_id()) .filter(Some(Filter::Condition( EmailFilterCondition::new() .in_mailbox(Some(mailbox_id)) @@ -283,7 +283,7 @@ pub async fn fetch( prev_seq, EmailQuery::RESULT_FIELD_IDS, ))) - .account_id(conn.mail_account_id().clone()), + .account_id(conn.mail_account_id()), ); req.add_call(&email_call); diff --git a/melib/src/backends/jmap/rfc8620.rs b/melib/src/backends/jmap/rfc8620.rs index fb55c5f2..cf1af11a 100644 --- a/melib/src/backends/jmap/rfc8620.rs +++ b/melib/src/backends/jmap/rfc8620.rs @@ -72,7 +72,7 @@ impl core::fmt::Debug for Id { //, Hash, Eq, PartialEq, Default)] impl Clone for Id { fn clone(&self) -> Self { - Id { + Self { inner: self.inner.clone(), _ph: PhantomData, } @@ -101,7 +101,7 @@ impl Default for Id { impl From for Id { fn from(inner: String) -> Self { - Id { + Self { inner, _ph: PhantomData, } @@ -146,7 +146,7 @@ pub struct State { //, Hash, Eq, PartialEq, Default)] impl Clone for State { fn clone(&self) -> Self { - State { + Self { inner: self.inner.clone(), _ph: PhantomData, } @@ -175,7 +175,7 @@ impl Default for State { impl From for State { fn from(inner: String) -> Self { - State { + Self { inner, _ph: PhantomData, } @@ -284,9 +284,9 @@ impl Object for BlobObject { /// The id of the account to use. #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct Get +pub struct Get where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub account_id: Id, #[serde(skip_serializing_if = "Option::is_none")] @@ -298,9 +298,9 @@ where _ph: PhantomData OBJ>, } -impl Get +impl Get where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub fn new() -> Self { Self { @@ -339,6 +339,15 @@ where ); } +impl Default for Get +where + OBJ: Object + std::fmt::Debug + Serialize, +{ + fn default() -> Self { + Self::new() + } +} + impl Serialize for Get { fn serialize(&self, serializer: S) -> Result where @@ -417,17 +426,16 @@ pub struct GetResponse { impl std::convert::TryFrom<&RawValue> for GetResponse { type Error = crate::error::Error; - fn try_from(t: &RawValue) -> Result, crate::error::Error> { - let res: (String, GetResponse, String) = - serde_json::from_str(t.get()).map_err(|err| { - crate::error::Error::new(format!( - "BUG: Could not deserialize server JSON response properly, please report \ - this!\nReply from server: {}", - &t - )) - .set_source(Some(Arc::new(err))) - .set_kind(crate::error::ErrorKind::Bug) - })?; + fn try_from(t: &RawValue) -> Result { + let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/get", OBJ::NAME)); Ok(res.1) } @@ -450,9 +458,9 @@ enum JmapError { #[derive(Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct Query, OBJ: Object> +pub struct Query, OBJ> where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub account_id: Id, pub filter: Option, @@ -472,9 +480,9 @@ where _ph: PhantomData OBJ>, } -impl, OBJ: Object> Query +impl, OBJ> Query where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub fn new() -> Self { Self { @@ -500,6 +508,15 @@ where _impl!(calculate_total: bool); } +impl, OBJ> Default for Query +where + OBJ: Object + std::fmt::Debug + Serialize, +{ + fn default() -> Self { + Self::new() + } +} + pub fn u64_zero(num: &u64) -> bool { *num == 0 } @@ -530,17 +547,16 @@ pub struct QueryResponse { impl std::convert::TryFrom<&RawValue> for QueryResponse { type Error = crate::error::Error; - fn try_from(t: &RawValue) -> Result, crate::error::Error> { - let res: (String, QueryResponse, String) = - serde_json::from_str(t.get()).map_err(|err| { - crate::error::Error::new(format!( - "BUG: Could not deserialize server JSON response properly, please report \ - this!\nReply from server: {}", - &t - )) - .set_source(Some(Arc::new(err))) - .set_kind(crate::error::ErrorKind::Bug) - })?; + fn try_from(t: &RawValue) -> Result { + let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/query", OBJ::NAME)); Ok(res.1) } @@ -557,7 +573,7 @@ pub struct ResultField, OBJ: Object> { impl, OBJ: Object> ResultField { pub fn new(field: &'static str) -> Self { - ResultField { + Self { field, _ph: PhantomData, } @@ -604,9 +620,9 @@ impl, OBJ: Object> ResultField { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] /* ch-ch-ch-ch-ch-Changes */ -pub struct Changes +pub struct Changes where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub account_id: Id, pub since_state: State, @@ -616,9 +632,9 @@ where _ph: PhantomData OBJ>, } -impl Changes +impl Changes where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub fn new() -> Self { Self { @@ -654,6 +670,15 @@ where ); } +impl Default for Changes +where + OBJ: Object + std::fmt::Debug + Serialize, +{ + fn default() -> Self { + Self::new() + } +} + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct ChangesResponse { @@ -670,17 +695,16 @@ pub struct ChangesResponse { impl std::convert::TryFrom<&RawValue> for ChangesResponse { type Error = crate::error::Error; - fn try_from(t: &RawValue) -> Result, crate::error::Error> { - let res: (String, ChangesResponse, String) = - serde_json::from_str(t.get()).map_err(|err| { - crate::error::Error::new(format!( - "BUG: Could not deserialize server JSON response properly, please report \ - this!\nReply from server: {}", - &t - )) - .set_source(Some(Arc::new(err))) - .set_kind(crate::error::ErrorKind::Bug) - })?; + fn try_from(t: &RawValue) -> Result { + let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/changes", OBJ::NAME)); Ok(res.1) } @@ -706,9 +730,9 @@ impl ChangesResponse { ///record type). #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct Set +pub struct Set where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { ///o accountId: "Id" /// @@ -785,9 +809,9 @@ where pub destroy: Option>>, } -impl Set +impl Set where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub fn new() -> Self { Self { @@ -813,6 +837,15 @@ where _impl!(update: Option, Value>>); } +impl Default for Set +where + OBJ: Object + std::fmt::Debug + Serialize, +{ + fn default() -> Self { + Self::new() + } +} + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct SetResponse { @@ -876,17 +909,16 @@ pub struct SetResponse { impl std::convert::TryFrom<&RawValue> for SetResponse { type Error = crate::error::Error; - fn try_from(t: &RawValue) -> Result, crate::error::Error> { - let res: (String, SetResponse, String) = - serde_json::from_str(t.get()).map_err(|err| { - crate::error::Error::new(format!( - "BUG: Could not deserialize server JSON response properly, please report \ - this!\nReply from server: {}", - &t - )) - .set_source(Some(Arc::new(err))) - .set_kind(crate::error::ErrorKind::Bug) - })?; + fn try_from(t: &RawValue) -> Result { + let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/set", OBJ::NAME)); Ok(res.1) } @@ -1002,7 +1034,7 @@ pub fn download_request_format( ret.push_str(blob_id.as_str()); prev_pos += "{blobId}".len(); } else if download_url[prev_pos..].starts_with("{name}") { - ret.push_str(name.as_ref().map(String::as_str).unwrap_or("")); + ret.push_str(name.as_deref().unwrap_or("")); prev_pos += "{name}".len(); } } @@ -1070,9 +1102,9 @@ pub struct UploadResponse { /// takes the following arguments: #[derive(Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct QueryChanges, OBJ: Object> +pub struct QueryChanges, OBJ> where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub account_id: Id, pub filter: Option, @@ -1114,9 +1146,9 @@ where _ph: PhantomData OBJ>, } -impl, OBJ: Object> QueryChanges +impl, OBJ> QueryChanges where - OBJ: std::fmt::Debug + Serialize, + OBJ: Object + std::fmt::Debug + Serialize, { pub fn new(account_id: Id, since_query_state: String) -> Self { Self { diff --git a/melib/src/backends/jmap/rfc8620/argument.rs b/melib/src/backends/jmap/rfc8620/argument.rs index 932579b9..6bf794b7 100644 --- a/melib/src/backends/jmap/rfc8620/argument.rs +++ b/melib/src/backends/jmap/rfc8620/argument.rs @@ -37,7 +37,7 @@ pub enum JmapArgument { impl JmapArgument { pub fn value(v: T) -> Self { - JmapArgument::Value(v) + Self::Value(v) } pub fn reference(result_of: usize, path: ResultField) -> Self @@ -45,7 +45,7 @@ impl JmapArgument { M: Method, OBJ: Object, { - JmapArgument::ResultReference { + Self::ResultReference { result_of: format!("m{}", result_of), name: M::NAME.to_string(), path: path.field.to_string(), diff --git a/melib/src/backends/jmap/rfc8620/comparator.rs b/melib/src/backends/jmap/rfc8620/comparator.rs index f5170f3d..2d6f5eff 100644 --- a/melib/src/backends/jmap/rfc8620/comparator.rs +++ b/melib/src/backends/jmap/rfc8620/comparator.rs @@ -51,3 +51,9 @@ impl Comparator { _impl!(collation: Option); _impl!(additional_properties: Vec); } + +impl Default for Comparator { + fn default() -> Self { + Self::new() + } +} diff --git a/melib/src/backends/jmap/rfc8620/filters.rs b/melib/src/backends/jmap/rfc8620/filters.rs index 7d393b24..04b9e536 100644 --- a/melib/src/backends/jmap/rfc8620/filters.rs +++ b/melib/src/backends/jmap/rfc8620/filters.rs @@ -44,7 +44,7 @@ pub struct FilterCondition, OBJ: Object> { pub _ph: PhantomData OBJ>, } -#[derive(Serialize, Debug, PartialEq)] +#[derive(Serialize, Debug, Eq, PartialEq)] #[serde(rename_all = "UPPERCASE")] pub enum FilterOperator { And, @@ -54,7 +54,7 @@ pub enum FilterOperator { impl, OBJ: Object> FilterCondition { pub fn new() -> Self { - FilterCondition { + Self { cond: F::default(), _ph: PhantomData, } @@ -69,7 +69,7 @@ impl, OBJ: Object> Default for FilterCondition { impl, OBJ: Object> Default for Filter { fn default() -> Self { - Filter::Condition(FilterCondition::default()) + Self::Condition(FilterCondition::default()) } } @@ -78,17 +78,17 @@ use std::ops::{BitAndAssign, BitOrAssign, Not}; impl, OBJ: Object> BitAndAssign for Filter { fn bitand_assign(&mut self, rhs: Self) { match self { - Filter::Operator { + Self::Operator { operator: FilterOperator::And, ref mut conditions, } => { conditions.push(rhs); } - Filter::Condition(_) | Filter::Operator { .. } => { - *self = Filter::Operator { + Self::Condition(_) | Self::Operator { .. } => { + *self = Self::Operator { operator: FilterOperator::And, conditions: vec![ - std::mem::replace(self, Filter::Condition(FilterCondition::new())), + std::mem::replace(self, Self::Condition(FilterCondition::new())), rhs, ], }; @@ -100,17 +100,17 @@ impl, OBJ: Object> BitAndAssign for Filter { impl, OBJ: Object> BitOrAssign for Filter { fn bitor_assign(&mut self, rhs: Self) { match self { - Filter::Operator { + Self::Operator { operator: FilterOperator::Or, ref mut conditions, } => { conditions.push(rhs); } - Filter::Condition(_) | Filter::Operator { .. } => { - *self = Filter::Operator { + Self::Condition(_) | Self::Operator { .. } => { + *self = Self::Operator { operator: FilterOperator::Or, conditions: vec![ - std::mem::replace(self, Filter::Condition(FilterCondition::new())), + std::mem::replace(self, Self::Condition(FilterCondition::new())), rhs, ], }; @@ -123,14 +123,14 @@ impl, OBJ: Object> Not for Filter { type Output = Self; fn not(self) -> Self { match self { - Filter::Operator { + Self::Operator { operator, conditions, - } if operator == FilterOperator::Not => Filter::Operator { + } if operator == FilterOperator::Not => Self::Operator { operator: FilterOperator::Or, conditions, }, - Filter::Condition(_) | Filter::Operator { .. } => Filter::Operator { + Self::Condition(_) | Self::Operator { .. } => Self::Operator { operator: FilterOperator::Not, conditions: vec![self], }, diff --git a/melib/src/backends/maildir.rs b/melib/src/backends/maildir.rs index 6a2202f4..28b0b9c0 100644 --- a/melib/src/backends/maildir.rs +++ b/melib/src/backends/maildir.rs @@ -54,7 +54,7 @@ pub struct MaildirOp { impl Clone for MaildirOp { fn clone(&self) -> Self { - MaildirOp { + Self { hash_index: self.hash_index.clone(), mailbox_hash: self.mailbox_hash, hash: self.hash, @@ -65,7 +65,7 @@ impl Clone for MaildirOp { impl MaildirOp { pub fn new(hash: EnvelopeHash, hash_index: HashIndexes, mailbox_hash: MailboxHash) -> Self { - MaildirOp { + Self { hash_index, mailbox_hash, hash, @@ -95,7 +95,7 @@ impl MaildirOp { } } -impl<'a> BackendOp for MaildirOp { +impl BackendOp for MaildirOp { fn as_bytes(&mut self) -> ResultFuture> { if self.slice.is_none() { let file = std::fs::OpenOptions::new() @@ -163,7 +163,7 @@ impl MaildirMailbox { true }; - let ret = MaildirMailbox { + let ret = Self { hash: MailboxHash(h.finish()), name: file_name, path: fname.unwrap().to_path_buf(), diff --git a/melib/src/backends/maildir/backend.rs b/melib/src/backends/maildir/backend.rs index 0dad802b..da495b7c 100644 --- a/melib/src/backends/maildir/backend.rs +++ b/melib/src/backends/maildir/backend.rs @@ -82,8 +82,8 @@ impl DerefMut for MaildirPath { } impl From for MaildirPath { - fn from(val: PathBuf) -> MaildirPath { - MaildirPath { + fn from(val: PathBuf) -> Self { + Self { buf: val, modified: None, removed: false, @@ -800,7 +800,7 @@ impl MailBackend for MaildirType { ) -> ResultFuture<()> { let path = self.mailboxes[&mailbox_hash].fs_path.clone(); Ok(Box::pin(async move { - MaildirType::save_to_mailbox(path, bytes, flags) + Self::save_to_mailbox(path, bytes, flags) })) } @@ -1073,6 +1073,7 @@ impl MailBackend for MaildirType { } impl MaildirType { + #[allow(clippy::new_ret_no_self)] pub fn new( settings: &AccountSettings, is_subscribed: Box bool>, @@ -1219,7 +1220,7 @@ impl MaildirType { }, ); } - Ok(Box::new(MaildirType { + Ok(Box::new(Self { name: settings.name.to_string(), mailboxes, hash_indexes: Arc::new(Mutex::new(hash_indexes)), @@ -1346,17 +1347,12 @@ fn add_path_to_index( ) -> Result { debug!("add_path_to_index path {:?} filename{:?}", path, file_name); let env_hash = get_file_hash(path); - { - let mut map = hash_index.lock().unwrap(); - let map = map.entry(mailbox_hash).or_default(); - map.insert(env_hash, path.to_path_buf().into()); - debug!( - "inserted {} in {} map, len={}", - env_hash, - mailbox_hash, - map.len() - ); - } + hash_index + .lock() + .unwrap() + .entry(mailbox_hash) + .or_default() + .insert(env_hash, path.to_path_buf().into()); let mut reader = io::BufReader::new(fs::File::open(path)?); buf.clear(); reader.read_to_end(buf)?; diff --git a/melib/src/backends/maildir/stream.rs b/melib/src/backends/maildir/stream.rs index 34108ed4..fd797299 100644 --- a/melib/src/backends/maildir/stream.rs +++ b/melib/src/backends/maildir/stream.rs @@ -34,15 +34,14 @@ use futures::{ use super::*; use crate::backends::maildir::backend::move_to_cur; +type Payload = Pin>> + Send + 'static>>; + pub struct MaildirStream { - payloads: Pin< - Box< - FuturesUnordered>> + Send + 'static>>>, - >, - >, + payloads: Pin>>, } impl MaildirStream { + #[allow(clippy::type_complexity, clippy::new_ret_no_self)] pub fn new( mailbox_hash: MailboxHash, unseen: Arc>, @@ -97,9 +96,11 @@ impl MaildirStream { for file in chunk { let env_hash = get_file_hash(&file); { - let mut map = map.lock().unwrap(); - let map = map.entry(mailbox_hash).or_default(); - map.insert(env_hash, PathBuf::from(&file).into()); + map.lock() + .unwrap() + .entry(mailbox_hash) + .or_default() + .insert(env_hash, PathBuf::from(&file).into()); } let mut reader = io::BufReader::new(fs::File::open(&file)?); buf.clear(); diff --git a/melib/src/backends/mbox.rs b/melib/src/backends/mbox.rs index 5fb25eab..5ee7d890 100644 --- a/melib/src/backends/mbox.rs +++ b/melib/src/backends/mbox.rs @@ -233,7 +233,7 @@ impl BackendMailbox for MboxMailbox { } fn clone(&self) -> Mailbox { - Box::new(MboxMailbox { + Box::new(Self { hash: self.hash, name: self.name.clone(), path: self.path.clone(), @@ -294,7 +294,7 @@ pub struct MboxOp { impl MboxOp { pub fn new(_hash: EnvelopeHash, path: &Path, offset: Offset, length: Length) -> Self { - MboxOp { + Self { _hash, path: path.to_path_buf(), slice: std::cell::RefCell::new(None), @@ -933,9 +933,10 @@ impl MailBackend for MboxType { if payload.is_empty() { Ok(None) } else { - let mut mailbox_lock = self.mailboxes.lock().unwrap(); - let contents = std::mem::replace(&mut self.contents, vec![]); - mailbox_lock + let contents = std::mem::take(&mut self.contents); + self.mailboxes + .lock() + .unwrap() .entry(self.mailbox_hash) .and_modify(|f| f.content = contents); Ok(Some(payload)) @@ -990,12 +991,15 @@ impl MailBackend for MboxType { let mut watcher = watcher(tx, std::time::Duration::from_secs(10)) .map_err(|e| e.to_string()) .map_err(Error::new)?; - for f in self.mailboxes.lock().unwrap().values() { - watcher - .watch(&f.fs_path, RecursiveMode::Recursive) - .map_err(|e| e.to_string()) - .map_err(Error::new)?; - debug!("watching {:?}", f.fs_path.as_path()); + { + let mailboxes_lck = self.mailboxes.lock().unwrap(); + for f in mailboxes_lck.values() { + watcher + .watch(&f.fs_path, RecursiveMode::Recursive) + .map_err(|e| e.to_string()) + .map_err(Error::new)?; + log::debug!("watching {:?}", f.fs_path.as_path()); + } } let account_hash = AccountHash::from_bytes(self.account_name.as_bytes()); let mailboxes = self.mailboxes.clone(); @@ -1114,7 +1118,8 @@ impl MailBackend for MboxType { } /* Trigger rescan of mailboxes */ DebouncedEvent::Rescan => { - for &mailbox_hash in mailboxes.lock().unwrap().keys() { + let mailboxes_lck = mailboxes.lock().unwrap(); + for &mailbox_hash in mailboxes_lck.keys() { (sender)( account_hash, BackendEvent::Refresh(RefreshEvent { @@ -1305,6 +1310,7 @@ macro_rules! get_conf_val { } impl MboxType { + #[allow(clippy::new_ret_no_self)] pub fn new( s: &AccountSettings, _is_subscribed: Box bool>, @@ -1319,7 +1325,7 @@ impl MboxType { ))); } let prefer_mbox_type: String = get_conf_val!(s["prefer_mbox_type"], "auto".to_string())?; - let ret = MboxType { + let ret = Self { account_name: s.name.to_string(), event_consumer, path, diff --git a/melib/src/backends/mbox/write.rs b/melib/src/backends/mbox/write.rs index 47fd8df9..f4e79c00 100644 --- a/melib/src/backends/mbox/write.rs +++ b/melib/src/backends/mbox/write.rs @@ -23,6 +23,7 @@ use super::*; use crate::utils::datetime; impl MboxFormat { + #[allow(clippy::too_many_arguments)] pub fn append( &self, writer: &mut dyn std::io::Write, @@ -153,8 +154,8 @@ impl MboxFormat { }; match self { - MboxFormat::MboxO | MboxFormat::MboxRd => Err(Error::new("Unimplemented.")), - MboxFormat::MboxCl => { + Self::MboxO | Self::MboxRd => Err(Error::new("Unimplemented.")), + Self::MboxCl => { let len = (body_len + body .windows(b"\nFrom ".len()) @@ -216,7 +217,7 @@ impl MboxFormat { } Ok(()) } - MboxFormat::MboxCl2 => { + Self::MboxCl2 => { let len = body_len.to_string(); for (h, v) in headers .into_iter() diff --git a/melib/src/backends/nntp.rs b/melib/src/backends/nntp.rs index 197a388e..30a43a32 100644 --- a/melib/src/backends/nntp.rs +++ b/melib/src/backends/nntp.rs @@ -119,7 +119,7 @@ type Capabilities = HashSet; #[derive(Debug)] pub struct UIDStore { account_hash: AccountHash, - account_name: Arc, + account_name: Arc, capabilities: Arc>, message_id_index: Arc>>, hash_index: Arc>>, @@ -134,10 +134,10 @@ pub struct UIDStore { impl UIDStore { fn new( account_hash: AccountHash, - account_name: Arc, + account_name: Arc, event_consumer: BackendEventConsumer, ) -> Self { - UIDStore { + Self { account_hash, account_name, event_consumer, @@ -356,7 +356,7 @@ impl MailBackend for NntpType { let uid_store = self.uid_store.clone(); let connection = self.connection.clone(); Ok(Box::pin(async move { - NntpType::nntp_mailboxes(&connection).await?; + Self::nntp_mailboxes(&connection).await?; let mailboxes_lck = uid_store.mailboxes.lock().await; let ret = mailboxes_lck .iter() @@ -552,6 +552,7 @@ impl MailBackend for NntpType { } impl NntpType { + #[allow(clippy::new_ret_no_self)] pub fn new( s: &AccountSettings, is_subscribed: Box bool + Send + Sync>, @@ -610,7 +611,7 @@ impl NntpType { }, }; let account_hash = AccountHash::from_bytes(s.name.as_bytes()); - let account_name = Arc::new(s.name.to_string()); + let account_name = s.name.to_string().into(); let mut mailboxes = HashMap::default(); for (k, _f) in s.mailboxes.iter() { let mailbox_hash = MailboxHash(get_path_hash!(&k)); @@ -639,7 +640,7 @@ impl NntpType { }); let connection = NntpConnection::new_connection(&server_conf, uid_store.clone()); - Ok(Box::new(NntpType { + Ok(Box::new(Self { server_conf, _is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)), _can_create_flags: Arc::new(Mutex::new(false)), @@ -791,7 +792,7 @@ struct FetchState { impl FetchState { async fn fetch_envs(&mut self) -> Result>> { - let FetchState { + let Self { mailbox_hash, ref connection, ref uid_store, diff --git a/melib/src/backends/nntp/connection.rs b/melib/src/backends/nntp/connection.rs index f9dd2a79..f82f81dd 100644 --- a/melib/src/backends/nntp/connection.rs +++ b/melib/src/backends/nntp/connection.rs @@ -35,21 +35,12 @@ pub use smol::Async as AsyncWrapper; use super::{Capabilities, NntpServerConf, UIDStore}; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Default, Clone, Copy)] pub struct NntpExtensionUse { #[cfg(feature = "deflate_compression")] pub deflate: bool, } -impl Default for NntpExtensionUse { - fn default() -> Self { - Self { - #[cfg(feature = "deflate_compression")] - deflate: false, - } - } -} - #[derive(Debug)] pub struct NntpStream { pub stream: AsyncWrapper, @@ -66,7 +57,7 @@ pub enum MailboxSelection { impl MailboxSelection { pub fn take(&mut self) -> Self { - std::mem::replace(self, MailboxSelection::None) + std::mem::replace(self, Self::None) } } @@ -82,9 +73,7 @@ pub struct NntpConnection { } impl NntpStream { - pub async fn new_connection( - server_conf: &NntpServerConf, - ) -> Result<(Capabilities, NntpStream)> { + pub async fn new_connection(server_conf: &NntpServerConf) -> Result<(Capabilities, Self)> { use std::net::TcpStream; let path = &server_conf.server_hostname; @@ -96,7 +85,7 @@ impl NntpStream { )?))? }; let mut res = String::with_capacity(8 * 1024); - let mut ret = NntpStream { + let mut ret = Self { stream, extension_use: server_conf.extension_use, current_mailbox: MailboxSelection::None, @@ -273,7 +262,7 @@ impl NntpStream { server_conf.server_hostname, res ) })?; - let NntpStream { + let Self { stream, extension_use, current_mailbox, @@ -282,7 +271,7 @@ impl NntpStream { let stream = stream.into_inner()?; return Ok(( capabilities, - NntpStream { + Self { stream: AsyncWrapper::new(stream.deflate())?, extension_use, current_mailbox, @@ -421,11 +410,8 @@ impl NntpStream { } impl NntpConnection { - pub fn new_connection( - server_conf: &NntpServerConf, - uid_store: Arc, - ) -> NntpConnection { - NntpConnection { + pub fn new_connection(server_conf: &NntpServerConf, uid_store: Arc) -> Self { + Self { stream: Err(Error::new("Offline".to_string())), server_conf: server_conf.clone(), uid_store, diff --git a/melib/src/backends/nntp/operations.rs b/melib/src/backends/nntp/operations.rs index 6ea5e6b5..a4ca29eb 100644 --- a/melib/src/backends/nntp/operations.rs +++ b/melib/src/backends/nntp/operations.rs @@ -40,7 +40,7 @@ impl NntpOp { connection: Arc>, uid_store: Arc, ) -> Self { - NntpOp { + Self { uid, connection, mailbox_hash, diff --git a/melib/src/backends/notmuch.rs b/melib/src/backends/notmuch.rs index 9a63f207..79fea253 100644 --- a/melib/src/backends/notmuch.rs +++ b/melib/src/backends/notmuch.rs @@ -88,6 +88,7 @@ impl DbConnection { } } + #[allow(clippy::too_many_arguments)] // Don't judge me clippy. fn refresh( &mut self, mailboxes: Arc>>, @@ -115,9 +116,7 @@ impl DbConnection { let mut tag_lock = tag_index.write().unwrap(); for tag in tags.1.iter() { let num = TagHash::from_bytes(tag.as_bytes()); - if !tag_lock.contains_key(&num) { - tag_lock.insert(num, tag.clone()); - } + tag_lock.entry(num).or_insert_with(|| tag.clone()); } for &mailbox_hash in mailbox_hashes { (event_consumer)( @@ -224,7 +223,7 @@ pub struct NotmuchDb { mailbox_index: Arc>>>, collection: Collection, path: PathBuf, - _account_name: Arc, + _account_name: Arc, account_hash: AccountHash, event_consumer: BackendEventConsumer, save_messages_to: Option, @@ -302,6 +301,7 @@ unsafe impl Send for NotmuchMailbox {} unsafe impl Sync for NotmuchMailbox {} impl NotmuchDb { + #[allow(clippy::new_ret_no_self)] pub fn new( s: &AccountSettings, _is_subscribed: Box bool>, @@ -422,7 +422,7 @@ impl NotmuchDb { } let account_hash = AccountHash::from_bytes(s.name.as_bytes()); - Ok(Box::new(NotmuchDb { + Ok(Box::new(Self { lib, revision_uuid: Arc::new(RwLock::new(0)), path, @@ -432,7 +432,7 @@ impl NotmuchDb { mailboxes: Arc::new(RwLock::new(mailboxes)), save_messages_to: None, - _account_name: Arc::new(s.name.to_string()), + _account_name: s.name.to_string().into(), account_hash, event_consumer, })) @@ -538,7 +538,7 @@ impl NotmuchDb { } else { notmuch_database_mode_t_NOTMUCH_DATABASE_MODE_READ_ONLY }, - &mut database as *mut _, + std::ptr::addr_of_mut!(database), ) }; if status != 0 { @@ -635,7 +635,7 @@ impl MailBackend for NotmuchDb { } } } - let database = Arc::new(NotmuchDb::new_connection( + let database = Arc::new(Self::new_connection( self.path.as_path(), self.revision_uuid.clone(), self.lib.clone(), @@ -659,7 +659,6 @@ impl MailBackend for NotmuchDb { let mut index_lck = index.write().unwrap(); v = query .search()? - .into_iter() .map(|m| { index_lck.insert(m.env_hash(), m.msg_id_cstr().into()); m.msg_id_cstr().into() @@ -685,7 +684,7 @@ impl MailBackend for NotmuchDb { fn refresh(&mut self, _mailbox_hash: MailboxHash) -> ResultFuture<()> { let account_hash = self.account_hash; - let mut database = NotmuchDb::new_connection( + let mut database = Self::new_connection( self.path.as_path(), self.revision_uuid.clone(), self.lib.clone(), @@ -737,7 +736,7 @@ impl MailBackend for NotmuchDb { loop { let _ = rx.recv().map_err(|err| err.to_string())?; { - let mut database = NotmuchDb::new_connection( + let mut database = Self::new_connection( path.as_path(), revision_uuid.clone(), lib.clone(), @@ -942,7 +941,7 @@ impl MailBackend for NotmuchDb { melib_query: crate::search::Query, mailbox_hash: Option, ) -> ResultFuture> { - let database = NotmuchDb::new_connection( + let database = Self::new_connection( self.path.as_path(), self.revision_uuid.clone(), self.lib.clone(), @@ -1098,7 +1097,10 @@ impl<'s> Query<'s> { unsafe { try_call!( self.lib, - call!(self.lib, notmuch_query_count_messages)(self.ptr, &mut count as *mut _) + call!(self.lib, notmuch_query_count_messages)( + self.ptr, + std::ptr::addr_of_mut!(count) + ) ) .map_err(|err| err.0)?; } @@ -1108,7 +1110,10 @@ impl<'s> Query<'s> { fn search(&'s self) -> Result> { let mut messages: *mut notmuch_messages_t = std::ptr::null_mut(); let status = unsafe { - call!(self.lib, notmuch_query_search_messages)(self.ptr, &mut messages as *mut _) + call!(self.lib, notmuch_query_search_messages)( + self.ptr, + std::ptr::addr_of_mut!(messages), + ) }; if status != 0 { return Err(Error::new(format!( diff --git a/melib/src/backends/notmuch/message.rs b/melib/src/backends/notmuch/message.rs index c9be3d6c..7b75ac0a 100644 --- a/melib/src/backends/notmuch/message.rs +++ b/melib/src/backends/notmuch/message.rs @@ -38,7 +38,7 @@ impl<'m> Message<'m> { call!(lib, notmuch_database_find_message)( *db.inner.read().unwrap(), msg_id.as_ptr(), - &mut message as *mut _, + std::ptr::addr_of_mut!(message), ) }; if message.is_null() { @@ -100,9 +100,7 @@ impl<'m> Message<'m> { let (flags, tags) = TagIterator::new(&self).collect_flags_and_tags(); for tag in tags { let num = TagHash::from_bytes(tag.as_bytes()); - if !tag_lock.contains_key(&num) { - tag_lock.insert(num, tag); - } + tag_lock.entry(num).or_insert(tag); env.tags_mut().push(num); } unsafe { diff --git a/melib/src/backends/notmuch/thread.rs b/melib/src/backends/notmuch/thread.rs index 97f9433a..276255f3 100644 --- a/melib/src/backends/notmuch/thread.rs +++ b/melib/src/backends/notmuch/thread.rs @@ -42,6 +42,10 @@ impl<'q> Thread<'q> { (unsafe { call!(self.lib, notmuch_thread_get_total_messages)(self.ptr) }) as usize } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn iter(&'q self) -> MessageIterator<'q> { let ptr = unsafe { call!(self.lib, notmuch_thread_get_messages)(self.ptr) }; MessageIterator { diff --git a/melib/src/collection.rs b/melib/src/collection.rs index 90b716a6..3a986b30 100644 --- a/melib/src/collection.rs +++ b/melib/src/collection.rs @@ -50,7 +50,7 @@ impl Default for Collection { } impl Collection { - pub fn new() -> Collection { + pub fn new() -> Self { let message_id_index = Arc::new(RwLock::new(HashMap::with_capacity_and_hasher( 16, Default::default(), @@ -64,7 +64,7 @@ impl Collection { Default::default(), ))); - Collection { + Self { envelopes: Arc::new(RwLock::new(Default::default())), tag_index: Arc::new(RwLock::new(BTreeMap::default())), message_id_index, @@ -145,9 +145,7 @@ impl Collection { if *h == mailbox_hash { continue; } - t.update_envelope(&self.envelopes, old_hash, new_hash) - .ok() - .take(); + _ = t.update_envelope(&self.envelopes, old_hash, new_hash); } true } @@ -162,7 +160,7 @@ impl Collection { ) -> Option> { *self.sent_mailbox.write().unwrap() = sent_mailbox; - let Collection { + let Self { ref threads, ref envelopes, ref mailboxes, @@ -172,8 +170,8 @@ impl Collection { let mut threads_lck = threads.write().unwrap(); let mut mailboxes_lck = mailboxes.write().unwrap(); - if !threads_lck.contains_key(&mailbox_hash) { - threads_lck.insert(mailbox_hash, Threads::new(new_envelopes.len())); + if let std::collections::hash_map::Entry::Vacant(e) = threads_lck.entry(mailbox_hash) { + e.insert(Threads::new(new_envelopes.len())); mailboxes_lck.insert(mailbox_hash, new_envelopes.keys().cloned().collect()); for (h, e) in new_envelopes { envelopes.write().unwrap().insert(h, e); @@ -303,8 +301,7 @@ impl Collection { .unwrap_or(false) { for (_, t) in threads_lck.iter_mut() { - t.update_envelope(&self.envelopes, old_hash, new_hash) - .unwrap_or(()); + _ = t.update_envelope(&self.envelopes, old_hash, new_hash); } } { @@ -326,9 +323,7 @@ impl Collection { if *h == mailbox_hash { continue; } - t.update_envelope(&self.envelopes, old_hash, new_hash) - .ok() - .take(); + _ = t.update_envelope(&self.envelopes, old_hash, new_hash); } } @@ -342,8 +337,7 @@ impl Collection { .unwrap_or(false) { for (_, t) in threads_lck.iter_mut() { - t.update_envelope(&self.envelopes, env_hash, env_hash) - .unwrap_or(()); + _ = t.update_envelope(&self.envelopes, env_hash, env_hash); } } { @@ -365,9 +359,7 @@ impl Collection { if *h == mailbox_hash { continue; } - t.update_envelope(&self.envelopes, env_hash, env_hash) - .ok() - .take(); + _ = t.update_envelope(&self.envelopes, env_hash, env_hash); } } @@ -401,7 +393,8 @@ impl Collection { pub fn insert_reply(&self, env_hash: EnvelopeHash) { debug_assert!(self.envelopes.read().unwrap().contains_key(&env_hash)); - for (_, t) in self.threads.write().unwrap().iter_mut() { + let mut iter = self.threads.write().unwrap(); + for (_, t) in iter.iter_mut() { t.insert_reply(&self.envelopes, env_hash); } } @@ -435,8 +428,8 @@ impl Collection { pub fn new_mailbox(&self, mailbox_hash: MailboxHash) { let mut mailboxes_lck = self.mailboxes.write().unwrap(); - if !mailboxes_lck.contains_key(&mailbox_hash) { - mailboxes_lck.insert(mailbox_hash, Default::default()); + if let std::collections::hash_map::Entry::Vacant(e) = mailboxes_lck.entry(mailbox_hash) { + e.insert(Default::default()); self.threads .write() .unwrap() diff --git a/melib/src/conf.rs b/melib/src/conf.rs index df5d337a..f2999a95 100644 --- a/melib/src/conf.rs +++ b/melib/src/conf.rs @@ -97,10 +97,10 @@ impl AccountSettings { } else if let Some(pass) = self.extra.get("server_password") { Ok(pass.to_owned()) } else { - Err(Error::new(format!( + Err(Error::new( "Configuration error: connection requires either server_password or \ - server_password_command" - ))) + server_password_command", + )) } } } @@ -128,7 +128,7 @@ pub struct MailboxConf { impl Default for MailboxConf { fn default() -> Self { - MailboxConf { + Self { alias: None, autoload: false, subscribe: ToggleFlag::Unset, @@ -190,8 +190,9 @@ mod strings { named_unit_variant!(ask); } -#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[derive(Copy, Default, Debug, Clone, PartialEq, Eq)] pub enum ToggleFlag { + #[default] Unset, InternalVal(bool), False, @@ -202,37 +203,32 @@ pub enum ToggleFlag { impl From for ToggleFlag { fn from(val: bool) -> Self { if val { - ToggleFlag::True + Self::True } else { - ToggleFlag::False + Self::False } } } -impl Default for ToggleFlag { - fn default() -> Self { - ToggleFlag::Unset - } -} - impl ToggleFlag { pub fn is_unset(&self) -> bool { - ToggleFlag::Unset == *self + Self::Unset == *self } + pub fn is_internal(&self) -> bool { - matches!(self, ToggleFlag::InternalVal(_)) + matches!(self, Self::InternalVal(_)) } pub fn is_ask(&self) -> bool { - matches!(self, ToggleFlag::Ask) + matches!(self, Self::Ask) } pub fn is_false(&self) -> bool { - matches!(self, ToggleFlag::False | ToggleFlag::InternalVal(false)) + matches!(self, Self::False | Self::InternalVal(false)) } pub fn is_true(&self) -> bool { - matches!(self, ToggleFlag::True | ToggleFlag::InternalVal(true)) + matches!(self, Self::True | Self::InternalVal(true)) } } @@ -242,10 +238,10 @@ impl Serialize for ToggleFlag { S: Serializer, { match self { - ToggleFlag::Unset | ToggleFlag::InternalVal(_) => serializer.serialize_none(), - ToggleFlag::False => serializer.serialize_bool(false), - ToggleFlag::True => serializer.serialize_bool(true), - ToggleFlag::Ask => serializer.serialize_str("ask"), + Self::Unset | Self::InternalVal(_) => serializer.serialize_none(), + Self::False => serializer.serialize_bool(false), + Self::True => serializer.serialize_bool(true), + Self::Ask => serializer.serialize_str("ask"), } } } @@ -270,9 +266,9 @@ impl<'de> Deserialize<'de> for ToggleFlag { err )) })? { - InnerToggleFlag::Bool(true) => ToggleFlag::True, - InnerToggleFlag::Bool(false) => ToggleFlag::False, - InnerToggleFlag::Ask => ToggleFlag::Ask, + InnerToggleFlag::Bool(true) => Self::True, + InnerToggleFlag::Bool(false) => Self::False, + InnerToggleFlag::Ask => Self::Ask, }, ) } diff --git a/melib/src/email.rs b/melib/src/email.rs index 68d99b54..e0d28609 100644 --- a/melib/src/email.rs +++ b/melib/src/email.rs @@ -159,15 +159,15 @@ bitflags! { impl PartialEq<&str> for Flag { fn eq(&self, other: &&str) -> bool { - (other.eq_ignore_ascii_case("passed") && self.contains(Flag::PASSED)) - || (other.eq_ignore_ascii_case("replied") && self.contains(Flag::REPLIED)) - || (other.eq_ignore_ascii_case("seen") && self.contains(Flag::SEEN)) - || (other.eq_ignore_ascii_case("read") && self.contains(Flag::SEEN)) - || (other.eq_ignore_ascii_case("junk") && self.contains(Flag::TRASHED)) - || (other.eq_ignore_ascii_case("trash") && self.contains(Flag::TRASHED)) - || (other.eq_ignore_ascii_case("trashed") && self.contains(Flag::TRASHED)) - || (other.eq_ignore_ascii_case("draft") && self.contains(Flag::DRAFT)) - || (other.eq_ignore_ascii_case("flagged") && self.contains(Flag::FLAGGED)) + (other.eq_ignore_ascii_case("passed") && self.contains(Self::PASSED)) + || (other.eq_ignore_ascii_case("replied") && self.contains(Self::REPLIED)) + || (other.eq_ignore_ascii_case("seen") && self.contains(Self::SEEN)) + || (other.eq_ignore_ascii_case("read") && self.contains(Self::SEEN)) + || (other.eq_ignore_ascii_case("junk") && self.contains(Self::TRASHED)) + || (other.eq_ignore_ascii_case("trash") && self.contains(Self::TRASHED)) + || (other.eq_ignore_ascii_case("trashed") && self.contains(Self::TRASHED)) + || (other.eq_ignore_ascii_case("draft") && self.contains(Self::DRAFT)) + || (other.eq_ignore_ascii_case("flagged") && self.contains(Self::FLAGGED)) } } @@ -180,12 +180,12 @@ macro_rules! flag_impl { } impl Flag { - flag_impl!(fn is_passed, Flag::PASSED); - flag_impl!(fn is_replied, Flag::REPLIED); - flag_impl!(fn is_seen, Flag::SEEN); - flag_impl!(fn is_trashed, Flag::TRASHED); - flag_impl!(fn is_draft, Flag::DRAFT); - flag_impl!(fn is_flagged, Flag::FLAGGED); + flag_impl!(fn is_passed, Self::PASSED); + flag_impl!(fn is_replied, Self::REPLIED); + flag_impl!(fn is_seen, Self::SEEN); + flag_impl!(fn is_trashed, Self::TRASHED); + flag_impl!(fn is_draft, Self::DRAFT); + flag_impl!(fn is_flagged, Self::FLAGGED); #[cfg(feature = "imap_backend")] pub(crate) fn derive_imap_codec_flags(&self) -> Vec { @@ -239,7 +239,7 @@ impl Deref for Mail { impl Mail { pub fn new(bytes: Vec, flags: Option) -> Result { - Ok(Mail { + Ok(Self { envelope: Envelope::from_bytes(&bytes, flags)?, bytes, }) @@ -309,13 +309,13 @@ impl core::fmt::Debug for Envelope { impl Default for Envelope { fn default() -> Self { - Envelope::new(EnvelopeHash::default()) + Self::new(EnvelopeHash::default()) } } impl Envelope { pub fn new(hash: EnvelopeHash) -> Self { - Envelope { + Self { hash, date: String::new(), timestamp: 0, @@ -340,8 +340,8 @@ impl Envelope { self } - pub fn from_bytes(bytes: &[u8], flags: Option) -> Result { - let mut e = Envelope::new(EnvelopeHash::from_bytes(bytes)); + pub fn from_bytes(bytes: &[u8], flags: Option) -> Result { + let mut e = Self::new(EnvelopeHash::from_bytes(bytes)); let res = e.populate_headers(bytes).ok(); if res.is_some() { if let Some(f) = flags { @@ -855,19 +855,19 @@ impl Envelope { impl Eq for Envelope {} impl Ord for Envelope { - fn cmp(&self, other: &Envelope) -> std::cmp::Ordering { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.datetime().cmp(&other.datetime()) } } impl PartialOrd for Envelope { - fn partial_cmp(&self, other: &Envelope) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialEq for Envelope { - fn eq(&self, other: &Envelope) -> bool { + fn eq(&self, other: &Self) -> bool { self.hash == other.hash } } diff --git a/melib/src/email/address.rs b/melib/src/email/address.rs index 9e2d35fe..680882ec 100644 --- a/melib/src/email/address.rs +++ b/melib/src/email/address.rs @@ -68,7 +68,7 @@ pub struct MailboxAddress { impl Eq for MailboxAddress {} impl PartialEq for MailboxAddress { - fn eq(&self, other: &MailboxAddress) -> bool { + fn eq(&self, other: &Self) -> bool { self.address_spec.display_bytes(&self.raw) == other.address_spec.display_bytes(&other.raw) } } @@ -108,7 +108,7 @@ pub enum Address { impl Address { pub fn new(display_name: Option, address: String) -> Self { - Address::Mailbox(if let Some(d) = display_name { + Self::Mailbox(if let Some(d) = display_name { MailboxAddress { raw: format!("{} <{}>", d, address).into_bytes(), display_name: StrBuilder { @@ -135,8 +135,8 @@ impl Address { }) } - pub fn new_group(display_name: String, mailbox_list: Vec
) -> Self { - Address::Group(GroupAddress { + pub fn new_group(display_name: String, mailbox_list: Vec) -> Self { + Self::Group(GroupAddress { raw: format!( "{}:{};", display_name, @@ -157,8 +157,8 @@ impl Address { pub fn raw(&self) -> &[u8] { match self { - Address::Mailbox(m) => m.raw.as_slice(), - Address::Group(g) => g.raw.as_slice(), + Self::Mailbox(m) => m.raw.as_slice(), + Self::Group(g) => g.raw.as_slice(), } } @@ -179,8 +179,8 @@ impl Address { /// ``` pub fn get_display_name(&self) -> Option { let ret = match self { - Address::Mailbox(m) => m.display_name.display(&m.raw), - Address::Group(g) => g.display_name.display(&g.raw), + Self::Mailbox(m) => m.display_name.display(&m.raw), + Self::Group(g) => g.display_name.display(&g.raw), }; if ret.is_empty() { None @@ -193,26 +193,26 @@ impl Address { /// `String`. pub fn get_email(&self) -> String { match self { - Address::Mailbox(m) => m.address_spec.display(&m.raw), - Address::Group(_) => String::new(), + Self::Mailbox(m) => m.address_spec.display(&m.raw), + Self::Group(_) => String::new(), } } pub fn address_spec_raw(&self) -> &[u8] { match self { - Address::Mailbox(m) => m.address_spec.display_bytes(&m.raw), - Address::Group(g) => &g.raw, + Self::Mailbox(m) => m.address_spec.display_bytes(&m.raw), + Self::Group(g) => &g.raw, } } pub fn get_fqdn(&self) -> Option { match self { - Address::Mailbox(m) => { + Self::Mailbox(m) => { let raw_address = m.address_spec.display_bytes(&m.raw); let fqdn_pos = raw_address.iter().position(|&b| b == b'@')? + 1; Some(String::from_utf8_lossy(&raw_address[fqdn_pos..]).into()) } - Address::Group(_) => None, + Self::Group(_) => None, } } @@ -231,16 +231,16 @@ impl Address { .collect::<_>() } - pub fn list_try_from>(val: T) -> Result> { + pub fn list_try_from>(val: T) -> Result> { Ok(parser::address::rfc2822address_list(val.as_ref())? .1 .to_vec()) } - pub fn contains_address(&self, other: &Address) -> bool { + pub fn contains_address(&self, other: &Self) -> bool { match self { - Address::Mailbox(_) => self == other, - Address::Group(g) => g + Self::Mailbox(_) => self == other, + Self::Group(g) => g .mailbox_list .iter() .any(|addr| addr.contains_address(other)), @@ -269,7 +269,7 @@ impl Address { /// ``` pub fn subaddress(&self, separator: &str) -> Option<(Self, String)> { match self { - Address::Mailbox(_) => { + Self::Mailbox(_) => { let email = self.get_email(); let (local_part, domain) = match super::parser::address::addr_spec_raw(email.as_bytes()) @@ -292,7 +292,18 @@ impl Address { subaddress.to_string(), )) } - Address::Group(_) => None, + Self::Group(_) => None, + } + } + + /// Get the display name of this address in bytes. + /// + /// For a string, see the [`display_name`](fn@Self::get_display_name) + /// method. + pub fn display_name_bytes(&self) -> &[u8] { + match self { + Self::Mailbox(m) => m.display_name.display_bytes(&m.raw), + Self::Group(g) => g.display_name.display_bytes(&g.raw), } } } @@ -300,14 +311,12 @@ impl Address { impl Eq for Address {} impl PartialEq for Address { - fn eq(&self, other: &Address) -> bool { + fn eq(&self, other: &Self) -> bool { match (self, other) { - (Address::Mailbox(_), Address::Group(_)) | (Address::Group(_), Address::Mailbox(_)) => { - false - } - (Address::Mailbox(s), Address::Mailbox(o)) => s == o, - (Address::Group(s), Address::Group(o)) => { - s.display_name.display_bytes(&s.raw) == o.display_name.display_bytes(&o.raw) + (Self::Mailbox(_), Self::Group(_)) | (Self::Group(_), Self::Mailbox(_)) => false, + (Self::Mailbox(s), Self::Mailbox(o)) => s == o, + (Self::Group(s), Self::Group(o)) => { + self.display_name_bytes() == other.display_name_bytes() && s.mailbox_list.iter().collect::>() == o.mailbox_list.iter().collect::>() } @@ -318,10 +327,10 @@ impl PartialEq for Address { impl Hash for Address { fn hash(&self, state: &mut H) { match self { - Address::Mailbox(s) => { + Self::Mailbox(s) => { s.address_spec.display_bytes(&s.raw).hash(state); } - Address::Group(s) => { + Self::Group(s) => { s.display_name.display_bytes(&s.raw).hash(state); for sub in &s.mailbox_list { sub.hash(state); @@ -334,15 +343,13 @@ impl Hash for Address { impl core::fmt::Display for Address { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { - Address::Mailbox(m) if m.display_name.length > 0 => { - match m.display_name.display(&m.raw) { - d if d.contains('.') || d.contains(',') => { - write!(f, "\"{}\" <{}>", d, m.address_spec.display(&m.raw)) - } - d => write!(f, "{} <{}>", d, m.address_spec.display(&m.raw)), + Self::Mailbox(m) if m.display_name.length > 0 => match m.display_name.display(&m.raw) { + d if d.contains('.') || d.contains(',') => { + write!(f, "\"{}\" <{}>", d, m.address_spec.display(&m.raw)) } - } - Address::Group(g) => { + d => write!(f, "{} <{}>", d, m.address_spec.display(&m.raw)), + }, + Self::Group(g) => { let attachment_strings: Vec = g.mailbox_list.iter().map(|a| format!("{}", a)).collect(); write!( @@ -352,7 +359,7 @@ impl core::fmt::Display for Address { attachment_strings.join(", ") ) } - Address::Mailbox(m) => write!(f, "{}", m.address_spec.display(&m.raw)), + Self::Mailbox(m) => write!(f, "{}", m.address_spec.display(&m.raw)), } } } @@ -360,12 +367,12 @@ impl core::fmt::Display for Address { impl core::fmt::Debug for Address { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { - Address::Mailbox(m) => f + Self::Mailbox(m) => f .debug_struct("Address::Mailbox") .field("display_name", &m.display_name.display(&m.raw)) .field("address_spec", &m.address_spec.display(&m.raw)) .finish(), - Address::Group(g) => { + Self::Group(g) => { let attachment_strings: Vec = g.mailbox_list.iter().map(|a| format!("{}", a)).collect(); @@ -381,7 +388,7 @@ impl core::fmt::Debug for Address { impl TryFrom<&str> for Address { type Error = Error; - fn try_from(val: &str) -> Result
{ + fn try_from(val: &str) -> Result { Ok(parser::address::address(val.as_bytes())?.1) } } @@ -422,7 +429,7 @@ pub struct MessageID(pub Vec, pub StrBuilder); impl StrBuild for MessageID { fn new(string: &[u8], slice: &[u8]) -> Self { let offset = string.find(slice).unwrap_or(0); - MessageID( + Self( string.to_owned(), StrBuilder { offset, @@ -430,11 +437,13 @@ impl StrBuild for MessageID { }, ) } + fn raw(&self) -> &[u8] { let offset = self.1.offset; let length = self.1.length; &self.0[offset..offset + length.saturating_sub(1)] } + fn val(&self) -> &[u8] { &self.0 } @@ -469,10 +478,11 @@ impl core::fmt::Display for MessageID { } impl PartialEq for MessageID { - fn eq(&self, other: &MessageID) -> bool { + fn eq(&self, other: &Self) -> bool { self.raw() == other.raw() } } + impl core::fmt::Debug for MessageID { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{}", String::from_utf8(self.raw().to_vec()).unwrap()) diff --git a/melib/src/email/attachment_types.rs b/melib/src/email/attachment_types.rs index a758e796..1c812a73 100644 --- a/melib/src/email/attachment_types.rs +++ b/melib/src/email/attachment_types.rs @@ -28,9 +28,10 @@ use crate::email::{ parser::BytesExt, }; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Default, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Charset { Ascii, + #[default] UTF8, UTF16, ISO8859_1, @@ -60,110 +61,102 @@ pub enum Charset { KOI8U, } -impl Default for Charset { - fn default() -> Self { - Charset::UTF8 - } -} - impl<'a> From<&'a [u8]> for Charset { fn from(b: &'a [u8]) -> Self { match b.trim() { b if b.eq_ignore_ascii_case(b"us-ascii") || b.eq_ignore_ascii_case(b"ascii") => { - Charset::Ascii - } - b if b.eq_ignore_ascii_case(b"utf-8") || b.eq_ignore_ascii_case(b"utf8") => { - Charset::UTF8 + Self::Ascii } + b if b.eq_ignore_ascii_case(b"utf-8") || b.eq_ignore_ascii_case(b"utf8") => Self::UTF8, b if b.eq_ignore_ascii_case(b"utf-16") || b.eq_ignore_ascii_case(b"utf16") => { - Charset::UTF16 + Self::UTF16 } b if b.eq_ignore_ascii_case(b"iso-8859-1") || b.eq_ignore_ascii_case(b"iso8859-1") => { - Charset::ISO8859_1 + Self::ISO8859_1 } b if b.eq_ignore_ascii_case(b"iso-8859-2") || b.eq_ignore_ascii_case(b"iso8859-2") => { - Charset::ISO8859_2 + Self::ISO8859_2 } b if b.eq_ignore_ascii_case(b"iso-8859-3") || b.eq_ignore_ascii_case(b"iso8859-3") => { - Charset::ISO8859_3 + Self::ISO8859_3 } b if b.eq_ignore_ascii_case(b"iso-8859-4") || b.eq_ignore_ascii_case(b"iso8859-4") => { - Charset::ISO8859_4 + Self::ISO8859_4 } b if b.eq_ignore_ascii_case(b"iso-8859-5") || b.eq_ignore_ascii_case(b"iso8859-5") => { - Charset::ISO8859_5 + Self::ISO8859_5 } b if b.eq_ignore_ascii_case(b"iso-8859-6") || b.eq_ignore_ascii_case(b"iso8859-6") => { - Charset::ISO8859_6 + Self::ISO8859_6 } b if b.eq_ignore_ascii_case(b"iso-8859-7") || b.eq_ignore_ascii_case(b"iso8859-7") => { - Charset::ISO8859_7 + Self::ISO8859_7 } b if b.eq_ignore_ascii_case(b"iso-8859-8") || b.eq_ignore_ascii_case(b"iso8859-8") => { - Charset::ISO8859_8 + Self::ISO8859_8 } b if b.eq_ignore_ascii_case(b"iso-8859-10") || b.eq_ignore_ascii_case(b"iso8859-10") => { - Charset::ISO8859_10 + Self::ISO8859_10 } b if b.eq_ignore_ascii_case(b"iso-8859-13") || b.eq_ignore_ascii_case(b"iso8859-13") => { - Charset::ISO8859_13 + Self::ISO8859_13 } b if b.eq_ignore_ascii_case(b"iso-8859-14") || b.eq_ignore_ascii_case(b"iso8859-14") => { - Charset::ISO8859_14 + Self::ISO8859_14 } b if b.eq_ignore_ascii_case(b"iso-8859-15") || b.eq_ignore_ascii_case(b"iso8859-15") => { - Charset::ISO8859_15 + Self::ISO8859_15 } b if b.eq_ignore_ascii_case(b"iso-8859-16") || b.eq_ignore_ascii_case(b"iso8859-16") => { - Charset::ISO8859_16 + Self::ISO8859_16 } b if b.eq_ignore_ascii_case(b"windows-1250") || b.eq_ignore_ascii_case(b"windows1250") => { - Charset::Windows1250 + Self::Windows1250 } b if b.eq_ignore_ascii_case(b"windows-1251") || b.eq_ignore_ascii_case(b"windows1251") => { - Charset::Windows1251 + Self::Windows1251 } b if b.eq_ignore_ascii_case(b"windows-1252") || b.eq_ignore_ascii_case(b"windows1252") => { - Charset::Windows1252 + Self::Windows1252 } b if b.eq_ignore_ascii_case(b"windows-1253") || b.eq_ignore_ascii_case(b"windows1253") || b.eq_ignore_ascii_case(b"cp1253") || b.eq_ignore_ascii_case(b"cp-1253") => { - Charset::Windows1253 + Self::Windows1253 } - b if b.eq_ignore_ascii_case(b"gbk") => Charset::GBK, + b if b.eq_ignore_ascii_case(b"gbk") => Self::GBK, b if b.eq_ignore_ascii_case(b"gb18030") || b.eq_ignore_ascii_case(b"gb-18030") => { - Charset::GB18030 + Self::GB18030 } b if b.eq_ignore_ascii_case(b"gb2312") || b.eq_ignore_ascii_case(b"gb-2312") => { - Charset::GB2312 + Self::GB2312 } - b if b.eq_ignore_ascii_case(b"big5") => Charset::BIG5, - b if b.eq_ignore_ascii_case(b"iso-2022-jp") => Charset::ISO2022JP, - b if b.eq_ignore_ascii_case(b"euc-jp") => Charset::EUCJP, - b if b.eq_ignore_ascii_case(b"koi8-r") => Charset::KOI8R, - b if b.eq_ignore_ascii_case(b"koi8-u") => Charset::KOI8U, + b if b.eq_ignore_ascii_case(b"big5") => Self::BIG5, + b if b.eq_ignore_ascii_case(b"iso-2022-jp") => Self::ISO2022JP, + b if b.eq_ignore_ascii_case(b"euc-jp") => Self::EUCJP, + b if b.eq_ignore_ascii_case(b"koi8-r") => Self::KOI8R, + b if b.eq_ignore_ascii_case(b"koi8-u") => Self::KOI8U, _ => { debug!("unknown tag is {:?}", str::from_utf8(b)); - Charset::Ascii + Self::Ascii } } } @@ -172,85 +165,80 @@ impl<'a> From<&'a [u8]> for Charset { impl Display for Charset { fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { - Charset::Ascii => write!(f, "us-ascii"), - Charset::UTF8 => write!(f, "utf-8"), - Charset::UTF16 => write!(f, "utf-16"), - Charset::ISO8859_1 => write!(f, "iso-8859-1"), - Charset::ISO8859_2 => write!(f, "iso-8859-2"), - Charset::ISO8859_3 => write!(f, "iso-8859-3"), - Charset::ISO8859_4 => write!(f, "iso-8859-4"), - Charset::ISO8859_5 => write!(f, "iso-8859-5"), - Charset::ISO8859_6 => write!(f, "iso-8859-6"), - Charset::ISO8859_7 => write!(f, "iso-8859-7"), - Charset::ISO8859_8 => write!(f, "iso-8859-8"), - Charset::ISO8859_10 => write!(f, "iso-8859-10"), - Charset::ISO8859_13 => write!(f, "iso-8859-13"), - Charset::ISO8859_14 => write!(f, "iso-8859-14"), - Charset::ISO8859_15 => write!(f, "iso-8859-15"), - Charset::ISO8859_16 => write!(f, "iso-8859-16"), - Charset::Windows1250 => write!(f, "windows-1250"), - Charset::Windows1251 => write!(f, "windows-1251"), - Charset::Windows1252 => write!(f, "windows-1252"), - Charset::Windows1253 => write!(f, "windows-1253"), - Charset::GBK => write!(f, "gbk"), - Charset::GB2312 => write!(f, "gb2312"), - Charset::GB18030 => write!(f, "gb18030"), - Charset::BIG5 => write!(f, "big5"), - Charset::ISO2022JP => write!(f, "iso-2022-jp"), - Charset::EUCJP => write!(f, "euc-jp"), - Charset::KOI8R => write!(f, "koi8-r"), - Charset::KOI8U => write!(f, "koi8-u"), + Self::Ascii => write!(f, "us-ascii"), + Self::UTF8 => write!(f, "utf-8"), + Self::UTF16 => write!(f, "utf-16"), + Self::ISO8859_1 => write!(f, "iso-8859-1"), + Self::ISO8859_2 => write!(f, "iso-8859-2"), + Self::ISO8859_3 => write!(f, "iso-8859-3"), + Self::ISO8859_4 => write!(f, "iso-8859-4"), + Self::ISO8859_5 => write!(f, "iso-8859-5"), + Self::ISO8859_6 => write!(f, "iso-8859-6"), + Self::ISO8859_7 => write!(f, "iso-8859-7"), + Self::ISO8859_8 => write!(f, "iso-8859-8"), + Self::ISO8859_10 => write!(f, "iso-8859-10"), + Self::ISO8859_13 => write!(f, "iso-8859-13"), + Self::ISO8859_14 => write!(f, "iso-8859-14"), + Self::ISO8859_15 => write!(f, "iso-8859-15"), + Self::ISO8859_16 => write!(f, "iso-8859-16"), + Self::Windows1250 => write!(f, "windows-1250"), + Self::Windows1251 => write!(f, "windows-1251"), + Self::Windows1252 => write!(f, "windows-1252"), + Self::Windows1253 => write!(f, "windows-1253"), + Self::GBK => write!(f, "gbk"), + Self::GB2312 => write!(f, "gb2312"), + Self::GB18030 => write!(f, "gb18030"), + Self::BIG5 => write!(f, "big5"), + Self::ISO2022JP => write!(f, "iso-2022-jp"), + Self::EUCJP => write!(f, "euc-jp"), + Self::KOI8R => write!(f, "koi8-r"), + Self::KOI8U => write!(f, "koi8-u"), } } } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum MultipartType { Alternative, Digest, Encrypted, + #[default] Mixed, Related, Signed, } -impl Default for MultipartType { - fn default() -> Self { - MultipartType::Mixed - } -} - impl Display for MultipartType { fn fmt(&self, f: &mut Formatter) -> FmtResult { write!( f, "{}", match self { - MultipartType::Alternative => "multipart/alternative", - MultipartType::Digest => "multipart/digest", - MultipartType::Encrypted => "multipart/encrypted", - MultipartType::Mixed => "multipart/mixed", - MultipartType::Related => "multipart/related", - MultipartType::Signed => "multipart/signed", + Self::Alternative => "multipart/alternative", + Self::Digest => "multipart/digest", + Self::Encrypted => "multipart/encrypted", + Self::Mixed => "multipart/mixed", + Self::Related => "multipart/related", + Self::Signed => "multipart/signed", } ) } } impl From<&[u8]> for MultipartType { - fn from(val: &[u8]) -> MultipartType { + fn from(val: &[u8]) -> Self { if val.eq_ignore_ascii_case(b"mixed") { - MultipartType::Mixed + Self::Mixed } else if val.eq_ignore_ascii_case(b"alternative") { - MultipartType::Alternative + Self::Alternative } else if val.eq_ignore_ascii_case(b"digest") { - MultipartType::Digest + Self::Digest } else if val.eq_ignore_ascii_case(b"encrypted") { - MultipartType::Encrypted + Self::Encrypted } else if val.eq_ignore_ascii_case(b"signed") { - MultipartType::Signed + Self::Signed } else if val.eq_ignore_ascii_case(b"related") { - MultipartType::Related + Self::Related } else { Default::default() } @@ -286,7 +274,7 @@ pub enum ContentType { impl Default for ContentType { fn default() -> Self { - ContentType::Text { + Self::Text { kind: Text::Plain, parameters: Vec::new(), charset: Charset::UTF8, @@ -298,64 +286,64 @@ impl PartialEq<&[u8]> for ContentType { fn eq(&self, other: &&[u8]) -> bool { match (self, *other) { ( - ContentType::Text { + Self::Text { kind: Text::Plain, .. }, b"text/plain", ) => true, ( - ContentType::Text { + Self::Text { kind: Text::Html, .. }, b"text/html", ) => true, ( - ContentType::Multipart { + Self::Multipart { kind: MultipartType::Alternative, .. }, b"multipart/alternative", ) => true, ( - ContentType::Multipart { + Self::Multipart { kind: MultipartType::Digest, .. }, b"multipart/digest", ) => true, ( - ContentType::Multipart { + Self::Multipart { kind: MultipartType::Encrypted, .. }, b"multipart/encrypted", ) => true, ( - ContentType::Multipart { + Self::Multipart { kind: MultipartType::Mixed, .. }, b"multipart/mixed", ) => true, ( - ContentType::Multipart { + Self::Multipart { kind: MultipartType::Related, .. }, b"multipart/related", ) => true, ( - ContentType::Multipart { + Self::Multipart { kind: MultipartType::Signed, .. }, b"multipart/signed", ) => true, - (ContentType::PGPSignature, b"application/pgp-signature") => true, - (ContentType::CMSSignature, b"application/pkcs7-signature") => true, - (ContentType::MessageRfc822, b"message/rfc822") => true, - (ContentType::Other { tag, .. }, _) => other.eq_ignore_ascii_case(tag), - (ContentType::OctetStream { .. }, b"application/octet-stream") => true, + (Self::PGPSignature, b"application/pgp-signature") => true, + (Self::CMSSignature, b"application/pkcs7-signature") => true, + (Self::MessageRfc822, b"message/rfc822") => true, + (Self::Other { tag, .. }, _) => other.eq_ignore_ascii_case(tag), + (Self::OctetStream { .. }, b"application/octet-stream") => true, _ => false, } } @@ -370,26 +358,26 @@ impl PartialEq<&str> for ContentType { impl Display for ContentType { fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { - ContentType::Text { kind: t, .. } => t.fmt(f), - ContentType::Multipart { kind: k, .. } => k.fmt(f), - ContentType::Other { ref tag, .. } => write!(f, "{}", String::from_utf8_lossy(tag)), - ContentType::PGPSignature => write!(f, "application/pgp-signature"), - ContentType::CMSSignature => write!(f, "application/pkcs7-signature"), - ContentType::MessageRfc822 => write!(f, "message/rfc822"), - ContentType::OctetStream { .. } => write!(f, "application/octet-stream"), + Self::Text { kind: t, .. } => t.fmt(f), + Self::Multipart { kind: k, .. } => k.fmt(f), + Self::Other { ref tag, .. } => write!(f, "{}", String::from_utf8_lossy(tag)), + Self::PGPSignature => write!(f, "application/pgp-signature"), + Self::CMSSignature => write!(f, "application/pkcs7-signature"), + Self::MessageRfc822 => write!(f, "message/rfc822"), + Self::OctetStream { .. } => write!(f, "application/octet-stream"), } } } impl ContentType { pub fn is_text(&self) -> bool { - matches!(self, ContentType::Text { .. }) + matches!(self, Self::Text { .. }) } pub fn is_text_html(&self) -> bool { matches!( self, - ContentType::Text { + Self::Text { kind: Text::Html, .. } @@ -435,8 +423,8 @@ impl ContentType { pub fn name(&self) -> Option<&str> { match self { - ContentType::Other { ref name, .. } => name.as_ref().map(|n| n.as_ref()), - ContentType::OctetStream { + Self::Other { ref name, .. } => name.as_ref().map(|n| n.as_ref()), + Self::OctetStream { ref name, parameters: _, } => name.as_ref().map(|n| n.as_ref()), @@ -445,7 +433,7 @@ impl ContentType { } pub fn parts(&self) -> Option<&[Attachment]> { - if let ContentType::Multipart { ref parts, .. } = self { + if let Self::Multipart { ref parts, .. } = self { Some(parts) } else { None @@ -463,61 +451,58 @@ pub enum Text { impl Text { pub fn is_html(&self) -> bool { - matches!(self, Text::Html) + matches!(self, Self::Html) } } impl Display for Text { fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { - Text::Plain => write!(f, "text/plain"), - Text::Html => write!(f, "text/html"), - Text::Rfc822 => write!(f, "text/rfc822"), - Text::Other { tag: ref t } => write!(f, "text/{}", String::from_utf8_lossy(t)), + Self::Plain => write!(f, "text/plain"), + Self::Html => write!(f, "text/html"), + Self::Rfc822 => write!(f, "text/rfc822"), + Self::Other { tag: ref t } => write!(f, "text/{}", String::from_utf8_lossy(t)), } } } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum ContentTransferEncoding { + #[default] _8Bit, _7Bit, Base64, QuotedPrintable, - Other { tag: Vec }, -} - -impl Default for ContentTransferEncoding { - fn default() -> Self { - ContentTransferEncoding::_8Bit - } + Other { + tag: Vec, + }, } impl Display for ContentTransferEncoding { fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { - ContentTransferEncoding::_7Bit => write!(f, "7bit"), - ContentTransferEncoding::_8Bit => write!(f, "8bit"), - ContentTransferEncoding::Base64 => write!(f, "base64"), - ContentTransferEncoding::QuotedPrintable => write!(f, "quoted-printable"), - ContentTransferEncoding::Other { tag: ref t } => { + Self::_7Bit => write!(f, "7bit"), + Self::_8Bit => write!(f, "8bit"), + Self::Base64 => write!(f, "base64"), + Self::QuotedPrintable => write!(f, "quoted-printable"), + Self::Other { tag: ref t } => { panic!("unknown encoding {:?}", str::from_utf8(t)) } } } } impl From<&[u8]> for ContentTransferEncoding { - fn from(val: &[u8]) -> ContentTransferEncoding { + fn from(val: &[u8]) -> Self { if val.eq_ignore_ascii_case(b"base64") { - ContentTransferEncoding::Base64 + Self::Base64 } else if val.eq_ignore_ascii_case(b"7bit") { - ContentTransferEncoding::_7Bit + Self::_7Bit } else if val.eq_ignore_ascii_case(b"8bit") { - ContentTransferEncoding::_8Bit + Self::_8Bit } else if val.eq_ignore_ascii_case(b"quoted-printable") { - ContentTransferEncoding::QuotedPrintable + Self::QuotedPrintable } else { - ContentTransferEncoding::Other { + Self::Other { tag: val.to_ascii_lowercase(), } } @@ -535,38 +520,33 @@ pub struct ContentDisposition { pub parameter: Vec, } -#[derive(Clone, Debug, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Default, Debug, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum ContentDispositionKind { + #[default] Inline, Attachment, } impl ContentDispositionKind { pub fn is_inline(&self) -> bool { - matches!(self, ContentDispositionKind::Inline) + matches!(self, Self::Inline) } pub fn is_attachment(&self) -> bool { - matches!(self, ContentDispositionKind::Attachment) - } -} - -impl Default for ContentDispositionKind { - fn default() -> Self { - ContentDispositionKind::Inline + matches!(self, Self::Attachment) } } impl Display for ContentDispositionKind { fn fmt(&self, f: &mut Formatter) -> FmtResult { match *self { - ContentDispositionKind::Inline => write!(f, "inline"), - ContentDispositionKind::Attachment => write!(f, "attachment"), + Self::Inline => write!(f, "inline"), + Self::Attachment => write!(f, "attachment"), } } } impl From<&[u8]> for ContentDisposition { - fn from(val: &[u8]) -> ContentDisposition { + fn from(val: &[u8]) -> Self { crate::email::parser::attachments::content_disposition(val) .map(|(_, v)| v) .unwrap_or_default() @@ -574,10 +554,10 @@ impl From<&[u8]> for ContentDisposition { } impl From for ContentDisposition { - fn from(kind: ContentDispositionKind) -> ContentDisposition { - ContentDisposition { + fn from(kind: ContentDispositionKind) -> Self { + Self { kind, - ..ContentDisposition::default() + ..Self::default() } } } diff --git a/melib/src/email/attachments.rs b/melib/src/email/attachments.rs index bfd57ede..0e494c52 100644 --- a/melib/src/email/attachments.rs +++ b/melib/src/email/attachments.rs @@ -82,7 +82,7 @@ impl AttachmentBuilder { log::debug!("{}\n", String::from_utf8_lossy(content)); log::debug!("-------------------------------\n"); - return AttachmentBuilder { + return Self { content_type: Default::default(), content_transfer_encoding: ContentTransferEncoding::_7Bit, content_disposition: ContentDisposition::default(), @@ -100,7 +100,7 @@ impl AttachmentBuilder { offset: content.len() - body.len(), length: body.len(), }; - let mut builder = AttachmentBuilder { + let mut builder = Self { raw, body, ..Default::default() @@ -300,7 +300,7 @@ impl AttachmentBuilder { Ok((_, attachments)) => { let mut vec = Vec::with_capacity(attachments.len()); for a in attachments { - let mut builder = AttachmentBuilder::default(); + let mut builder = Self::default(); let (headers, body) = match parser::attachments::attachment(a) { Ok((_, v)) => v, Err(err) => { @@ -355,7 +355,7 @@ impl From for AttachmentBuilder { raw, body, } = val; - AttachmentBuilder { + Self { content_type, content_disposition, content_transfer_encoding, @@ -374,7 +374,7 @@ impl From for Attachment { raw, body, } = val; - Attachment { + Self { content_type, content_transfer_encoding, content_disposition, @@ -486,7 +486,7 @@ impl Attachment { content_transfer_encoding: ContentTransferEncoding, raw: Vec, ) -> Self { - Attachment { + Self { content_type, content_disposition: ContentDisposition::default(), content_transfer_encoding, @@ -575,7 +575,7 @@ impl Attachment { None }) { - if Attachment::check_if_has_attachments_quick(body, boundary) { + if Self::check_if_has_attachments_quick(body, boundary) { return true; } } @@ -663,7 +663,7 @@ impl Attachment { self.content_type.to_string() } - pub fn attachments(&self) -> Vec { + pub fn attachments(&self) -> Vec { let mut ret = Vec::new(); fn count_recursive(att: &Attachment, ret: &mut Vec) { match att.content_type { @@ -713,12 +713,12 @@ impl Attachment { kind: MultipartType::Alternative, ref parts, .. - } => parts.iter().all(Attachment::is_html), + } => parts.iter().all(Self::is_html), ContentType::Multipart { kind: MultipartType::Related, .. } => false, - ContentType::Multipart { ref parts, .. } => parts.iter().any(Attachment::is_html), + ContentType::Multipart { ref parts, .. } => parts.iter().any(Self::is_html), _ => false, } } @@ -893,7 +893,7 @@ impl Attachment { .map(|n| n.replace(|c| std::path::is_separator(c) || c.is_ascii_control(), "_")) } - fn decode_rec_helper<'a, 'b>(&'a self, options: &mut DecodeOptions<'b>) -> Vec { + fn decode_rec_helper(&self, options: &mut DecodeOptions<'_>) -> Vec { match self.content_type { ContentType::Other { .. } => Vec::new(), ContentType::Text { .. } => self.decode_helper(options), @@ -962,11 +962,11 @@ impl Attachment { } } - pub fn decode_rec<'a, 'b>(&'a self, mut options: DecodeOptions<'b>) -> Vec { + pub fn decode_rec(&self, mut options: DecodeOptions<'_>) -> Vec { self.decode_rec_helper(&mut options) } - fn decode_helper<'a, 'b>(&'a self, options: &mut DecodeOptions<'b>) -> Vec { + fn decode_helper(&self, options: &mut DecodeOptions<'_>) -> Vec { let charset = options .force_charset .unwrap_or_else(|| match self.content_type { @@ -1006,7 +1006,7 @@ impl Attachment { ret } - pub fn decode<'a, 'b>(&'a self, mut options: DecodeOptions<'b>) -> Vec { + pub fn decode(&self, mut options: DecodeOptions<'_>) -> Vec { self.decode_helper(&mut options) } } diff --git a/melib/src/email/compose.rs b/melib/src/email/compose.rs index 11a43063..3646cdf4 100644 --- a/melib/src/email/compose.rs +++ b/melib/src/email/compose.rs @@ -71,7 +71,7 @@ impl Default for Draft { headers.insert(HeaderName::BCC, "".into()); headers.insert(HeaderName::SUBJECT, "".into()); - Draft { + Self { headers, body: String::new(), wrap_header_preamble: None, @@ -89,7 +89,7 @@ impl FromStr for Draft { } let (headers, _) = parser::mail(s.as_bytes())?; - let mut ret = Draft::default(); + let mut ret = Self::default(); for (k, v) in headers { ret.headers @@ -105,7 +105,7 @@ impl FromStr for Draft { impl Draft { pub fn edit(envelope: &Envelope, bytes: &[u8]) -> Result { - let mut ret = Draft::default(); + let mut ret = Self::default(); for (k, v) in envelope.headers(bytes).unwrap_or_else(|_| Vec::new()) { ret.headers.insert(k.try_into()?, v.into()); } @@ -157,7 +157,7 @@ impl Draft { .into(); } } - let new = Draft::from_str(value.as_ref())?; + let new = Self::from_str(value.as_ref())?; let changes: bool = self.headers != new.headers || self.body != new.body; self.headers = new.headers; self.body = new.body; @@ -165,7 +165,7 @@ impl Draft { } pub fn new_reply(envelope: &Envelope, bytes: &[u8], reply_to_all: bool) -> Self { - let mut ret = Draft::default(); + let mut ret = Self::default(); ret.headers_mut().insert( HeaderName::REFERENCES, format!( @@ -525,11 +525,7 @@ where .set_body_to_raw() .set_content_type(ContentType::Other { name: path.file_name().map(|s| s.to_string_lossy().into()), - tag: if let Ok(mime_type) = query_mime_info(&path) { - mime_type - } else { - b"application/octet-stream".to_vec() - }, + tag: query_mime_info(&path).unwrap_or_else(|_| b"application/octet-stream".to_vec()), parameters: vec![], }); diff --git a/melib/src/email/headers.rs b/melib/src/email/headers.rs index 2cf773ec..2ca25747 100644 --- a/melib/src/email/headers.rs +++ b/melib/src/email/headers.rs @@ -186,7 +186,6 @@ mod tests { fn test_headers_case_sensitivity() { let mut headers = HeaderMap::default(); headers.insert("from".try_into().unwrap(), "Myself ".into()); - dbg!(&headers); assert_eq!(&headers["From"], "Myself "); assert_eq!(&headers["From"], &headers["from"]); assert_eq!(&headers["fROm"], &headers["from"]); @@ -201,7 +200,6 @@ mod tests { let mut headers = HeaderMap::default(); headers.insert(HeaderName::SUBJECT, "foobar".into()); headers.insert(HeaderName::MESSAGE_ID, "foobar@examplecom".into()); - dbg!(&headers); assert_eq!(&headers[0], "foobar"); assert_eq!(&headers[HeaderName::SUBJECT], "foobar"); assert_eq!(&headers[&HeaderName::SUBJECT], "foobar"); diff --git a/melib/src/email/headers/names.rs b/melib/src/email/headers/names.rs index 4fc341b0..90a35964 100644 --- a/melib/src/email/headers/names.rs +++ b/melib/src/email/headers/names.rs @@ -55,7 +55,7 @@ pub struct HeaderName { impl Custom { fn as_str(&self) -> &str { - unsafe { std::str::from_utf8_unchecked(&*self.0) } + unsafe { std::str::from_utf8_unchecked(&self.0) } } } @@ -85,7 +85,7 @@ impl Error for InvalidHeaderName {} impl std::fmt::Debug for InvalidHeaderName { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "{}", "Invalid header name.") + write!(fmt, "Invalid header name.") } } @@ -159,6 +159,8 @@ macro_rules! standard_headers { } } + // invalid clippy lint match here + #[allow(clippy::string_lit_as_bytes)] pub fn from_bytes(name_bytes: &[u8]) -> Option { match name_bytes { $( @@ -217,6 +219,8 @@ macro_rules! standards { } + // invalid clippy lint match here + #[allow(clippy::string_lit_as_bytes)] pub fn from_bytes(name_bytes: &[u8]) -> Option { match name_bytes { $( @@ -565,8 +569,8 @@ impl HeaderName { impl FromStr for HeaderName { type Err = InvalidHeaderName; - fn from_str(s: &str) -> Result { - HeaderName::from_bytes(s.as_bytes()).map_err(|_| InvalidHeaderName::new()) + fn from_str(s: &str) -> Result { + Self::from_bytes(s.as_bytes()).map_err(|_| InvalidHeaderName::new()) } } @@ -605,15 +609,15 @@ impl<'de> Deserialize<'de> for HeaderName { S(String), B(Vec), } - if let Ok(s) = ::deserialize(deserializer) { - Self::from_bytes(match &s { - Helper::S(v) => v.as_bytes(), - Helper::B(v) => v.as_slice(), - }) + ::deserialize(deserializer) .map_err(|_| de::Error::custom("invalid header name value")) - } else { - Err(de::Error::custom("invalid header name value")) - } + .and_then(|s| { + Self::from_bytes(match &s { + Helper::S(v) => v.as_bytes(), + Helper::B(v) => v.as_slice(), + }) + .map_err(|_| de::Error::custom("invalid header name value")) + }) } } @@ -627,13 +631,13 @@ impl Serialize for HeaderName { } impl InvalidHeaderName { - const fn new() -> InvalidHeaderName { - InvalidHeaderName + const fn new() -> Self { + Self } } -impl<'a> From<&'a HeaderName> for HeaderName { - fn from(src: &'a HeaderName) -> Self { +impl<'a> From<&'a Self> for HeaderName { + fn from(src: &'a Self) -> Self { src.clone() } } @@ -691,8 +695,8 @@ impl TryFrom> for HeaderName { #[doc(hidden)] impl From for HeaderName { - fn from(src: StandardHeader) -> HeaderName { - HeaderName { + fn from(src: StandardHeader) -> Self { + Self { inner: Repr::Standard(src), } } @@ -700,16 +704,16 @@ impl From for HeaderName { #[doc(hidden)] impl From for HeaderName { - fn from(src: Custom) -> HeaderName { - HeaderName { + fn from(src: Custom) -> Self { + Self { inner: Repr::Custom(src), } } } -impl<'a> PartialEq<&'a HeaderName> for HeaderName { +impl<'a> PartialEq<&'a Self> for HeaderName { #[inline] - fn eq(&self, other: &&'a HeaderName) -> bool { + fn eq(&self, other: &&'a Self) -> bool { *self == **other } } @@ -861,7 +865,7 @@ impl<'a, 'b> Iterator for AsciiIgnoreCaseCmp<'a, 'b> { type Item = (); fn next(&mut self) -> Option<()> { - match (self.a.get(0), self.b.get(0)) { + match (self.a.first(), self.b.first()) { (Some(a_char), Some(b_char)) => { self.ord = a_char .to_ascii_lowercase() diff --git a/melib/src/email/list_management.rs b/melib/src/email/list_management.rs index 4727c307..452c35b1 100644 --- a/melib/src/email/list_management.rs +++ b/melib/src/email/list_management.rs @@ -107,9 +107,10 @@ pub fn list_id(header: Option<&'_ str>) -> Option<&'_ str> { impl<'a> ListActions<'a> { pub fn detect(envelope: &'a Envelope) -> Option> { - let mut ret = ListActions::default(); - - ret.id = list_id_header(envelope); + let mut ret = Self { + id: list_id_header(envelope), + ..Self::default() + }; if let Some(archive) = envelope.other_headers().get("List-Archive") { if archive.starts_with('<') { diff --git a/melib/src/email/mailto.rs b/melib/src/email/mailto.rs index b4a801a5..6ce75f45 100644 --- a/melib/src/email/mailto.rs +++ b/melib/src/email/mailto.rs @@ -114,7 +114,7 @@ impl Mailto { impl From for Draft { fn from(val: Mailto) -> Self { - let mut ret = Draft::default(); + let mut ret = Self::default(); let Mailto { address: _, body, @@ -130,7 +130,7 @@ impl From for Draft { impl From<&Mailto> for Draft { fn from(val: &Mailto) -> Self { - Draft::from(val.clone()) + Self::from(val.clone()) } } @@ -138,17 +138,16 @@ impl TryFrom<&[u8]> for Mailto { type Error = String; fn try_from(value: &[u8]) -> std::result::Result { - let parse_res = super::parser::generic::mailto(value).map(|(_, v)| v); - if let Ok(res) = parse_res { - Ok(res) - } else { - debug!( - "parser::mailto returned error while parsing {}:\n{:?}", - String::from_utf8_lossy(value), - parse_res.as_ref().err().unwrap() - ); - Err(format!("{:?}", parse_res.err().unwrap())) - } + super::parser::generic::mailto(value) + .map(|(_, v)| v) + .map_err(|err| { + log::debug!( + "parser::mailto returned error while parsing {}:\n{:?}", + String::from_utf8_lossy(value), + &err, + ); + format!("{:?}", err) + }) } } @@ -156,17 +155,16 @@ impl TryFrom<&str> for Mailto { type Error = String; fn try_from(value: &str) -> std::result::Result { - let parse_res = super::parser::generic::mailto(value.as_bytes()).map(|(_, v)| v); - if let Ok(res) = parse_res { - Ok(res) - } else { - debug!( - "parser::mailto returned error while parsing {}:\n{:?}", - value, - parse_res.as_ref().err().unwrap() - ); - Err(format!("{:?}", parse_res.err().unwrap())) - } + super::parser::generic::mailto(value.as_bytes()) + .map(|(_, v)| v) + .map_err(|err| { + log::debug!( + "parser::mailto returned error while parsing {}:\n{:?}", + value, + &err + ); + format!("{:?}", err) + }) } } @@ -331,7 +329,7 @@ mod tests { // by using "?" twice, is incorrect: ; WRONG! - assert!(Mailto::try_from("mailto:joe@example.com?cc=bob@example.com?body=hello").is_err()); + Mailto::try_from("mailto:joe@example.com?cc=bob@example.com?body=hello").unwrap_err(); // assert // these are equal diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index 6dd426da..38f3b979 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -20,6 +20,7 @@ */ //! Parsers for email. See submodules. +#![allow(clippy::type_complexity)] use std::{borrow::Cow, convert::TryFrom, fmt::Write}; @@ -143,8 +144,8 @@ impl nom::error::FromExternalError for ParsingError { impl nom::error::ContextError for ParsingError {} impl<'i> From> for Error { - fn from(val: ParsingError<&'i [u8]>) -> Error { - Error::new("Parsing error").set_summary(format!( + fn from(val: ParsingError<&'i [u8]>) -> Self { + Self::new("Parsing error").set_summary(format!( r#"In input: "{}...", Error: {}"#, String::from_utf8_lossy(val.input) @@ -157,8 +158,8 @@ Error: {}"#, } impl<'i> From> for Error { - fn from(val: ParsingError<&'i str>) -> Error { - Error::new("Parsing error").set_summary(format!( + fn from(val: ParsingError<&'i str>) -> Self { + Self::new("Parsing error").set_summary(format!( r#"In input: "{}...", Error: {}"#, val.input.chars().take(30).collect::(), @@ -168,34 +169,34 @@ Error: {}"#, } impl<'i> From>> for Error { - fn from(val: nom::Err>) -> Error { + fn from(val: nom::Err>) -> Self { match val { - nom::Err::Incomplete(_) => Error::new("Parsing Error: Incomplete"), + nom::Err::Incomplete(_) => Self::new("Parsing Error: Incomplete"), nom::Err::Error(err) | nom::Err::Failure(err) => err.into(), } } } impl<'i> From>> for Error { - fn from(val: nom::Err>) -> Error { + fn from(val: nom::Err>) -> Self { match val { - nom::Err::Incomplete(_) => Error::new("Parsing Error: Incomplete"), + nom::Err::Incomplete(_) => Self::new("Parsing Error: Incomplete"), nom::Err::Error(err) | nom::Err::Failure(err) => err.into(), } } } impl From>> for Error { - fn from(val: nom::Err>) -> Error { + fn from(val: nom::Err>) -> Self { match val { - nom::Err::Incomplete(_) => Error::new("Parsing Error: Incomplete"), - nom::Err::Error(_) | nom::Err::Failure(_) => Error::new("Parsing Error"), + nom::Err::Incomplete(_) => Self::new("Parsing Error: Incomplete"), + nom::Err::Error(_) | nom::Err::Failure(_) => Self::new("Parsing Error"), } } } impl<'i> From> for nom::error::Error<&'i [u8]> { - fn from(val: ParsingError<&'i [u8]>) -> nom::error::Error<&'i [u8]> { + fn from(val: ParsingError<&'i [u8]>) -> Self { nom::error::Error::new(val.input, ErrorKind::Satisfy) } } @@ -2044,10 +2045,9 @@ pub mod encodings { let encoded_text = &input[3 + tag_end_idx..encoded_end_idx]; let s: Vec = match input[tag_end_idx + 1] { - b'b' | b'B' => match BASE64_MIME.decode(encoded_text) { - Ok(v) => v, - Err(_) => encoded_text.to_vec(), - }, + b'b' | b'B' => BASE64_MIME + .decode(encoded_text) + .map_or_else(|_| encoded_text.to_vec(), |v| v), b'q' | b'Q' => match quoted_printable_bytes_header(encoded_text) { Ok((b"", s)) => s, _ => { @@ -2065,19 +2065,21 @@ pub mod encodings { let charset = Charset::from(&input[2..tag_end_idx]); - if let Charset::UTF8 = charset { + if Charset::UTF8 == charset { Ok((&input[encoded_end_idx + 2..], s)) } else { - match decode_charset(&s, charset) { - Ok(v) => Ok((&input[encoded_end_idx + 2..], v.into_bytes())), - _ => Err(nom::Err::Error( - ( - input, - format!("encoded_word(): unknown charset {:?}", charset), - ) - .into(), - )), - } + decode_charset(&s, charset).map_or_else( + |_| { + Err(nom::Err::Error( + ( + input, + format!("encoded_word(): unknown charset {:?}", charset), + ) + .into(), + )) + }, + |v| Ok((&input[encoded_end_idx + 2..], v.into_bytes())), + ) } } @@ -2798,32 +2800,31 @@ mod tests { ); } - #[test] - fn test_attachments() { - //FIXME: add file - return; - /* - use std::io::Read; - let mut buffer: Vec = Vec::new(); - let _ = std::fs::File::open("").unwrap().read_to_end(&mut buffer); - let boundary = b"b1_4382d284f0c601a737bb32aaeda53160"; - let (_, body) = match mail(&buffer) { - Ok(v) => v, - Err(_) => panic!(), - }; - let attachments = parts(body, boundary).unwrap().1; - assert_eq!(attachments.len(), 4); - let v: Vec<&str> = attachments - .iter() - .map(|v| std::str::from_utf8(v).unwrap()) - .collect(); - //println!("attachments {:?}", v); - */ - } + // //FIXME: add file + //#[test] + //fn test_attachments() { + // use std::io::Read; + // let mut buffer: Vec = Vec::new(); + // let _ = std::fs::File::open("").unwrap().read_to_end(&mut buffer); + // let boundary = b"b1_4382d284f0c601a737bb32aaeda53160"; + // let (_, body) = match mail(&buffer) { + // Ok(v) => v, + // Err(_) => panic!(), + // }; + // let attachments = parts(body, boundary).unwrap().1; + // assert_eq!(attachments.len(), 4); + // let v: Vec<&str> = attachments + // .iter() + // .map(|v| std::str::from_utf8(v).unwrap()) + // .collect(); + // //println!("attachments {:?}", v); + //} + #[test] fn test_addresses() { macro_rules! assert_parse { ($name:literal, $addr:literal, $raw:literal) => {{ + #[allow(clippy::string_lit_as_bytes)] let s = $raw.as_bytes(); let r = address(s).unwrap().1; match r { diff --git a/melib/src/error.rs b/melib/src/error.rs index e61e99f2..3a443f11 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -460,11 +460,11 @@ impl> ResultIntoError for std::result::Result { } impl Error { - pub fn new(msg: M) -> Error + pub fn new(msg: M) -> Self where M: Into>, { - Error { + Self { summary: msg.into(), details: None, source: None, @@ -472,7 +472,7 @@ impl Error { } } - pub fn set_details(mut self, details: M) -> Error + pub fn set_details(mut self, details: M) -> Self where M: Into>, { @@ -484,7 +484,7 @@ impl Error { self } - pub fn set_summary(mut self, summary: M) -> Error + pub fn set_summary(mut self, summary: M) -> Self where M: Into>, { @@ -499,12 +499,12 @@ impl Error { pub fn set_source( mut self, new_val: Option>, - ) -> Error { + ) -> Self { self.source = new_val; self } - pub fn set_kind(mut self, new_val: ErrorKind) -> Error { + pub fn set_kind(mut self, new_val: ErrorKind) -> Self { self.kind = new_val; self } @@ -528,14 +528,16 @@ impl fmt::Display for Error { impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.source.as_ref().map(|s| &(*(*s)) as _) + self.source + .as_ref() + .map(|s| &(*(*s)) as &(dyn std::error::Error + 'static)) } } impl From for Error { #[inline] - fn from(kind: io::Error) -> Error { - Error::new(kind.to_string()) + fn from(kind: io::Error) -> Self { + Self::new(kind.to_string()) .set_details(kind.kind().to_string()) .set_source(Some(Arc::new(kind))) .set_kind(ErrorKind::OSError) @@ -544,22 +546,22 @@ impl From for Error { impl<'a> From> for Error { #[inline] - fn from(kind: Cow<'_, str>) -> Error { - Error::new(kind.to_string()) + fn from(kind: Cow<'_, str>) -> Self { + Self::new(kind.to_string()) } } impl From for Error { #[inline] - fn from(kind: string::FromUtf8Error) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: string::FromUtf8Error) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } impl From for Error { #[inline] - fn from(kind: str::Utf8Error) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: str::Utf8Error) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } //use std::option; @@ -572,16 +574,16 @@ impl From for Error { impl From> for Error { #[inline] - fn from(kind: std::sync::PoisonError) -> Error { - Error::new(kind.to_string()).set_kind(ErrorKind::Bug) + fn from(kind: std::sync::PoisonError) -> Self { + Self::new(kind.to_string()).set_kind(ErrorKind::Bug) } } #[cfg(feature = "tls")] impl From> for Error { #[inline] - fn from(kind: native_tls::HandshakeError) -> Error { - Error::new(kind.to_string()) + fn from(kind: native_tls::HandshakeError) -> Self { + Self::new(kind.to_string()) .set_source(Some(Arc::new(kind))) .set_kind(ErrorKind::Network(NetworkErrorKind::InvalidTLSConnection)) } @@ -590,8 +592,8 @@ impl From for Error { #[inline] - fn from(kind: native_tls::Error) -> Error { - Error::new(kind.to_string()) + fn from(kind: native_tls::Error) -> Self { + Self::new(kind.to_string()) .set_source(Some(Arc::new(kind))) .set_kind(ErrorKind::Network(NetworkErrorKind::InvalidTLSConnection)) } @@ -599,49 +601,49 @@ impl From for Error { impl From for Error { #[inline] - fn from(kind: std::num::ParseIntError) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: std::num::ParseIntError) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } #[cfg(feature = "http")] impl From<&isahc::error::ErrorKind> for NetworkErrorKind { #[inline] - fn from(val: &isahc::error::ErrorKind) -> NetworkErrorKind { + fn from(val: &isahc::error::ErrorKind) -> Self { use isahc::error::ErrorKind::*; match val { - BadClientCertificate => NetworkErrorKind::BadClientCertificate, - BadServerCertificate => NetworkErrorKind::BadServerCertificate, - ClientInitialization => NetworkErrorKind::ClientInitialization, - ConnectionFailed => NetworkErrorKind::ConnectionFailed, - InvalidContentEncoding => NetworkErrorKind::InvalidContentEncoding, - InvalidCredentials => NetworkErrorKind::InvalidCredentials, - InvalidRequest => NetworkErrorKind::BadRequest, - Io => NetworkErrorKind::Io, - NameResolution => NetworkErrorKind::HostLookupFailed, - ProtocolViolation => NetworkErrorKind::ProtocolViolation, - RequestBodyNotRewindable => NetworkErrorKind::RequestBodyNotRewindable, - Timeout => NetworkErrorKind::Timeout, - TlsEngine => NetworkErrorKind::InvalidTLSConnection, - TooManyRedirects => NetworkErrorKind::TooManyRedirects, - _ => NetworkErrorKind::None, + BadClientCertificate => Self::BadClientCertificate, + BadServerCertificate => Self::BadServerCertificate, + ClientInitialization => Self::ClientInitialization, + ConnectionFailed => Self::ConnectionFailed, + InvalidContentEncoding => Self::InvalidContentEncoding, + InvalidCredentials => Self::InvalidCredentials, + InvalidRequest => Self::BadRequest, + Io => Self::Io, + NameResolution => Self::HostLookupFailed, + ProtocolViolation => Self::ProtocolViolation, + RequestBodyNotRewindable => Self::RequestBodyNotRewindable, + Timeout => Self::Timeout, + TlsEngine => Self::InvalidTLSConnection, + TooManyRedirects => Self::TooManyRedirects, + _ => Self::None, } } } impl From for ErrorKind { #[inline] - fn from(kind: NetworkErrorKind) -> ErrorKind { - ErrorKind::Network(kind) + fn from(kind: NetworkErrorKind) -> Self { + Self::Network(kind) } } #[cfg(feature = "http")] impl From for Error { #[inline] - fn from(val: isahc::Error) -> Error { + fn from(val: isahc::Error) -> Self { let kind: NetworkErrorKind = val.kind().into(); - Error::new(val.to_string()) + Self::new(val.to_string()) .set_source(Some(Arc::new(val))) .set_kind(ErrorKind::Network(kind)) } @@ -650,102 +652,102 @@ impl From for Error { #[cfg(feature = "jmap_backend")] impl From for Error { #[inline] - fn from(kind: serde_json::error::Error) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: serde_json::error::Error) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } impl From> for Error { #[inline] - fn from(kind: Box) -> Error { - Error::new(kind.to_string()).set_source(Some(kind.into())) + fn from(kind: Box) -> Self { + Self::new(kind.to_string()).set_source(Some(kind.into())) } } impl From for Error { #[inline] - fn from(kind: std::ffi::NulError) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: std::ffi::NulError) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } impl From for Error { #[inline] - fn from(kind: nix::Error) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: nix::Error) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } #[cfg(feature = "sqlite3")] impl From for Error { #[inline] - fn from(kind: rusqlite::Error) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: rusqlite::Error) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } impl From for Error { #[inline] - fn from(kind: libloading::Error) -> Error { - Error::new(kind.to_string()).set_source(Some(Arc::new(kind))) + fn from(kind: libloading::Error) -> Self { + Self::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } impl From<&str> for Error { #[inline] - fn from(kind: &str) -> Error { - Error::new(kind.to_string()) + fn from(kind: &str) -> Self { + Self::new(kind.to_string()) } } impl From for Error { #[inline] - fn from(kind: String) -> Error { - Error::new(kind) + fn from(kind: String) -> Self { + Self::new(kind) } } impl From> for Error { #[inline] - fn from(kind: nom::Err<(&[u8], nom::error::ErrorKind)>) -> Error { - Error::new("Parsing error").set_source(Some(Arc::new(Error::new(kind.to_string())))) + fn from(kind: nom::Err<(&[u8], nom::error::ErrorKind)>) -> Self { + Self::new("Parsing error").set_source(Some(Arc::new(Self::new(kind.to_string())))) } } impl From> for Error { #[inline] - fn from(kind: nom::Err<(&str, nom::error::ErrorKind)>) -> Error { - Error::new("Parsing error").set_details(kind.to_string()) + fn from(kind: nom::Err<(&str, nom::error::ErrorKind)>) -> Self { + Self::new("Parsing error").set_details(kind.to_string()) } } impl From for Error { #[inline] - fn from(kind: crate::email::InvalidHeaderName) -> Error { - Error::new(kind.to_string()) + fn from(kind: crate::email::InvalidHeaderName) -> Self { + Self::new(kind.to_string()) .set_source(Some(Arc::new(kind))) .set_kind(ErrorKind::Network(NetworkErrorKind::InvalidTLSConnection)) } } -impl<'a> From<&'a mut Error> for Error { +impl<'a> From<&'a mut Self> for Error { #[inline] - fn from(kind: &'a mut Error) -> Error { + fn from(kind: &'a mut Self) -> Self { kind.clone() } } -impl<'a> From<&'a Error> for Error { +impl<'a> From<&'a Self> for Error { #[inline] - fn from(kind: &'a Error) -> Error { + fn from(kind: &'a Self) -> Self { kind.clone() } } impl From for Error { #[inline] - fn from(kind: base64::DecodeError) -> Error { - Error::new("base64 decoding failed") + fn from(kind: base64::DecodeError) -> Self { + Self::new("base64 decoding failed") .set_source(Some(Arc::new(kind))) .set_kind(ErrorKind::ValueError) } diff --git a/melib/src/gpgme/bindings.rs b/melib/src/gpgme/bindings.rs index 4ff92587..80318c51 100644 --- a/melib/src/gpgme/bindings.rs +++ b/melib/src/gpgme/bindings.rs @@ -25,6 +25,7 @@ #![allow(unused)] #![allow(dead_code)] #![allow(clippy::useless_transmute)] +#![allow(clippy::borrow_as_ptr)] #![allow(clippy::too_many_arguments)] use libc::{off_t, time_t, FILE}; @@ -4993,10 +4994,10 @@ pub type gpgme_set_global_flag = extern "C" fn( value: *const ::std::os::raw::c_char, ) -> ::std::os::raw::c_int; pub type gpgme_check_version = unsafe extern "C" fn( - req_version: *const ::std::os::raw::c_char, + req_version: *const ::std::os::raw::c_uchar, ) -> *const ::std::os::raw::c_char; pub type gpgme_check_version_internal = extern "C" fn( - req_version: *const ::std::os::raw::c_char, + req_version: *const ::std::os::raw::c_uchar, offset_sig_validity: usize, ) -> *const ::std::os::raw::c_char; pub type gpgme_get_dirinfo = @@ -5379,7 +5380,7 @@ fn bindgen_test_layout___va_list_tag() { concat!("Alignment of ", stringify!(__va_list_tag)) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<__va_list_tag>())).gp_offset as *const _ as usize }, + unsafe { std::ptr::addr_of!((*(::std::ptr::null::<__va_list_tag>())).gp_offset) as usize }, 0usize, concat!( "Offset of field: ", @@ -5389,7 +5390,7 @@ fn bindgen_test_layout___va_list_tag() { ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<__va_list_tag>())).fp_offset as *const _ as usize }, + unsafe { std::ptr::addr_of!((*(::std::ptr::null::<__va_list_tag>())).fp_offset) as usize }, 4usize, concat!( "Offset of field: ", @@ -5399,7 +5400,9 @@ fn bindgen_test_layout___va_list_tag() { ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<__va_list_tag>())).overflow_arg_area as *const _ as usize }, + unsafe { + std::ptr::addr_of!((*(::std::ptr::null::<__va_list_tag>())).overflow_arg_area) as usize + }, 8usize, concat!( "Offset of field: ", @@ -5409,7 +5412,9 @@ fn bindgen_test_layout___va_list_tag() { ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<__va_list_tag>())).reg_save_area as *const _ as usize }, + unsafe { + std::ptr::addr_of!((*(::std::ptr::null::<__va_list_tag>())).reg_save_area) as usize + }, 16usize, concat!( "Offset of field: ", diff --git a/melib/src/gpgme/mod.rs b/melib/src/gpgme/mod.rs index 858a14cb..f4a9b62b 100644 --- a/melib/src/gpgme/mod.rs +++ b/melib/src/gpgme/mod.rs @@ -108,11 +108,10 @@ impl<'de> Deserialize<'de> for LocateKey { where D: Deserializer<'de>, { - if let Ok(s) = ::deserialize(deserializer) { - LocateKey::from_string_de::<'de, D, String>(s) - } else { - Err(de::Error::custom("LocateKey value must be a string.")) - } + ::deserialize(deserializer).map_or_else( + |_| Err(de::Error::custom("LocateKey value must be a string.")), + |s| Self::from_string_de::<'de, D, String>(s), + ) } } @@ -131,16 +130,16 @@ impl LocateKey { D: Deserializer<'de>, { Ok(match s.as_ref().trim() { - s if s.eq_ignore_ascii_case("cert") => LocateKey::CERT, - s if s.eq_ignore_ascii_case("pka") => LocateKey::PKA, - s if s.eq_ignore_ascii_case("dane") => LocateKey::DANE, - s if s.eq_ignore_ascii_case("wkd") => LocateKey::WKD, - s if s.eq_ignore_ascii_case("ldap") => LocateKey::LDAP, - s if s.eq_ignore_ascii_case("keyserver") => LocateKey::KEYSERVER, - s if s.eq_ignore_ascii_case("keyserver-url") => LocateKey::KEYSERVER_URL, - s if s.eq_ignore_ascii_case("local") => LocateKey::LOCAL, + s if s.eq_ignore_ascii_case("cert") => Self::CERT, + s if s.eq_ignore_ascii_case("pka") => Self::PKA, + s if s.eq_ignore_ascii_case("dane") => Self::DANE, + s if s.eq_ignore_ascii_case("wkd") => Self::WKD, + s if s.eq_ignore_ascii_case("ldap") => Self::LDAP, + s if s.eq_ignore_ascii_case("keyserver") => Self::KEYSERVER, + s if s.eq_ignore_ascii_case("keyserver-url") => Self::KEYSERVER_URL, + s if s.eq_ignore_ascii_case("local") => Self::LOCAL, combination if combination.contains(',') => { - let mut ret = LocateKey::NODEFAULT; + let mut ret = Self::NODEFAULT; for c in combination.trim().split(',') { ret |= Self::from_string_de::<'de, D, &str>(c.trim())?; } @@ -157,7 +156,7 @@ impl LocateKey { impl std::fmt::Display for LocateKey { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - if *self == LocateKey::NODEFAULT { + if *self == Self::NODEFAULT { write!(fmt, "clear,nodefault") } else { let mut accum = String::new(); @@ -169,13 +168,13 @@ impl std::fmt::Display for LocateKey { } }}; } - is_set!(LocateKey::CERT, "cert"); - is_set!(LocateKey::PKA, "pka"); - is_set!(LocateKey::WKD, "wkd"); - is_set!(LocateKey::LDAP, "ldap"); - is_set!(LocateKey::KEYSERVER, "keyserver"); - is_set!(LocateKey::KEYSERVER_URL, "keyserver-url"); - is_set!(LocateKey::LOCAL, "local"); + is_set!(Self::CERT, "cert"); + is_set!(Self::PKA, "pka"); + is_set!(Self::WKD, "wkd"); + is_set!(Self::LDAP, "ldap"); + is_set!(Self::KEYSERVER, "keyserver"); + is_set!(Self::KEYSERVER_URL, "keyserver-url"); + is_set!(Self::LOCAL, "local"); accum.pop(); write!(fmt, "{}", accum) } @@ -223,8 +222,7 @@ impl Context { pub fn new() -> Result { let lib = Arc::new(unsafe { libloading::Library::new(libloading::library_filename("gpgme")) }?); - if unsafe { call!(&lib, gpgme_check_version)(GPGME_VERSION.as_bytes().as_ptr() as *mut _) } - .is_null() + if unsafe { call!(&lib, gpgme_check_version)(GPGME_VERSION.as_bytes().as_ptr()) }.is_null() { return Err(Error::new(format!( "Could not use libgpgme: requested version compatible with {} but got {}", @@ -265,7 +263,7 @@ impl Context { gpgme_error_try(&lib, call!(&lib, gpgme_new)(&mut ptr))?; call!(&lib, gpgme_set_io_cbs)(ptr, &mut io_cbs); } - let ret = Context { + let ret = Self { inner: Arc::new(ContextInner { inner: core::ptr::NonNull::new(ptr) .ok_or_else(|| Error::new("Could not use libgpgme").set_kind(ErrorKind::Bug))?, @@ -586,7 +584,7 @@ impl Context { .map(|cs| cs.as_ptr()) .unwrap_or(std::ptr::null_mut()) as *const ::std::os::raw::c_char, - if secret { 1 } else { 0 }, + secret.into(), ), )?; } @@ -663,8 +661,9 @@ impl Context { call!(&ctx.lib, gpgme_op_keylist_end)(ctx.inner.as_ptr()), )?; } - let io_state_lck = io_state.lock().unwrap(); - io_state_lck + io_state + .lock() + .unwrap() .done .lock() .unwrap() @@ -782,13 +781,13 @@ impl Context { } })) .await; - let rcv = { - let io_state_lck = io_state.lock().unwrap(); - io_state_lck.receiver.clone() - }; - let _ = rcv.recv().await; - let io_state_lck = io_state.lock().unwrap(); - io_state_lck + { + let rcv = io_state.lock().unwrap().receiver.clone(); + let _ = rcv.recv().await; + } + io_state + .lock() + .unwrap() .done .lock() .unwrap() @@ -887,13 +886,11 @@ impl Context { } })) .await; - let rcv = { - let io_state_lck = io_state.lock().unwrap(); - io_state_lck.receiver.clone() - }; + let rcv = { io_state.lock().unwrap().receiver.clone() }; let _ = rcv.recv().await; - let io_state_lck = io_state.lock().unwrap(); - io_state_lck + io_state + .lock() + .unwrap() .done .lock() .unwrap() @@ -1097,13 +1094,11 @@ impl Context { } })) .await; - let rcv = { - let io_state_lck = io_state.lock().unwrap(); - io_state_lck.receiver.clone() - }; + let rcv = { io_state.lock().unwrap().receiver.clone() }; let _ = rcv.recv().await; - let io_state_lck = io_state.lock().unwrap(); - io_state_lck + io_state + .lock() + .unwrap() .done .lock() .unwrap() @@ -1230,7 +1225,7 @@ impl Clone for Key { unsafe { call!(&self.lib, gpgme_key_ref)(self.inner.inner.as_ptr()); } - Key { + Self { inner: self.inner.clone(), lib, } @@ -1240,7 +1235,7 @@ impl Clone for Key { impl Key { #[inline(always)] fn new(inner: KeyInner, lib: Arc) -> Self { - Key { inner, lib } + Self { inner, lib } } pub fn primary_uid(&self) -> Option
{ @@ -1319,7 +1314,7 @@ impl std::fmt::Debug for Key { } impl PartialEq for Key { - fn eq(&self, other: &Key) -> bool { + fn eq(&self, other: &Self) -> bool { self.fingerprint() == other.fingerprint() } } diff --git a/melib/src/lib.rs b/melib/src/lib.rs index 6c66c73f..d519f6e6 100644 --- a/melib/src/lib.rs +++ b/melib/src/lib.rs @@ -19,6 +19,41 @@ * along with meli. If not, see . */ +#![deny( + /* groups */ + clippy::correctness, + clippy::suspicious, + clippy::complexity, + clippy::perf, + clippy::cargo, + clippy::nursery, + clippy::style, + /* restriction */ + clippy::dbg_macro, + clippy::rc_buffer, + clippy::as_underscore, + clippy::assertions_on_result_states, + /* rustdoc */ + rustdoc::broken_intra_doc_links, + /* pedantic */ + //clippy::cast_lossless, + //clippy::cast_possible_wrap, + //clippy::ptr_as_ptr, + //clippy::bool_to_int_with_if, + clippy::borrow_as_ptr, + clippy::case_sensitive_file_extension_comparisons, + //clippy::cast_lossless, + //clippy::cast_ptr_alignment, +)] +#![allow( + clippy::option_if_let_else, + clippy::missing_const_for_fn, + clippy::significant_drop_tightening, + clippy::multiple_crate_versions, + clippy::significant_drop_in_scrutinee, + clippy::cognitive_complexity +)] + //! A crate that performs mail client operations such as //! - Hold an [`Envelope`](./email/struct.Envelope.html) with methods convenient //! for mail client use. (see module [`email`](./email/index.html)) diff --git a/melib/src/search.rs b/melib/src/search.rs index 9df959ea..38c006e5 100644 --- a/melib/src/search.rs +++ b/melib/src/search.rs @@ -138,7 +138,7 @@ impl QueryTrait for crate::Envelope { impl TryFrom<&str> for Query { type Error = crate::error::Error; - fn try_from(t: &str) -> crate::error::Result { + fn try_from(t: &str) -> crate::error::Result { query() .parse_complete(t) .map(|(_, q)| q) diff --git a/melib/src/sieve.rs b/melib/src/sieve.rs index c9fa53cd..356bb907 100644 --- a/melib/src/sieve.rs +++ b/melib/src/sieve.rs @@ -525,7 +525,7 @@ pub mod parser { either( map( right(ws(parse_token("exists")), ws(parse_string_list())), - |l| ConditionRule::Exists(l), + ConditionRule::Exists, ), map( right(ws(parse_token("size")), ws(parse_sieve_integer_operator())), @@ -540,12 +540,14 @@ pub mod parser { either(parse_sieve_header(), parse_sieve_address()), ), either( - map(right(ws(parse_token("allof")), parse_test_list()), |l| { - ConditionRule::AllOf(l) - }), - map(right(ws(parse_token("anyof")), parse_test_list()), |l| { - ConditionRule::AnyOf(l) - }), + map( + right(ws(parse_token("allof")), parse_test_list()), + ConditionRule::AllOf, + ), + map( + right(ws(parse_token("anyof")), parse_test_list()), + ConditionRule::AnyOf, + ), ), ), ), @@ -574,14 +576,14 @@ pub mod parser { either(parse_sieve_stop(), parse_sieve_require()), parse_sieve_if(), ), - |c| Rule::Control(c), + Rule::Control, ), map( either( either(parse_sieve_keep(), parse_sieve_fileinto()), either(parse_sieve_redirect(), parse_sieve_discard()), ), - |ac| Rule::Action(ac), + Rule::Action, ), ) } @@ -594,7 +596,7 @@ pub mod parser { ws(zero_or_more(parse_sieve_rule())), parse_token("}"), )), - |v| RuleBlock(v), + RuleBlock, ) .parse(input) } diff --git a/melib/src/smtp.rs b/melib/src/smtp.rs index a11982c2..64524238 100644 --- a/melib/src/smtp.rs +++ b/melib/src/smtp.rs @@ -157,7 +157,7 @@ pub struct SmtpAuthType { } impl SmtpAuth { - fn require_auth(&self) -> bool { + pub const fn require_auth(&self) -> bool { use SmtpAuth::*; match self { None => false, @@ -274,8 +274,8 @@ impl SmtpConnection { ) .await?; drop(pre_ehlo_extensions_reply); - //debug!(pre_ehlo_extensions_reply); - if let SmtpSecurity::Auto { .. } = server_conf.security { + + if matches!(server_conf.security, SmtpSecurity::Auto { .. }) { if server_conf.port == 465 { server_conf.security = SmtpSecurity::Tls { danger_accept_invalid_certs, @@ -292,7 +292,7 @@ impl SmtpConnection { } } socket.write_all(b"EHLO meli.delivery\r\n").await?; - if let SmtpSecurity::StartTLS { .. } = server_conf.security { + if matches!(server_conf.security, SmtpSecurity::StartTLS { .. }) { let pre_tls_extensions_reply = read_lines( &mut socket, &mut res, @@ -372,7 +372,7 @@ impl SmtpConnection { ret } }; - let mut ret = SmtpConnection { + let mut ret = Self { stream, read_buffer: String::new(), server_conf: server_conf.clone(), @@ -852,7 +852,7 @@ pub enum ReplyCode { } impl ReplyCode { - fn as_str(&self) -> &'static str { + pub const fn as_str(&self) -> &'static str { use ReplyCode::*; match self { _211 => "System status, or system help reply", @@ -893,7 +893,7 @@ impl ReplyCode { } } - fn is_err(&self) -> bool { + pub const fn is_err(&self) -> bool { use ReplyCode::*; matches!( self, @@ -920,7 +920,7 @@ impl ReplyCode { impl TryFrom<&'_ str> for ReplyCode { type Error = Error; - fn try_from(val: &'_ str) -> Result { + fn try_from(val: &'_ str) -> Result { if val.len() != 3 { debug!("{}", val); } @@ -981,12 +981,12 @@ impl<'s> Reply<'s> { /// code, a space or '-' and end with '\r\n' pub fn new(s: &'s str, code: ReplyCode) -> Self { let lines: SmallVec<_> = s.lines().map(|l| &l[4..l.len()]).collect(); - Reply { lines, code } + Self { lines, code } } } async fn read_lines<'r>( - _self: &mut (impl futures::io::AsyncRead + std::marker::Unpin), + _self: &mut (impl futures::io::AsyncRead + std::marker::Unpin + Send), ret: &'r mut String, expected_reply_code: Option<(ReplyCode, &[ReplyCode])>, buffer: &mut String, @@ -1069,7 +1069,10 @@ mod test { thread, }; - use mailin_embedded::{Handler, Response, Server, SslConfig}; + use mailin_embedded::{ + response::{INTERNAL_ERROR, OK}, + Handler, Response, Server, SslConfig, + }; use super::*; @@ -1096,12 +1099,13 @@ mod test { }, } + type QueuedMail = ((IpAddr, String), Message); + #[derive(Debug, Clone)] struct MyHandler { - mails: Arc>>, + mails: Arc>>, stored: Arc>>, } - use mailin_embedded::response::{INTERNAL_ERROR, OK}; impl Handler for MyHandler { fn helo(&mut self, ip: IpAddr, domain: &str) -> Response { @@ -1123,8 +1127,8 @@ mod test { .rev() .find(|((i, d), _)| (i, d.as_str()) == (&ip, domain)) { - std::dbg!(&message); - if let Message::Helo = message { + eprintln!("mail is {:?}", &message); + if matches!(message, Message::Helo) { *message = Message::Mail { from: from.to_string(), }; @@ -1137,7 +1141,7 @@ mod test { fn rcpt(&mut self, _to: &str) -> Response { eprintln!("rcpt() to {:?}", _to); if let Some((_, message)) = self.mails.lock().unwrap().last_mut() { - std::dbg!(&message); + eprintln!("rcpt mail is {:?}", &message); if let Message::Mail { from } = message { *message = Message::Rcpt { from: from.clone(), @@ -1167,7 +1171,7 @@ mod test { if d != _domain { return INTERNAL_ERROR; } - std::dbg!(&message); + eprintln!("data_start mail is {:?}", &message); if let Message::Rcpt { from, to } = message { *message = Message::DataStart { from: from.to_string(), @@ -1189,7 +1193,7 @@ mod test { }; return Ok(()); } else if let Message::Data { buf, .. } = message { - buf.extend(_buf.into_iter().copied()); + buf.extend(_buf.iter()); return Ok(()); } } @@ -1202,8 +1206,8 @@ mod test { for to in to { match crate::Envelope::from_bytes(&buf, None) { Ok(env) => { - std::dbg!(&env); - std::dbg!(env.other_headers()); + eprintln!("data_end env is {:?}", &env); + eprintln!("data_end env.other_headers is {:?}", env.other_headers()); self.stored.lock().unwrap().push((to.clone(), env)); } Err(err) => { diff --git a/melib/src/text_processing/line_break.rs b/melib/src/text_processing/line_break.rs index 6bbdb2f9..3758737f 100644 --- a/melib/src/text_processing/line_break.rs +++ b/melib/src/text_processing/line_break.rs @@ -32,19 +32,14 @@ use super::{ types::{LineBreakClass, Reflow}, }; -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Default, Debug, Eq, PartialEq, Copy, Clone)] pub enum LineBreakCandidate { MandatoryBreak, BreakAllowed, + #[default] NoBreak, // Not used. } -impl Default for LineBreakCandidate { - fn default() -> Self { - LineBreakCandidate::NoBreak - } -} - use LineBreakCandidate::*; pub struct LineBreakCandidateIter<'a> { @@ -1202,8 +1197,7 @@ fn reflow_helper( let paragraph = paragraph .trim_start_matches("es) .replace(&format!("\n{}", "es), "") - .replace('\n', "") - .replace('\r', ""); + .replace(['\n', '\r'], ""); if in_paragraph { if let Some(width) = width { ret.extend( @@ -1218,7 +1212,7 @@ fn reflow_helper( ret.push(format!("{}{}", "es, ¶graph)); } } else { - let paragraph = paragraph.replace('\n', "").replace('\r', ""); + let paragraph = paragraph.replace(['\n', '\r'], ""); if in_paragraph { if let Some(width) = width { @@ -1284,9 +1278,9 @@ mod segment_tree { } impl SegmentTree { - pub(super) fn new(val: SmallVec<[usize; 1024]>) -> SegmentTree { + pub(super) fn new(val: SmallVec<[usize; 1024]>) -> Self { if val.is_empty() { - return SegmentTree { + return Self { array: val.clone(), tree: val, }; @@ -1307,7 +1301,7 @@ mod segment_tree { segment_tree[i] = segment_tree[2 * i] + segment_tree[2 * i + 1]; } - SegmentTree { + Self { array: val, tree: segment_tree, } @@ -1382,15 +1376,15 @@ enum ReflowState { } impl ReflowState { - fn new(reflow: Reflow, width: Option, cur_index: usize) -> ReflowState { + fn new(reflow: Reflow, width: Option, cur_index: usize) -> Self { match reflow { - Reflow::All if width.is_some() => ReflowState::AllWidth { + Reflow::All if width.is_some() => Self::AllWidth { width: width.unwrap(), state: LineBreakTextState::AtLine { cur_index }, }, - Reflow::All => ReflowState::All { cur_index }, - Reflow::FormatFlowed => ReflowState::FormatFlowed { cur_index }, - Reflow::No => ReflowState::No { cur_index }, + Reflow::All => Self::All { cur_index }, + Reflow::FormatFlowed => Self::FormatFlowed { cur_index }, + Reflow::No => Self::No { cur_index }, } } } @@ -1418,7 +1412,7 @@ impl Default for LineBreakText { impl LineBreakText { pub fn new(text: String, reflow: Reflow, width: Option) -> Self { - LineBreakText { + Self { text, state: ReflowState::new(reflow, width, 0), paragraph: VecDeque::new(), @@ -1790,8 +1784,7 @@ fn reflow_helper2( let paragraph = paragraph .trim_start_matches("es) .replace(&format!("\n{}", "es), "") - .replace('\n', "") - .replace('\r', ""); + .replace(['\n', '\r'], ""); if in_paragraph { if let Some(width) = width { ret.extend( @@ -1806,7 +1799,7 @@ fn reflow_helper2( ret.push_back(format!("{}{}", "es, ¶graph)); } } else { - let paragraph = paragraph.replace('\n', "").replace('\r', ""); + let paragraph = paragraph.replace(['\n', '\r'], ""); if in_paragraph { if let Some(width) = width { diff --git a/melib/src/text_processing/mod.rs b/melib/src/text_processing/mod.rs index 1c445303..6abf148b 100644 --- a/melib/src/text_processing/mod.rs +++ b/melib/src/text_processing/mod.rs @@ -110,7 +110,7 @@ impl Truncate for String { .take(new_len) .last() { - String::truncate(self, last); + Self::truncate(self, last); } } @@ -170,11 +170,11 @@ pub trait GlobMatch { impl GlobMatch for str { fn matches_glob(&self, _pattern: &str) -> bool { - let pattern: Vec<&str> = _pattern + let pattern: Vec<&Self> = _pattern .strip_suffix('/') .unwrap_or(_pattern) .split_graphemes(); - let s: Vec<&str> = self.strip_suffix('/').unwrap_or(self).split_graphemes(); + let s: Vec<&Self> = self.strip_suffix('/').unwrap_or(self).split_graphemes(); // Taken from https://research.swtch.com/glob diff --git a/melib/src/text_processing/wcwidth.rs b/melib/src/text_processing/wcwidth.rs index cde86861..f4976f79 100644 --- a/melib/src/text_processing/wcwidth.rs +++ b/melib/src/text_processing/wcwidth.rs @@ -109,19 +109,16 @@ fn bisearch(ucs: WChar, table: &'static [Interval]) -> bool { pub fn wcwidth(ucs: WChar) -> Option { if bisearch(ucs, super::tables::ASCII) { Some(1) - } else if bisearch(ucs, super::tables::PRIVATE) { - None - } else if bisearch(ucs, super::tables::NONPRINT) { - None - } else if bisearch(ucs, super::tables::COMBINING) { + } else if bisearch(ucs, super::tables::PRIVATE) + || bisearch(ucs, super::tables::NONPRINT) + || bisearch(ucs, super::tables::COMBINING) + { None } else if bisearch(ucs, super::tables::DOUBLEWIDE) { Some(2) } else if bisearch(ucs, super::tables::AMBIGUOUS) { Some(1) - } else if bisearch(ucs, super::tables::UNASSIGNED) { - Some(2) - } else if bisearch(ucs, super::tables::WIDENEDIN9) { + } else if bisearch(ucs, super::tables::UNASSIGNED) || bisearch(ucs, super::tables::WIDENEDIN9) { Some(2) } else { Some(1) diff --git a/melib/src/thread.rs b/melib/src/thread.rs index 9ad634eb..b04243cf 100644 --- a/melib/src/thread.rs +++ b/melib/src/thread.rs @@ -88,7 +88,7 @@ macro_rules! uuid_hash_type { $n(Uuid::new_v4()) } - pub fn null() -> Self { + pub const fn null() -> Self { $n(Uuid::nil()) } } @@ -474,36 +474,26 @@ impl SubjectPrefix for &str { /* Sorting states. */ -#[derive(Debug, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)] pub enum SortOrder { Asc, + #[default] Desc, } -#[derive(Debug, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)] pub enum SortField { Subject, + #[default] Date, } -impl Default for SortField { - fn default() -> Self { - SortField::Date - } -} - -impl Default for SortOrder { - fn default() -> Self { - SortOrder::Desc - } -} - impl FromStr for SortField { type Err = (); fn from_str(s: &str) -> StdResult { match s.trim() { - "subject" | "s" | "sub" | "sbj" | "subj" => Ok(SortField::Subject), - "date" | "d" => Ok(SortField::Date), + "subject" | "s" | "sub" | "sbj" | "subj" => Ok(Self::Subject), + "date" | "d" => Ok(Self::Date), _ => Err(()), } } @@ -513,8 +503,8 @@ impl FromStr for SortOrder { type Err = (); fn from_str(s: &str) -> StdResult { match s.trim() { - "asc" => Ok(SortOrder::Asc), - "desc" => Ok(SortOrder::Desc), + "asc" => Ok(Self::Asc), + "desc" => Ok(Self::Desc), _ => Err(()), } } @@ -539,13 +529,13 @@ pub enum ThreadGroup { impl Default for ThreadGroup { fn default() -> Self { - ThreadGroup::Root(Thread::default()) + Self::Root(Thread::default()) } } impl ThreadGroup { pub fn root(&self) -> Option<&Thread> { - if let ThreadGroup::Root(ref root) = self { + if let Self::Root(ref root) = self { Some(root) } else { None @@ -594,8 +584,8 @@ pub struct ThreadNode { } impl Default for ThreadNode { - fn default() -> ThreadNode { - ThreadNode { + fn default() -> Self { + Self { message: None, parent: None, other_mailbox: false, @@ -610,7 +600,7 @@ impl Default for ThreadNode { impl ThreadNode { fn new() -> Self { - ThreadNode::default() + Self::default() } pub fn show_subject(&self) -> bool { @@ -672,7 +662,7 @@ pub struct Threads { } impl PartialEq for ThreadNode { - fn eq(&self, other: &ThreadNode) -> bool { + fn eq(&self, other: &Self) -> bool { match (self.message, other.message) { (Some(s), Some(o)) => s == o, _ => false, @@ -717,7 +707,7 @@ impl Threads { parent_group } - pub fn new(length: usize) -> Threads { + pub fn new(length: usize) -> Self { /* To reconstruct thread information from the mails we need: */ /* a vector to hold thread members */ @@ -739,7 +729,7 @@ impl Threads { let envelope_to_thread: HashMap = HashMap::with_capacity_and_hasher(length, Default::default()); - Threads { + Self { thread_nodes, message_ids, message_ids_set, @@ -775,6 +765,7 @@ impl Threads { } } + #[allow(clippy::result_unit_err)] pub fn update_envelope( &mut self, envelopes: &Envelopes, @@ -992,26 +983,23 @@ impl Threads { } let thread_hash = self.thread_nodes[&new_id].group; - if !self.groups.contains_key(&thread_hash) { - self.groups.insert( - thread_hash, - ThreadGroup::Root(Thread { - root: new_id, - date: envelopes_lck[&env_hash].date(), - len: 1, - unseen: if !envelopes_lck[&env_hash].is_seen() { - 1 - } else { - 0 - }, - attachments: if envelopes_lck[&env_hash].has_attachments() { - 1 - } else { - 0 - }, - snoozed: false, - }), - ); + if let std::collections::hash_map::Entry::Vacant(e) = self.groups.entry(thread_hash) { + e.insert(ThreadGroup::Root(Thread { + root: new_id, + date: envelopes_lck[&env_hash].date(), + len: 1, + unseen: if !envelopes_lck[&env_hash].is_seen() { + 1 + } else { + 0 + }, + attachments: if envelopes_lck[&env_hash].has_attachments() { + 1 + } else { + 0 + }, + snoozed: false, + })); } else { let parent_group = self.thread_ref_mut(thread_hash); parent_group.date = std::cmp::max(parent_group.date, envelopes_lck[&env_hash].date()); diff --git a/melib/src/utils/connections.rs b/melib/src/utils/connections.rs index 357b748a..cb6a5a86 100644 --- a/melib/src/utils/connections.rs +++ b/melib/src/utils/connections.rs @@ -68,7 +68,7 @@ impl Connection { pub const IO_BUF_SIZE: usize = 64 * 1024; #[cfg(feature = "deflate_compression")] pub fn deflate(self) -> Self { - Connection::Deflate { + Self::Deflate { inner: DeflateEncoder::new( DeflateDecoder::new_with_buf(Box::new(self), vec![0; Self::IO_BUF_SIZE]), Compression::default(), @@ -157,7 +157,7 @@ impl Connection { where T: Copy, { - let payload = &payload as *const T as *const c_void; + let payload = std::ptr::addr_of!(payload) as *const c_void; syscall!(setsockopt( self.as_raw_fd(), opt, @@ -175,7 +175,7 @@ impl Connection { self.as_raw_fd(), opt, val, - &mut slot as *mut _ as *mut _, + std::ptr::addr_of_mut!(slot) as *mut _, &mut len, ))?; assert_eq!(len as usize, std::mem::size_of::()); diff --git a/melib/src/utils/datetime.rs b/melib/src/utils/datetime.rs index 2ae1b401..8ba414e3 100644 --- a/melib/src/utils/datetime.rs +++ b/melib/src/utils/datetime.rs @@ -156,7 +156,7 @@ impl Locale { unsafe { libc::freelocale(new_locale) }; return Err(nix::Error::last().into()); } - Ok(Locale { + Ok(Self { mask, category, new_locale, @@ -190,7 +190,7 @@ pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>, posix: b let mut new_tm: libc::tm = unsafe { std::mem::zeroed() }; unsafe { let i: i64 = timestamp.try_into().unwrap_or(0); - localtime_r(&i as *const i64, &mut new_tm as *mut libc::tm); + localtime_r(std::ptr::addr_of!(i), std::ptr::addr_of_mut!(new_tm)); } let format: Cow<'_, CStr> = if let Some(cs) = fmt .map(str::as_bytes) @@ -230,7 +230,7 @@ pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>, posix: b vec.as_mut_ptr() as *mut _, 256, format.as_ptr(), - &new_tm as *const _, + std::ptr::addr_of!(new_tm), ) } }; @@ -320,7 +320,7 @@ fn year_to_secs(year: i64, is_leap: &mut bool) -> std::result::Result { } } -fn month_to_secs(month: usize, is_leap: bool) -> i64 { +const fn month_to_secs(month: usize, is_leap: bool) -> i64 { const SECS_THROUGH_MONTH: [i64; 12] = [ 0, 31 * 86400, @@ -359,7 +359,7 @@ where ) .chain_err_summary(|| "Could not set locale for datetime conversion") .chain_err_kind(crate::error::ErrorKind::External)?; - unsafe { strptime(s.as_ptr(), fmt.as_ptr(), &mut new_tm as *mut _) } + unsafe { strptime(s.as_ptr(), fmt.as_ptr(), std::ptr::addr_of_mut!(new_tm)) } }; if ret.is_null() { @@ -390,12 +390,15 @@ where rest.to_bytes() }; - if let Ok(idx) = TIMEZONE_ABBR.binary_search_by(|probe| probe.0.cmp(rest)) { - let (hr_offset, min_offset) = TIMEZONE_ABBR[idx].1; - (hr_offset as i64) * 60 * 60 + (min_offset as i64) * 60 - } else { - 0 - } + TIMEZONE_ABBR + .binary_search_by(|probe| probe.0.cmp(rest)) + .map_or_else( + |_| 0, + |idx| { + let (hr_offset, min_offset) = TIMEZONE_ABBR[idx].1; + (hr_offset as i64) * 60 * 60 + (min_offset as i64) * 60 + }, + ) }; return Ok(tm_to_secs(new_tm) .map(|res| (res - tm_gmtoff) as u64) @@ -421,7 +424,7 @@ where ) .chain_err_summary(|| "Could not set locale for datetime conversion") .chain_err_kind(crate::error::ErrorKind::External)?; - unsafe { strptime(s.as_ptr(), fmt.as_ptr(), &mut new_tm as *mut _) } + unsafe { strptime(s.as_ptr(), fmt.as_ptr(), std::ptr::addr_of_mut!(new_tm)) } }; if ret.is_null() { continue; @@ -452,12 +455,15 @@ where rest.to_bytes() }; - if let Ok(idx) = TIMEZONE_ABBR.binary_search_by(|probe| probe.0.cmp(rest)) { - let (hr_offset, min_offset) = TIMEZONE_ABBR[idx].1; - (hr_offset as i64) * 60 * 60 + (min_offset as i64) * 60 - } else { - 0 - } + TIMEZONE_ABBR + .binary_search_by(|probe| probe.0.cmp(rest)) + .map_or_else( + |_| 0, + |idx| { + let (hr_offset, min_offset) = TIMEZONE_ABBR[idx].1; + (hr_offset as i64) * 60 * 60 + (min_offset as i64) * 60 + }, + ) }; return Ok(tm_to_secs(new_tm) .map(|res| (res - tm_gmtoff) as u64) @@ -485,12 +491,15 @@ where }; unsafe { let val = CString::new(s)?; - let ret = strptime(val.as_ptr(), fmt.as_ptr(), &mut new_tm as *mut _); + let ret = strptime(val.as_ptr(), fmt.as_ptr(), std::ptr::addr_of_mut!(new_tm)); if ret.is_null() { return Err("Could not parse time with strptime.".into()); } let rest: isize = val.as_ptr().offset_from(ret); - Ok((rest.unsigned_abs(), mktime(&new_tm as *const _) as u64)) + Ok(( + rest.unsigned_abs(), + mktime(std::ptr::addr_of!(new_tm)) as u64, + )) } } @@ -711,8 +720,8 @@ mod tests { #[test] fn test_datetime_rfcs() { - if unsafe { libc::setlocale(libc::LC_ALL, b"\0".as_ptr() as _) }.is_null() { - println!("Unable to set locale."); + if unsafe { libc::setlocale(libc::LC_ALL, b"\0".as_ptr() as *const i8) }.is_null() { + eprintln!("Unable to set locale."); } /* Some tests were lazily stolen from https://rachelbythebay.com/w/2013/06/11/time/ */ diff --git a/melib/src/utils/futures.rs b/melib/src/utils/futures.rs index 1c100c58..fd928472 100644 --- a/melib/src/utils/futures.rs +++ b/melib/src/utils/futures.rs @@ -23,7 +23,10 @@ use std::time::Duration; use futures::future::{self, Either, Future}; -pub async fn timeout(dur: Option, f: impl Future) -> crate::Result { +pub async fn timeout( + dur: Option, + f: impl Future + Send, +) -> crate::Result { futures::pin_mut!(f); if let Some(dur) = dur { match future::select(f, smol::Timer::after(dur)).await { diff --git a/melib/src/utils/logging.rs b/melib/src/utils/logging.rs index 3b0478ad..4a6b0448 100644 --- a/melib/src/utils/logging.rs +++ b/melib/src/utils/logging.rs @@ -31,7 +31,7 @@ use std::{ use log::{Level, LevelFilter, Log, Metadata, Record}; -#[derive(Copy, Clone, Default, PartialEq, PartialOrd, Hash, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, Default, Eq, PartialEq, PartialOrd, Hash, Debug, Serialize, Deserialize)] #[repr(u8)] pub enum LogLevel { OFF = 0, @@ -46,12 +46,12 @@ pub enum LogLevel { impl From for LogLevel { fn from(verbosity: u8) -> Self { match verbosity { - 0 => LogLevel::OFF, - 1 => LogLevel::ERROR, - 2 => LogLevel::WARN, - 3 => LogLevel::INFO, - 4 => LogLevel::DEBUG, - _ => LogLevel::TRACE, + 0 => Self::OFF, + 1 => Self::ERROR, + 2 => Self::WARN, + 3 => Self::INFO, + 4 => Self::DEBUG, + _ => Self::TRACE, } } } @@ -125,7 +125,7 @@ impl std::fmt::Display for LogLevel { use LogLevel::*; -#[derive(Copy, Clone, Default, PartialEq, PartialOrd, Hash, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, Default, Eq, PartialEq, PartialOrd, Hash, Debug, Serialize, Deserialize)] pub enum Destination { File, #[default] @@ -175,8 +175,8 @@ impl StderrLogger { .create(true) /* a new file will be created if the file does not yet already exist.*/ .read(true) .open(data_dir.place_data_file("meli.log").unwrap()).unwrap(); - StderrLogger { - dest: Arc::new(Mutex::new(BufWriter::new(log_file).into())), + Self { + dest: Arc::new(Mutex::new(BufWriter::new(log_file))), level: Arc::new(AtomicU8::new(level as u8)), print_level: true, print_module_names: true, @@ -188,8 +188,8 @@ impl StderrLogger { }; #[cfg(test)] let logger = { - StderrLogger { - dest: Arc::new(Mutex::new(BufWriter::new(std::io::stderr()).into())), + Self { + dest: Arc::new(Mutex::new(BufWriter::new(std::io::stderr()))), level: Arc::new(AtomicU8::new(level as u8)), print_level: true, print_module_names: true, @@ -227,7 +227,7 @@ impl StderrLogger { *dest = BufWriter::new(OpenOptions::new().append(true) /* writes will append to a file instead of overwriting previous contents */ .create(true) /* a new file will be created if the file does not yet already exist.*/ .read(true) - .open(path).unwrap()).into(); + .open(path).unwrap()); } } @@ -279,7 +279,7 @@ impl Log for StderrLogger { self.debug_dest, record.metadata().level() <= Level::from(self.log_level()), ) { - (Destination::None, false) => return, + (Destination::None, false) => {} (Destination::None | Destination::File, _) => { _ = self.dest.lock().ok().and_then(|mut d| { write( diff --git a/melib/src/utils/parsec.rs b/melib/src/utils/parsec.rs index 6c16d23b..6ac4f4ff 100644 --- a/melib/src/utils/parsec.rs +++ b/melib/src/utils/parsec.rs @@ -104,11 +104,7 @@ where { move |input| { parser.parse(input).and_then(|(next_input, result)| { - if let Ok(res) = map_fn(result) { - Ok((next_input, res)) - } else { - Err(next_input) - } + map_fn(result).map_or_else(|_| Err(next_input), |res| Ok((next_input, res))) }) } } @@ -387,10 +383,10 @@ where } pub fn any_char(input: &str) -> Result { - match input.chars().next() { - Some(next) => Ok((&input[next.len_utf8()..], next)), - _ => Err(input), - } + input + .chars() + .next() + .map_or_else(|| Err(input), |next| Ok((&input[next.len_utf8()..], next))) } pub fn string<'a>() -> impl Parser<'a, String> { @@ -615,7 +611,7 @@ pub fn date<'a, T: Into>>(fmt: T) -> impl Parser<'a, UnixTimes pub fn integer<'a>() -> impl Parser<'a, usize> { use std::str::FromStr; - map_res(is_a(b"0123456789"), |s| usize::from_str(s)) + map_res(is_a(b"0123456789"), usize::from_str) } #[cfg(test)] @@ -628,12 +624,12 @@ mod test { fn test_parsec() { #[derive(Debug, PartialEq)] enum JsonValue { - JsonString(String), - JsonNumber(f64), - JsonBool(bool), - JsonNull, - JsonObject(HashMap), - JsonArray(Vec), + String(String), + Number(f64), + Bool(bool), + Null, + Object(HashMap), + Array(Vec), } fn parse_value<'a>() -> impl Parser<'a, JsonValue> { @@ -643,16 +639,16 @@ mod test { either( either( either( - map(parse_bool(), JsonValue::JsonBool), - map(parse_null(), |()| JsonValue::JsonNull), + map(parse_bool(), JsonValue::Bool), + map(parse_null(), |()| JsonValue::Null), ), - map(parse_array(), JsonValue::JsonArray), + map(parse_array(), JsonValue::Array), ), - map(parse_object(), JsonValue::JsonObject), + map(parse_object(), JsonValue::Object), ), - map(parse_number(), JsonValue::JsonNumber), + map(parse_number(), JsonValue::Number), ), - map(quoted_string(), JsonValue::JsonString), + map(quoted_string(), JsonValue::String), ) .parse(input) } @@ -714,15 +710,15 @@ mod test { } } assert_eq!( - Ok(("", JsonValue::JsonString("a".to_string()))), + Ok(("", JsonValue::String("a".to_string()))), parse_value().parse(r#""a""#) ); assert_eq!( - Ok(("", JsonValue::JsonBool(true))), + Ok(("", JsonValue::Bool(true))), parse_value().parse(r#"true"#) ); assert_eq!( - Ok(("", JsonValue::JsonObject(HashMap::default()))), + Ok(("", JsonValue::Object(HashMap::default()))), parse_value().parse(r#"{}"#) ); println!("{:?}", parse_value().parse(r#"{"a":true}"#)); diff --git a/melib/src/utils/percent_encoding.rs b/melib/src/utils/percent_encoding.rs index da93f7f1..28ed54d7 100644 --- a/melib/src/utils/percent_encoding.rs +++ b/melib/src/utils/percent_encoding.rs @@ -80,20 +80,20 @@ impl AsciiSet { (chunk & mask) != 0 } - fn should_percent_encode(&self, byte: u8) -> bool { + const fn should_percent_encode(&self, byte: u8) -> bool { !byte.is_ascii() || self.contains(byte) } pub const fn add(&self, byte: u8) -> Self { let mut mask = self.mask; mask[byte as usize / BITS_PER_CHUNK] |= 1 << (byte as usize % BITS_PER_CHUNK); - AsciiSet { mask } + Self { mask } } pub const fn remove(&self, byte: u8) -> Self { let mut mask = self.mask; mask[byte as usize / BITS_PER_CHUNK] &= !(1 << (byte as usize % BITS_PER_CHUNK)); - AsciiSet { mask } + Self { mask } } } @@ -114,7 +114,7 @@ pub const CONTROLS: &AsciiSet = &AsciiSet { macro_rules! static_assert { ($( $bool: expr, )+) => { - fn _static_assert() { + const fn _static_assert() { $( let _ = mem::transmute::<[u8; $bool as usize], u8>; )+ @@ -236,7 +236,10 @@ pub fn percent_encode_byte(byte: u8) -> &'static str { /// ); /// ``` #[inline] -pub fn percent_encode<'a>(input: &'a [u8], ascii_set: &'static AsciiSet) -> PercentEncode<'a> { +pub const fn percent_encode<'a>( + input: &'a [u8], + ascii_set: &'static AsciiSet, +) -> PercentEncode<'a> { PercentEncode { bytes: input, ascii_set, @@ -317,18 +320,20 @@ impl<'a> fmt::Display for PercentEncode<'a> { impl<'a> From> for Cow<'a, str> { fn from(mut iter: PercentEncode<'a>) -> Self { - match iter.next() { - None => "".into(), - Some(first) => match iter.next() { - None => first.into(), - Some(second) => { - let mut string = first.to_owned(); - string.push_str(second); - string.extend(iter); - string.into() - } + iter.next().map_or_else( + || "".into(), + |first| { + iter.next().map_or_else( + || first.into(), + |second| { + let mut string = first.to_owned(); + string.push_str(second); + string.extend(iter); + string.into() + }, + ) }, - } + ) } } @@ -474,7 +479,7 @@ fn decode_utf8_lossy(input: Cow<'_, [u8]>) -> Cow<'_, str> { // First we do a debug_assert to confirm our description above. let raw_utf8: *const [u8] = utf8.as_bytes(); - debug_assert!(raw_utf8 == &*bytes as *const [u8]); + debug_assert!(raw_utf8 == std::ptr::addr_of!(*bytes)); // Given we know the original input bytes are valid UTF-8, // and we have ownership of those bytes, we re-use them and diff --git a/melib/src/utils/shellexpand.rs b/melib/src/utils/shellexpand.rs index 4be4bfd9..395d5766 100644 --- a/melib/src/utils/shellexpand.rs +++ b/melib/src/utils/shellexpand.rs @@ -71,8 +71,11 @@ impl ShellExpandTrait for Path { #[cfg(target_os = "linux")] fn complete(&self, force: bool) -> SmallVec<[String; 128]> { + use std::convert::TryFrom; + use libc::dirent64; use nix::fcntl::OFlag; + const BUF_SIZE: ::libc::size_t = 8 << 10; let (prefix, _match) = if self.as_os_str().as_bytes().ends_with(b"/.") { @@ -126,13 +129,13 @@ impl ShellExpandTrait for Path { BUF_SIZE - 256, ) }; - if n < 0 { - return SmallVec::new(); - } else if n == 0 { - break; - } - let n = n as usize; + let Ok(n) = usize::try_from(n) else { + if n == 0 { + break; + } + return SmallVec::new(); + }; unsafe { buf.set_len(n); } @@ -140,23 +143,24 @@ impl ShellExpandTrait for Path { while pos < n { let dir = unsafe { std::mem::transmute::<&[u8], &[dirent64]>(&buf[pos..]) }; let entry = unsafe { std::ffi::CStr::from_ptr(dir[0].d_name.as_ptr()) }; - if entry.to_bytes() != b"." && entry.to_bytes() != b".." { - if entry.to_bytes().starts_with(_match.as_bytes()) { - if dir[0].d_type == ::libc::DT_DIR && !entry.to_bytes().ends_with(b"/") { - let mut s = unsafe { - String::from_utf8_unchecked( - entry.to_bytes()[_match.as_bytes().len()..].to_vec(), - ) - }; - s.push('/'); - entries.push(s); - } else { - entries.push(unsafe { - String::from_utf8_unchecked( - entry.to_bytes()[_match.as_bytes().len()..].to_vec(), - ) - }); - } + if entry.to_bytes() != b"." + && entry.to_bytes() != b".." + && entry.to_bytes().starts_with(_match.as_bytes()) + { + if dir[0].d_type == ::libc::DT_DIR && !entry.to_bytes().ends_with(b"/") { + let mut s = unsafe { + String::from_utf8_unchecked( + entry.to_bytes()[_match.as_bytes().len()..].to_vec(), + ) + }; + s.push('/'); + entries.push(s); + } else { + entries.push(unsafe { + String::from_utf8_unchecked( + entry.to_bytes()[_match.as_bytes().len()..].to_vec(), + ) + }); } } pos += dir[0].d_reclen as usize; @@ -198,7 +202,7 @@ impl ShellExpandTrait for Path { entries.push("/".to_string()); } - if let Ok(iter) = std::fs::read_dir(&prefix) { + if let Ok(iter) = std::fs::read_dir(prefix) { for entry in iter.flatten() { if entry.path().as_os_str().as_bytes() != b"." && entry.path().as_os_str().as_bytes() != b".." diff --git a/melib/src/utils/sqlite3.rs b/melib/src/utils/sqlite3.rs index ad590f78..a50762bf 100644 --- a/melib/src/utils/sqlite3.rs +++ b/melib/src/utils/sqlite3.rs @@ -54,19 +54,17 @@ pub fn open_or_create_db( ) -> Result { let mut second_try: bool = false; loop { - let db_path = if let Some(id) = identifier { - db_path(&format!("{}_{}", id, description.name)) - } else { - db_path(description.name) - }?; - let mut set_mode = false; - if !db_path.exists() { + let db_path = identifier.map_or_else( + || db_path(description.name), + |id| db_path(&format!("{}_{}", id, description.name)), + )?; + let set_mode = !db_path.exists(); + if set_mode { log::info!( "Creating {} database in {}", description.name, db_path.display() ); - set_mode = true; } let conn = Connection::open(&db_path).map_err(|e| Error::new(e.to_string()))?; if set_mode { @@ -112,11 +110,10 @@ pub fn open_or_create_db( /// Return database to a clean slate. pub fn reset_db(description: &DatabaseDescription, identifier: Option<&str>) -> Result<()> { - let db_path = if let Some(id) = identifier { - db_path(&format!("{}_{}", id, description.name)) - } else { - db_path(description.name) - }?; + let db_path = identifier.map_or_else( + || db_path(description.name), + |id| db_path(&format!("{}_{}", id, description.name)), + )?; if !db_path.exists() { return Ok(()); } diff --git a/tools/Cargo.toml b/tools/Cargo.toml index e0c766a2..d2f71252 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -4,6 +4,12 @@ version = "0.4.1" authors = ["Manos Pitsidianakis "] workspace = ".." edition = "2018" +rust-version = "1.65.0" + +license = "GPL-3.0-or-later" +homepage = "https://meli.delivery" +repository = "https://git.meli.delivery/meli/meli.git" +publish = false [[bin]] name = "emailparse"