melib: clippy lint fixes

pull/237/head
Manos Pitsidianakis 2023-07-01 16:34:06 +03:00
parent 6858ee1fab
commit 5f29faa640
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
70 changed files with 1290 additions and 1194 deletions

View File

@ -18,6 +18,12 @@
# along with meli. If not, see <http://www.gnu.org/licenses/>.
.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

View File

@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
#![allow(clippy::needless_range_loop)]
#[cfg(feature = "unicode_algorithms")]
include!("src/text_processing/types.rs");

View File

@ -41,22 +41,37 @@ pub enum CardId {
Hash(u64),
}
impl Into<String> 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<CardId> for String {
fn from(val: CardId) -> Self {
val.to_string()
}
}
impl From<String> 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<HashMap<String, String>> for Card {
fn from(mut map: HashMap<String, String>) -> Card {
let mut card = Card::new();
fn from(mut map: HashMap<String, String>) -> Self {
let mut card = Self::new();
if let Some(val) = map.remove("TITLE") {
card.title = val;
}

View File

@ -84,7 +84,7 @@ pub struct ContentLine {
}
impl CardDeserializer {
pub fn from_str(mut input: &str) -> Result<VCard<impl VCardVersion>> {
pub fn try_from_str(mut input: &str) -> Result<VCard<impl VCardVersion>> {
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<Vec<Card>> {
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<Vec<Card>> {
#[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()
);
}

View File

@ -86,6 +86,8 @@ pub type BackendCreator = Box<
) -> Result<Box<dyn MailBackend>>,
>;
pub type BackendValidateConfigFn = Box<dyn Fn(&mut AccountSettings) -> 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<dyn Fn() -> BackendCreator>,
pub validate_conf_fn: Box<dyn Fn(&mut AccountSettings) -> 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<Error> 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<dyn Fn(AccountHash, BackendEvent) + Send + Sync>);
impl BackendEventConsumer {
pub fn new(b: Arc<dyn Fn(AccountHash, BackendEvent) + Send + Sync>) -> 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<dyn BackendOp>) -> Box<dyn BackendOp> {
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<SpecialUsageMailbox> {
pub fn detect_usage(name: &str) -> Option<Self> {
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<EnvelopeHash> 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<BTreeSet<EnvelopeHash>> for &EnvelopeHashBatch {
fn into(self) -> BTreeSet<EnvelopeHash> {
self.iter().collect::<BTreeSet<EnvelopeHash>>()
impl From<&EnvelopeHashBatch> for BTreeSet<EnvelopeHash> {
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

View File

@ -146,7 +146,7 @@ macro_rules! get_conf_val {
#[derive(Debug)]
pub struct UIDStore {
account_hash: AccountHash,
account_name: Arc<String>,
account_name: Arc<str>,
keep_offline_cache: bool,
capabilities: Arc<Mutex<Capabilities>>,
hash_index: Arc<Mutex<HashMap<EnvelopeHash, (UID, MailboxHash)>>>,
@ -171,11 +171,11 @@ pub struct UIDStore {
impl UIDStore {
fn new(
account_hash: AccountHash,
account_name: Arc<String>,
account_name: Arc<str>,
event_consumer: BackendEventConsumer,
timeout: Option<Duration>,
) -> 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<dyn Fn(&str) -> 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<UIDStore> = 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<Vec<Envelope>> {
}
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);
}
}

View File

@ -34,9 +34,9 @@ pub struct ModSequence(pub std::num::NonZeroU64);
impl TryFrom<i64> for ModSequence {
type Error = ();
fn try_from(val: i64) -> std::result::Result<ModSequence, ()> {
fn try_from(val: i64) -> std::result::Result<Self, ()> {
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<Option<()>> {
@ -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::<std::result::Result<_, _>>()?;

View File

@ -32,7 +32,7 @@ impl ImapConnection {
pub async fn resync(&mut self, mailbox_hash: MailboxHash) -> Result<Option<Vec<Envelope>>> {
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:<lastseenuid> FLAGS
// 3. tag2 UID FETCH 1:<lastseenuid> 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 <lastseenuid+1>:* <descriptors>
// 2. tag1 UID FETCH <lastseenuid+1>:* <descriptors>
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:<lastseenuid> FLAGS
// 3. tag2 UID FETCH 1:<lastseenuid> 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 <cached-value>)" or
// "SEARCH MODSEQ <cached-value>".
// 2. tag1 UID FETCH <lastseenuid+1>:* <descriptors>
// 2. tag1 UID FETCH <lastseenuid+1>:* <descriptors>
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:<lastseenuid> FLAGS
// 3. tag2 UID FETCH 1:<lastseenuid> 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::<BTreeSet<EnvelopeHash>>()
.difference(&valid_envs)
{
.collect::<BTreeSet<EnvelopeHash>>();
for env_hash in olds.difference(&valid_envs) {
refresh_events.push((
env_lck[env_hash].uid,
RefreshEvent {

View File

@ -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<UIDStore>,
) -> ImapConnection {
ImapConnection {
) -> Self {
Self {
stream: Err(Error::new("Offline".to_string())),
#[cfg(debug_assertions)]
id,
@ -1167,7 +1167,7 @@ pub struct ImapBlockingConnection {
impl From<ImapConnection> 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<Output = Option<Vec<u8>>> + 'a {
pub fn as_stream(&mut self) -> impl Future<Output = Option<Vec<u8>>> + '_ {
self.result.drain(0..self.prev_res_length);
self.prev_res_length = 0;
let mut break_flag = false;

View File

@ -32,8 +32,8 @@ use crate::error::{Error, ErrorKind};
impl From<LiteralError> 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<LiteralError> for Error {
impl From<SequenceSetError> 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<S, L>: fmt::Debug + fmt::Display + Sync + Send + 'static,
{
#[inline]
fn from(error: AppendError<S, L>) -> Error {
Error {
fn from(error: AppendError<S, L>) -> Self {
Self {
summary: error.to_string().into(),
details: None,
source: Some(Arc::new(error)),
@ -74,8 +74,8 @@ where
CopyError<S, L>: fmt::Debug + fmt::Display + Sync + Send + 'static,
{
#[inline]
fn from(error: CopyError<S, L>) -> Error {
Error {
fn from(error: CopyError<S, L>) -> Self {
Self {
summary: error.to_string().into(),
details: None,
source: Some(Arc::new(error)),
@ -89,8 +89,8 @@ where
MoveError<S, M>: fmt::Debug + fmt::Display + Sync + Send + 'static,
{
#[inline]
fn from(error: MoveError<S, M>) -> Error {
Error {
fn from(error: MoveError<S, M>) -> Self {
Self {
summary: error.to_string().into(),
details: None,
source: Some(Arc::new(error)),
@ -104,8 +104,8 @@ where
ListError<L1, L2>: fmt::Debug + fmt::Display + Sync + Send + 'static,
{
#[inline]
fn from(error: ListError<L1, L2>) -> Error {
Error {
fn from(error: ListError<L1, L2>) -> Self {
Self {
summary: error.to_string().into(),
details: None,
source: Some(Arc::new(error)),

View File

@ -328,7 +328,7 @@ impl ManageSieveConnection {
))),
..UIDStore::new(
account_hash,
Arc::new(account_name),
account_name.into(),
event_consumer,
server_conf.timeout,
)

View File

@ -42,7 +42,7 @@ impl ImapOp {
connection: Arc<FutureMutex<ImapConnection>>,
uid_store: Arc<UIDStore>,
) -> Self {
ImapOp {
Self {
uid,
connection,
mailbox_hash,

View File

@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
#![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<Alert>)>;
@ -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<ImapResponse> {
fn try_from(val: &'_ [u8]) -> Result<Self> {
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<Result<()>> 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<ImapResponse> 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<UID>,
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("<xx@xx.com>".as_bytes());
env.set_message_id(b"<xx@xx.com>");
assert_eq!(
fetch_response(input).unwrap(),
(

View File

@ -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::<Vec<(UID, crate::email::EnvelopeHash)>>()
{
.collect::<Vec<(UID, crate::email::EnvelopeHash)>>();
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);
}
}

View File

@ -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);
}
}

View File

@ -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<ImportError> =
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<Id<EmailObject>, Value> = HashMap::default();
let mut ids: Vec<Id<EmailObject>> = Vec::with_capacity(env_hashes.rest.len() + 1);
let mut id_map: HashMap<Id<EmailObject>, EnvelopeHash> = HashMap::default();
let mut update_keywords: HashMap<String, Value> = 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::<EmailObject>::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::<EmailObject>::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<dyn Fn(&str) -> 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(())

View File

@ -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() {

View File

@ -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,

View File

@ -211,7 +211,7 @@ where
T: Deserialize<'de> + Default,
{
let v = Option::<T>::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<String>,
}
impl Into<crate::email::Address> for EmailAddress {
fn into(self) -> crate::email::Address {
let Self { email, mut name } = self;
impl From<EmailAddress> 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<EmailObject> 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<EmailObject> 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::<SmallVec<[crate::email::Address; 1]>>(),
@ -306,7 +306,7 @@ impl std::convert::From<EmailObject> 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::<SmallVec<[crate::email::Address; 1]>>(),
@ -315,7 +315,7 @@ impl std::convert::From<EmailObject> 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::<SmallVec<[crate::email::Address; 1]>>(),
@ -324,17 +324,15 @@ impl std::convert::From<EmailObject> 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::<Vec<crate::email::Address>>(),
);
}
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<EmailObject> for EmailQuery {
}
impl EmailQuery {
pub const RESULT_FIELD_IDS: ResultField<EmailQuery, EmailObject> =
ResultField::<EmailQuery, EmailObject> {
field: "/ids",
_ph: PhantomData,
};
pub const RESULT_FIELD_IDS: ResultField<Self, EmailObject> = ResultField::<Self, EmailObject> {
field: "/ids",
_ph: PhantomData,
};
pub fn new(query_call: Query<Filter<EmailFilterCondition, EmailObject>, EmailObject>) -> Self {
EmailQuery {
Self {
query_call,
collapse_threads: false,
}
@ -454,7 +451,7 @@ impl Method<EmailObject> for EmailGet {
impl EmailGet {
pub fn new(get_call: Get<EmailObject>) -> Self {
EmailGet {
Self {
get_call,
body_properties: Vec::new(),
fetch_text_body_values: false,
@ -548,8 +545,8 @@ impl EmailFilterCondition {
impl FilterTrait<EmailObject> for EmailFilterCondition {}
impl From<EmailFilterCondition> for FilterCondition<EmailFilterCondition, EmailObject> {
fn from(val: EmailFilterCondition) -> FilterCondition<EmailFilterCondition, EmailObject> {
FilterCondition {
fn from(val: EmailFilterCondition) -> Self {
Self {
cond: val,
_ph: PhantomData,
}
@ -586,7 +583,7 @@ pub enum MessageProperty {
impl From<crate::search::Query> for Filter<EmailFilterCondition, EmailObject> {
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<EmailFilterCondition, EmailObject>) {
use datetime::{formats::RFC3339_DATE, timestamp_to_string};
@ -813,7 +810,7 @@ impl Method<EmailObject> for EmailSet {
impl EmailSet {
pub fn new(set_call: Set<EmailObject>) -> Self {
EmailSet { set_call }
Self { set_call }
}
}
@ -830,7 +827,7 @@ impl Method<EmailObject> for EmailChanges {
impl EmailChanges {
pub fn new(changes_call: Changes<EmailObject>) -> Self {
EmailChanges { changes_call }
Self { changes_call }
}
}
@ -849,7 +846,7 @@ impl EmailQueryChanges {
pub fn new(
query_changes_call: QueryChanges<Filter<EmailFilterCondition, EmailObject>, 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<EmailQueryChangesResponse> {
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<Self> {
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)
}

View File

@ -90,6 +90,12 @@ impl ImportCall {
_impl!(emails: HashMap<Id<EmailObject>, EmailImport>);
}
impl Default for ImportCall {
fn default() -> Self {
Self::new()
}
}
impl Method<EmailObject> for ImportCall {
const NAME: &'static str = "Email/import";
}
@ -110,6 +116,12 @@ impl EmailImport {
_impl!(received_at: Option<String>);
}
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<ImportResponse> {
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<Self> {
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)
}

View File

@ -68,7 +68,7 @@ pub struct MailboxGet {
}
impl MailboxGet {
pub fn new(get_call: Get<MailboxObject>) -> Self {
MailboxGet { get_call }
Self { get_call }
}
}

View File

@ -37,7 +37,7 @@ impl JmapOp {
connection: Arc<FutureMutex<JmapConnection>>,
store: Arc<Store>,
) -> Self {
JmapOp {
Self {
hash,
connection,
store,

View File

@ -63,7 +63,7 @@ pub struct Request {
impl Request {
pub fn new(request_no: Arc<Mutex<usize>>) -> Self {
Request {
Self {
using: USING,
method_calls: Vec::new(),
request_no,
@ -177,7 +177,7 @@ pub async fn get_mailboxes(conn: &JmapConnection) -> Result<HashMap<MailboxHash,
})
.collect();
for key in ret.keys().cloned().collect::<SmallVec<[MailboxHash; 24]>>() {
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<Vec<Id<EmailObject>>> {
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);

View File

@ -72,7 +72,7 @@ impl core::fmt::Debug for Id<String> {
//, Hash, Eq, PartialEq, Default)]
impl<OBJ> Clone for Id<OBJ> {
fn clone(&self) -> Self {
Id {
Self {
inner: self.inner.clone(),
_ph: PhantomData,
}
@ -101,7 +101,7 @@ impl<OBJ> Default for Id<OBJ> {
impl<OBJ> From<String> for Id<OBJ> {
fn from(inner: String) -> Self {
Id {
Self {
inner,
_ph: PhantomData,
}
@ -146,7 +146,7 @@ pub struct State<OBJ> {
//, Hash, Eq, PartialEq, Default)]
impl<OBJ> Clone for State<OBJ> {
fn clone(&self) -> Self {
State {
Self {
inner: self.inner.clone(),
_ph: PhantomData,
}
@ -175,7 +175,7 @@ impl<OBJ> Default for State<OBJ> {
impl<OBJ> From<String> for State<OBJ> {
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<OBJ: Object>
pub struct Get<OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
pub account_id: Id<Account>,
#[serde(skip_serializing_if = "Option::is_none")]
@ -298,9 +298,9 @@ where
_ph: PhantomData<fn() -> OBJ>,
}
impl<OBJ: Object> Get<OBJ>
impl<OBJ> Get<OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
pub fn new() -> Self {
Self {
@ -339,6 +339,15 @@ where
);
}
impl<OBJ> Default for Get<OBJ>
where
OBJ: Object + std::fmt::Debug + Serialize,
{
fn default() -> Self {
Self::new()
}
}
impl<OBJ: Object + Serialize + std::fmt::Debug> Serialize for Get<OBJ> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -417,17 +426,16 @@ pub struct GetResponse<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for GetResponse<OBJ> {
type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<GetResponse<OBJ>, crate::error::Error> {
let res: (String, GetResponse<OBJ>, 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<Self, crate::error::Error> {
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<F: FilterTrait<OBJ>, OBJ: Object>
pub struct Query<F: FilterTrait<OBJ>, OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
pub account_id: Id<Account>,
pub filter: Option<F>,
@ -472,9 +480,9 @@ where
_ph: PhantomData<fn() -> OBJ>,
}
impl<F: FilterTrait<OBJ>, OBJ: Object> Query<F, OBJ>
impl<F: FilterTrait<OBJ>, OBJ> Query<F, OBJ>
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<F: FilterTrait<OBJ>, OBJ> Default for Query<F, OBJ>
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<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for QueryResponse<OBJ> {
type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<QueryResponse<OBJ>, crate::error::Error> {
let res: (String, QueryResponse<OBJ>, 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<Self, crate::error::Error> {
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<M: Method<OBJ>, OBJ: Object> {
impl<M: Method<OBJ>, OBJ: Object> ResultField<M, OBJ> {
pub fn new(field: &'static str) -> Self {
ResultField {
Self {
field,
_ph: PhantomData,
}
@ -604,9 +620,9 @@ impl<M: Method<OBJ>, OBJ: Object> ResultField<M, OBJ> {
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
/* ch-ch-ch-ch-ch-Changes */
pub struct Changes<OBJ: Object>
pub struct Changes<OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
pub account_id: Id<Account>,
pub since_state: State<OBJ>,
@ -616,9 +632,9 @@ where
_ph: PhantomData<fn() -> OBJ>,
}
impl<OBJ: Object> Changes<OBJ>
impl<OBJ> Changes<OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
pub fn new() -> Self {
Self {
@ -654,6 +670,15 @@ where
);
}
impl<OBJ> Default for Changes<OBJ>
where
OBJ: Object + std::fmt::Debug + Serialize,
{
fn default() -> Self {
Self::new()
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ChangesResponse<OBJ: Object> {
@ -670,17 +695,16 @@ pub struct ChangesResponse<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for ChangesResponse<OBJ> {
type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<ChangesResponse<OBJ>, crate::error::Error> {
let res: (String, ChangesResponse<OBJ>, 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<Self, crate::error::Error> {
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<OBJ: Object> ChangesResponse<OBJ> {
///record type).
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Set<OBJ: Object>
pub struct Set<OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
///o accountId: "Id"
///
@ -785,9 +809,9 @@ where
pub destroy: Option<Vec<Id<OBJ>>>,
}
impl<OBJ: Object> Set<OBJ>
impl<OBJ> Set<OBJ>
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<HashMap<Id<OBJ>, Value>>);
}
impl<OBJ> Default for Set<OBJ>
where
OBJ: Object + std::fmt::Debug + Serialize,
{
fn default() -> Self {
Self::new()
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct SetResponse<OBJ: Object> {
@ -876,17 +909,16 @@ pub struct SetResponse<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for SetResponse<OBJ> {
type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<SetResponse<OBJ>, crate::error::Error> {
let res: (String, SetResponse<OBJ>, 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<Self, crate::error::Error> {
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<F: FilterTrait<OBJ>, OBJ: Object>
pub struct QueryChanges<F: FilterTrait<OBJ>, OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
pub account_id: Id<Account>,
pub filter: Option<F>,
@ -1114,9 +1146,9 @@ where
_ph: PhantomData<fn() -> OBJ>,
}
impl<F: FilterTrait<OBJ>, OBJ: Object> QueryChanges<F, OBJ>
impl<F: FilterTrait<OBJ>, OBJ> QueryChanges<F, OBJ>
where
OBJ: std::fmt::Debug + Serialize,
OBJ: Object + std::fmt::Debug + Serialize,
{
pub fn new(account_id: Id<Account>, since_query_state: String) -> Self {
Self {

View File

@ -37,7 +37,7 @@ pub enum JmapArgument<T> {
impl<T> JmapArgument<T> {
pub fn value(v: T) -> Self {
JmapArgument::Value(v)
Self::Value(v)
}
pub fn reference<M, OBJ>(result_of: usize, path: ResultField<M, OBJ>) -> Self
@ -45,7 +45,7 @@ impl<T> JmapArgument<T> {
M: Method<OBJ>,
OBJ: Object,
{
JmapArgument::ResultReference {
Self::ResultReference {
result_of: format!("m{}", result_of),
name: M::NAME.to_string(),
path: path.field.to_string(),

View File

@ -51,3 +51,9 @@ impl<OBJ: Object> Comparator<OBJ> {
_impl!(collation: Option<String>);
_impl!(additional_properties: Vec<String>);
}
impl<OBJ: Object> Default for Comparator<OBJ> {
fn default() -> Self {
Self::new()
}
}

View File

@ -44,7 +44,7 @@ pub struct FilterCondition<F: FilterTrait<OBJ>, OBJ: Object> {
pub _ph: PhantomData<fn() -> 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<F: FilterTrait<OBJ>, OBJ: Object> FilterCondition<F, OBJ> {
pub fn new() -> Self {
FilterCondition {
Self {
cond: F::default(),
_ph: PhantomData,
}
@ -69,7 +69,7 @@ impl<F: FilterTrait<OBJ>, OBJ: Object> Default for FilterCondition<F, OBJ> {
impl<F: FilterTrait<OBJ>, OBJ: Object> Default for Filter<F, OBJ> {
fn default() -> Self {
Filter::Condition(FilterCondition::default())
Self::Condition(FilterCondition::default())
}
}
@ -78,17 +78,17 @@ use std::ops::{BitAndAssign, BitOrAssign, Not};
impl<F: FilterTrait<OBJ>, OBJ: Object> BitAndAssign for Filter<F, OBJ> {
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<F: FilterTrait<OBJ>, OBJ: Object> BitAndAssign for Filter<F, OBJ> {
impl<F: FilterTrait<OBJ>, OBJ: Object> BitOrAssign for Filter<F, OBJ> {
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<F: FilterTrait<OBJ>, OBJ: Object> Not for Filter<F, OBJ> {
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],
},

View File

@ -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<Vec<u8>> {
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(),

View File

@ -82,8 +82,8 @@ impl DerefMut for MaildirPath {
}
impl From<PathBuf> 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<dyn Fn(&str) -> 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<Envelope> {
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)?;

View File

@ -34,15 +34,14 @@ use futures::{
use super::*;
use crate::backends::maildir::backend::move_to_cur;
type Payload = Pin<Box<dyn Future<Output = Result<Vec<Envelope>>> + Send + 'static>>;
pub struct MaildirStream {
payloads: Pin<
Box<
FuturesUnordered<Pin<Box<dyn Future<Output = Result<Vec<Envelope>>> + Send + 'static>>>,
>,
>,
payloads: Pin<Box<FuturesUnordered<Payload>>>,
}
impl MaildirStream {
#[allow(clippy::type_complexity, clippy::new_ret_no_self)]
pub fn new(
mailbox_hash: MailboxHash,
unseen: Arc<Mutex<usize>>,
@ -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();

View File

@ -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<dyn Fn(&str) -> 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,

View File

@ -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()

View File

@ -119,7 +119,7 @@ type Capabilities = HashSet<String>;
#[derive(Debug)]
pub struct UIDStore {
account_hash: AccountHash,
account_name: Arc<String>,
account_name: Arc<str>,
capabilities: Arc<Mutex<Capabilities>>,
message_id_index: Arc<Mutex<HashMap<String, EnvelopeHash>>>,
hash_index: Arc<Mutex<HashMap<EnvelopeHash, (UID, MailboxHash)>>>,
@ -134,10 +134,10 @@ pub struct UIDStore {
impl UIDStore {
fn new(
account_hash: AccountHash,
account_name: Arc<String>,
account_name: Arc<str>,
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<dyn Fn(&str) -> 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<Option<Vec<Envelope>>> {
let FetchState {
let Self {
mailbox_hash,
ref connection,
ref uid_store,

View File

@ -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<Connection>,
@ -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<UIDStore>,
) -> NntpConnection {
NntpConnection {
pub fn new_connection(server_conf: &NntpServerConf, uid_store: Arc<UIDStore>) -> Self {
Self {
stream: Err(Error::new("Offline".to_string())),
server_conf: server_conf.clone(),
uid_store,

View File

@ -40,7 +40,7 @@ impl NntpOp {
connection: Arc<FutureMutex<NntpConnection>>,
uid_store: Arc<UIDStore>,
) -> Self {
NntpOp {
Self {
uid,
connection,
mailbox_hash,

View File

@ -88,6 +88,7 @@ impl DbConnection {
}
}
#[allow(clippy::too_many_arguments)] // Don't judge me clippy.
fn refresh(
&mut self,
mailboxes: Arc<RwLock<HashMap<MailboxHash, NotmuchMailbox>>>,
@ -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<RwLock<HashMap<EnvelopeHash, SmallVec<[MailboxHash; 16]>>>>,
collection: Collection,
path: PathBuf,
_account_name: Arc<String>,
_account_name: Arc<str>,
account_hash: AccountHash,
event_consumer: BackendEventConsumer,
save_messages_to: Option<PathBuf>,
@ -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<dyn Fn(&str) -> 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<MailboxHash>,
) -> ResultFuture<SmallVec<[EnvelopeHash; 512]>> {
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<MessageIterator<'s>> {
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!(

View File

@ -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 {

View File

@ -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 {

View File

@ -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<SmallVec<[MailboxHash; 8]>> {
*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()

View File

@ -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<bool> 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,
},
)
}

View File

@ -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<ImapCodecFlag> {
@ -239,7 +239,7 @@ impl Deref for Mail {
impl Mail {
pub fn new(bytes: Vec<u8>, flags: Option<Flag>) -> Result<Self> {
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<Flag>) -> Result<Envelope> {
let mut e = Envelope::new(EnvelopeHash::from_bytes(bytes));
pub fn from_bytes(bytes: &[u8], flags: Option<Flag>) -> Result<Self> {
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<std::cmp::Ordering> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Envelope {
fn eq(&self, other: &Envelope) -> bool {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}

View File

@ -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<String>, 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<Address>) -> Self {
Address::Group(GroupAddress {
pub fn new_group(display_name: String, mailbox_list: Vec<Self>) -> 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<String> {
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<String> {
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<T: AsRef<[u8]>>(val: T) -> Result<Vec<Address>> {
pub fn list_try_from<T: AsRef<[u8]>>(val: T) -> Result<Vec<Self>> {
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::<HashSet<_>>()
== o.mailbox_list.iter().collect::<HashSet<_>>()
}
@ -318,10 +327,10 @@ impl PartialEq for Address {
impl Hash for Address {
fn hash<H: Hasher>(&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<String> =
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<String> =
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<Address> {
fn try_from(val: &str) -> Result<Self> {
Ok(parser::address::address(val.as_bytes())?.1)
}
}
@ -422,7 +429,7 @@ pub struct MessageID(pub Vec<u8>, 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())

View File

@ -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<u8> },
}
impl Default for ContentTransferEncoding {
fn default() -> Self {
ContentTransferEncoding::_8Bit
}
Other {
tag: Vec<u8>,
},
}
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<String>,
}
#[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<ContentDispositionKind> for ContentDisposition {
fn from(kind: ContentDispositionKind) -> ContentDisposition {
ContentDisposition {
fn from(kind: ContentDispositionKind) -> Self {
Self {
kind,
..ContentDisposition::default()
..Self::default()
}
}
}

View File

@ -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<Attachment> for AttachmentBuilder {
raw,
body,
} = val;
AttachmentBuilder {
Self {
content_type,
content_disposition,
content_transfer_encoding,
@ -374,7 +374,7 @@ impl From<AttachmentBuilder> 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<u8>,
) -> 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<Attachment> {
pub fn attachments(&self) -> Vec<Self> {
let mut ret = Vec::new();
fn count_recursive(att: &Attachment, ret: &mut Vec<Attachment>) {
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<u8> {
fn decode_rec_helper(&self, options: &mut DecodeOptions<'_>) -> Vec<u8> {
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<u8> {
pub fn decode_rec(&self, mut options: DecodeOptions<'_>) -> Vec<u8> {
self.decode_rec_helper(&mut options)
}
fn decode_helper<'a, 'b>(&'a self, options: &mut DecodeOptions<'b>) -> Vec<u8> {
fn decode_helper(&self, options: &mut DecodeOptions<'_>) -> Vec<u8> {
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<u8> {
pub fn decode(&self, mut options: DecodeOptions<'_>) -> Vec<u8> {
self.decode_helper(&mut options)
}
}

View File

@ -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<Self> {
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![],
});

View File

@ -186,7 +186,6 @@ mod tests {
fn test_headers_case_sensitivity() {
let mut headers = HeaderMap::default();
headers.insert("from".try_into().unwrap(), "Myself <a@b.c>".into());
dbg!(&headers);
assert_eq!(&headers["From"], "Myself <a@b.c>");
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");

View File

@ -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<Self> {
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<Self> {
match name_bytes {
$(
@ -565,8 +569,8 @@ impl HeaderName {
impl FromStr for HeaderName {
type Err = InvalidHeaderName;
fn from_str(s: &str) -> Result<HeaderName, InvalidHeaderName> {
HeaderName::from_bytes(s.as_bytes()).map_err(|_| InvalidHeaderName::new())
fn from_str(s: &str) -> Result<Self, InvalidHeaderName> {
Self::from_bytes(s.as_bytes()).map_err(|_| InvalidHeaderName::new())
}
}
@ -605,15 +609,15 @@ impl<'de> Deserialize<'de> for HeaderName {
S(String),
B(Vec<u8>),
}
if let Ok(s) = <Helper>::deserialize(deserializer) {
Self::from_bytes(match &s {
Helper::S(v) => v.as_bytes(),
Helper::B(v) => v.as_slice(),
})
<Helper>::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<Vec<u8>> for HeaderName {
#[doc(hidden)]
impl From<StandardHeader> for HeaderName {
fn from(src: StandardHeader) -> HeaderName {
HeaderName {
fn from(src: StandardHeader) -> Self {
Self {
inner: Repr::Standard(src),
}
}
@ -700,16 +704,16 @@ impl From<StandardHeader> for HeaderName {
#[doc(hidden)]
impl From<Custom> 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()

View File

@ -107,9 +107,10 @@ pub fn list_id(header: Option<&'_ str>) -> Option<&'_ str> {
impl<'a> ListActions<'a> {
pub fn detect(envelope: &'a Envelope) -> Option<ListActions<'a>> {
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('<') {

View File

@ -114,7 +114,7 @@ impl Mailto {
impl From<Mailto> 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<Mailto> 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<Self, Self::Error> {
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<Self, Self::Error> {
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: <mailto:joe@example.com?cc=bob@
// example.com?body=hello> ; 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();
// <a href="mailto:?to=joe@xyz.com&amp;cc=bob@xyz.com&amp;body=hello"> assert
// these are equal

View File

@ -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<I, E> nom::error::FromExternalError<I, E> for ParsingError<I> {
impl<I> nom::error::ContextError<I> for ParsingError<I> {}
impl<'i> From<ParsingError<&'i [u8]>> 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<ParsingError<&'i str>> 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::<String>(),
@ -168,34 +169,34 @@ Error: {}"#,
}
impl<'i> From<nom::Err<ParsingError<&'i [u8]>>> for Error {
fn from(val: nom::Err<ParsingError<&'i [u8]>>) -> Error {
fn from(val: nom::Err<ParsingError<&'i [u8]>>) -> 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<nom::Err<ParsingError<&'i str>>> for Error {
fn from(val: nom::Err<ParsingError<&'i str>>) -> Error {
fn from(val: nom::Err<ParsingError<&'i str>>) -> 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<nom::Err<nom::error::Error<&[u8]>>> for Error {
fn from(val: nom::Err<nom::error::Error<&[u8]>>) -> Error {
fn from(val: nom::Err<nom::error::Error<&[u8]>>) -> 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<ParsingError<&'i [u8]>> 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<u8> = 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<u8> = 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<u8> = 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 {

View File

@ -460,11 +460,11 @@ impl<T, I: Into<Error>> ResultIntoError<T> for std::result::Result<T, I> {
}
impl Error {
pub fn new<M>(msg: M) -> Error
pub fn new<M>(msg: M) -> Self
where
M: Into<Cow<'static, str>>,
{
Error {
Self {
summary: msg.into(),
details: None,
source: None,
@ -472,7 +472,7 @@ impl Error {
}
}
pub fn set_details<M>(mut self, details: M) -> Error
pub fn set_details<M>(mut self, details: M) -> Self
where
M: Into<Cow<'static, str>>,
{
@ -484,7 +484,7 @@ impl Error {
self
}
pub fn set_summary<M>(mut self, summary: M) -> Error
pub fn set_summary<M>(mut self, summary: M) -> Self
where
M: Into<Cow<'static, str>>,
{
@ -499,12 +499,12 @@ impl Error {
pub fn set_source(
mut self,
new_val: Option<std::sync::Arc<dyn std::error::Error + Send + Sync + 'static>>,
) -> 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<io::Error> 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<io::Error> for Error {
impl<'a> From<Cow<'a, str>> 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<string::FromUtf8Error> 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<str::Utf8Error> 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<str::Utf8Error> for Error {
impl<T> From<std::sync::PoisonError<T>> for Error {
#[inline]
fn from(kind: std::sync::PoisonError<T>) -> Error {
Error::new(kind.to_string()).set_kind(ErrorKind::Bug)
fn from(kind: std::sync::PoisonError<T>) -> Self {
Self::new(kind.to_string()).set_kind(ErrorKind::Bug)
}
}
#[cfg(feature = "tls")]
impl<T: Sync + Send + 'static + core::fmt::Debug> From<native_tls::HandshakeError<T>> for Error {
#[inline]
fn from(kind: native_tls::HandshakeError<T>) -> Error {
Error::new(kind.to_string())
fn from(kind: native_tls::HandshakeError<T>) -> Self {
Self::new(kind.to_string())
.set_source(Some(Arc::new(kind)))
.set_kind(ErrorKind::Network(NetworkErrorKind::InvalidTLSConnection))
}
@ -590,8 +592,8 @@ impl<T: Sync + Send + 'static + core::fmt::Debug> From<native_tls::HandshakeErro
#[cfg(feature = "tls")]
impl From<native_tls::Error> 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<native_tls::Error> for Error {
impl From<std::num::ParseIntError> 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<NetworkErrorKind> for ErrorKind {
#[inline]
fn from(kind: NetworkErrorKind) -> ErrorKind {
ErrorKind::Network(kind)
fn from(kind: NetworkErrorKind) -> Self {
Self::Network(kind)
}
}
#[cfg(feature = "http")]
impl From<isahc::Error> 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<isahc::Error> for Error {
#[cfg(feature = "jmap_backend")]
impl From<serde_json::error::Error> 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<Box<dyn std::error::Error + Sync + Send + 'static>> for Error {
#[inline]
fn from(kind: Box<dyn std::error::Error + Sync + Send + 'static>) -> Error {
Error::new(kind.to_string()).set_source(Some(kind.into()))
fn from(kind: Box<dyn std::error::Error + Sync + Send + 'static>) -> Self {
Self::new(kind.to_string()).set_source(Some(kind.into()))
}
}
impl From<std::ffi::NulError> 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<nix::Error> 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<rusqlite::Error> 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<libloading::Error> 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<String> for Error {
#[inline]
fn from(kind: String) -> Error {
Error::new(kind)
fn from(kind: String) -> Self {
Self::new(kind)
}
}
impl From<nom::Err<(&[u8], nom::error::ErrorKind)>> 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<nom::Err<(&str, nom::error::ErrorKind)>> 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<crate::email::InvalidHeaderName> 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<base64::DecodeError> 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)
}

View File

@ -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: ",

View File

@ -108,11 +108,10 @@ impl<'de> Deserialize<'de> for LocateKey {
where
D: Deserializer<'de>,
{
if let Ok(s) = <String>::deserialize(deserializer) {
LocateKey::from_string_de::<'de, D, String>(s)
} else {
Err(de::Error::custom("LocateKey value must be a string."))
}
<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<Self> {
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<libloading::Library>) -> Self {
Key { inner, lib }
Self { inner, lib }
}
pub fn primary_uid(&self) -> Option<Address> {
@ -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()
}
}

View File

@ -19,6 +19,41 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
#![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))

View File

@ -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<Query> {
fn try_from(t: &str) -> crate::error::Result<Self> {
query()
.parse_complete(t)
.map(|(_, q)| q)

View File

@ -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)
}

View File

@ -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<ReplyCode> {
fn try_from(val: &'_ str) -> Result<Self> {
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<Mutex<Vec<((IpAddr, String), Message)>>>,
mails: Arc<Mutex<Vec<QueuedMail>>>,
stored: Arc<Mutex<Vec<(String, crate::Envelope)>>>,
}
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) => {

View File

@ -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(&quotes)
.replace(&format!("\n{}", &quotes), "")
.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!("{}{}", &quotes, &paragraph));
}
} 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<usize>, cur_index: usize) -> ReflowState {
fn new(reflow: Reflow, width: Option<usize>, 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<usize>) -> 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(&quotes)
.replace(&format!("\n{}", &quotes), "")
.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!("{}{}", &quotes, &paragraph));
}
} else {
let paragraph = paragraph.replace('\n', "").replace('\r', "");
let paragraph = paragraph.replace(['\n', '\r'], "");
if in_paragraph {
if let Some(width) = width {

View File

@ -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

View File

@ -109,19 +109,16 @@ fn bisearch(ucs: WChar, table: &'static [Interval]) -> bool {
pub fn wcwidth(ucs: WChar) -> Option<usize> {
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)

View File

@ -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<Self, Self::Err> {
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<Self, Self::Err> {
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<EnvelopeHash, ThreadHash> =
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());

View File

@ -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::<T>());

View File

@ -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<i64, ()> {
}
}
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/ */

View File

@ -23,7 +23,10 @@ use std::time::Duration;
use futures::future::{self, Either, Future};
pub async fn timeout<O>(dur: Option<Duration>, f: impl Future<Output = O>) -> crate::Result<O> {
pub async fn timeout<O>(
dur: Option<Duration>,
f: impl Future<Output = O> + Send,
) -> crate::Result<O> {
futures::pin_mut!(f);
if let Some(dur) = dur {
match future::select(f, smol::Timer::after(dur)).await {

View File

@ -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<u8> 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(

View File

@ -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<char> {
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<Cow<'static, str>>>(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<String, JsonValue>),
JsonArray(Vec<JsonValue>),
String(String),
Number(f64),
Bool(bool),
Null,
Object(HashMap<String, JsonValue>),
Array(Vec<JsonValue>),
}
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}"#));

View File

@ -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<PercentEncode<'a>> 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

View File

@ -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".."

View File

@ -54,19 +54,17 @@ pub fn open_or_create_db(
) -> Result<Connection> {
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(());
}

View File

@ -4,6 +4,12 @@ version = "0.4.1"
authors = ["Manos Pitsidianakis <el13635@mail.ntua.gr>"]
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"