Remove indexmap dependency

`indexmap` is a large dependency (4K SLoC) containing `unsafe` code.

Contact IDs are now passed around as a Vec<u32> or &[u32].

QUOTA roots are now sorted by name instead of perserving original order.
This commit is contained in:
link2xt
2021-11-21 19:11:11 +00:00
committed by Simon Laux
parent 5c571520a0
commit 016fb2ceb2
4 changed files with 41 additions and 52 deletions

11
Cargo.lock generated
View File

@@ -1084,7 +1084,6 @@ dependencies = [
"hex",
"humansize",
"image",
"indexmap",
"kamadak-exif",
"lettre_email",
"libc",
@@ -1935,16 +1934,6 @@ dependencies = [
"nom 6.1.2",
]
[[package]]
name = "indexmap"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg 1.0.1",
"hashbrown",
]
[[package]]
name = "infer"
version = "0.2.3"

View File

@@ -36,7 +36,6 @@ escaper = "0.1"
futures = "0.3"
hex = "0.4.0"
image = { version = "0.23.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
indexmap = "1.7"
kamadak-exif = "0.5"
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" }
libc = "0.2"

View File

@@ -1,6 +1,7 @@
//! Internet Message Format reception pipeline.
use std::cmp::min;
use std::collections::BTreeSet;
use std::convert::TryFrom;
use anyhow::{bail, ensure, Context as _, Result};
@@ -35,9 +36,6 @@ use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on
use crate::stock_str;
use crate::{contact, location};
// IndexSet is like HashSet but maintains order of insertion.
type ContactIds = indexmap::IndexSet<u32>;
#[derive(Debug, PartialEq, Eq)]
enum CreateEvent {
MsgsChanged,
@@ -162,23 +160,19 @@ pub(crate) async fn dc_receive_imf_inner(
let incoming = from_id != DC_CONTACT_ID_SELF;
let mut to_ids = ContactIds::new();
to_ids.extend(
&dc_add_or_lookup_contacts_by_address_list(
context,
&mime_parser.recipients,
if !incoming {
Origin::OutgoingTo
} else if incoming_origin.is_known() {
Origin::IncomingTo
} else {
Origin::IncomingUnknownTo
},
prevent_rename,
)
.await?,
);
let to_ids = dc_add_or_lookup_contacts_by_address_list(
context,
&mime_parser.recipients,
if !incoming {
Origin::OutgoingTo
} else if incoming_origin.is_known() {
Origin::IncomingTo
} else {
Origin::IncomingUnknownTo
},
prevent_rename,
)
.await?;
let rcvd_timestamp = dc_smeared_time(context).await;
let sent_timestamp = mime_parser
@@ -402,7 +396,7 @@ pub async fn from_field_to_contact_id(
"mail has more than one From address, only using first: {:?}", from_address_list
);
}
let from_id = from_ids.get_index(0).cloned().unwrap_or_default();
let from_id = from_ids.get(0).cloned().unwrap_or_default();
let mut from_id_blocked = false;
let mut incoming_origin = Origin::Unknown;
@@ -430,7 +424,7 @@ async fn add_parts(
incoming_origin: Origin,
server_folder: &str,
server_uid: u32,
to_ids: &ContactIds,
to_ids: &[u32],
rfc724_mid: String,
sent_timestamp: i64,
rcvd_timestamp: i64,
@@ -724,7 +718,7 @@ async fn add_parts(
// the mail is on the IMAP server, probably it is also delivered.
// We cannot recreate other states (read, error).
state = MessageState::OutDelivered;
to_id = to_ids.get_index(0).cloned().unwrap_or_default();
to_id = to_ids.get(0).cloned().unwrap_or_default();
let self_sent = from_id == DC_CONTACT_ID_SELF
&& to_ids.len() == 1
@@ -1316,7 +1310,7 @@ async fn lookup_chat_by_reply(
mime_parser: &mut MimeMessage,
parent: &Option<Message>,
from_id: u32,
to_ids: &ContactIds,
to_ids: &[u32],
) -> Result<Option<(ChatId, Blocked)>> {
// Try to assign message to the same chat as the parent message.
@@ -1356,7 +1350,7 @@ async fn lookup_chat_by_reply(
/// If it returns false, it shall be assigned to the parent chat.
async fn is_probably_private_reply(
context: &Context,
to_ids: &indexmap::IndexSet<u32>,
to_ids: &[u32],
mime_parser: &MimeMessage,
parent_chat_id: ChatId,
from_id: u32,
@@ -1368,7 +1362,7 @@ async fn is_probably_private_reply(
// should be assigned to the group chat. We restrict this exception to classical emails, as chat-group-messages
// contain a Chat-Group-Id header and can be sorted into the correct chat this way.
let private_message = to_ids == &[DC_CONTACT_ID_SELF].iter().copied().collect::<ContactIds>();
let private_message = to_ids == [DC_CONTACT_ID_SELF].iter().copied().collect::<Vec<u32>>();
if !private_message {
return Ok(false);
}
@@ -1397,7 +1391,7 @@ async fn create_or_lookup_group(
allow_creation: bool,
create_blocked: Blocked,
from_id: u32,
to_ids: &ContactIds,
to_ids: &[u32],
) -> Result<Option<(ChatId, Blocked)>> {
let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) {
grpid
@@ -1541,7 +1535,7 @@ async fn apply_group_changes(
sent_timestamp: i64,
chat_id: ChatId,
from_id: u32,
to_ids: &ContactIds,
to_ids: &[u32],
) -> Result<()> {
let mut chat = Chat::load_from_db(context, chat_id).await?;
if chat.typ != Chattype::Group {
@@ -1981,7 +1975,7 @@ async fn check_verified_properties(
context: &Context,
mimeparser: &MimeMessage,
from_id: u32,
to_ids: &ContactIds,
to_ids: &[u32],
) -> Result<()> {
let contact = Contact::load_from_db(context, from_id).await?;
@@ -2024,8 +2018,11 @@ async fn check_verified_properties(
}
// we do not need to check if we are verified with ourself
let mut to_ids = to_ids.clone();
to_ids.remove(&DC_CONTACT_ID_SELF);
let to_ids = to_ids
.iter()
.copied()
.filter(|id| *id != DC_CONTACT_ID_SELF)
.collect::<Vec<u32>>();
if to_ids.is_empty() {
return Ok(());
@@ -2188,6 +2185,10 @@ pub(crate) async fn get_prefetch_parent_message(
Ok(None)
}
/// Looks up contact IDs from the database given the list of recipients.
///
/// Returns vector of IDs guaranteed to be unique.
///
/// * param `prevent_rename`: if true, the display_name of this contact will not be changed. Useful for
/// mailing lists: In some mailing lists, many users write from the same address but with different
/// display names. We don't want the display name to change everytime the user gets a new email from
@@ -2197,8 +2198,8 @@ async fn dc_add_or_lookup_contacts_by_address_list(
address_list: &[SingleInfo],
origin: Origin,
prevent_rename: bool,
) -> Result<ContactIds> {
let mut contact_ids = ContactIds::new();
) -> Result<Vec<u32>> {
let mut contact_ids = BTreeSet::new();
for info in address_list.iter() {
let display_name = if prevent_rename {
Some("")
@@ -2210,7 +2211,7 @@ async fn dc_add_or_lookup_contacts_by_address_list(
);
}
Ok(contact_ids)
Ok(contact_ids.into_iter().collect::<Vec<u32>>())
}
/// Add contacts to database on receiving messages.

View File

@@ -2,7 +2,7 @@
use anyhow::{anyhow, Result};
use async_imap::types::{Quota, QuotaResource};
use indexmap::IndexMap;
use std::collections::BTreeMap;
use crate::chat::add_device_msg_with_importance;
use crate::config::Config;
@@ -43,7 +43,7 @@ pub struct QuotaInfo {
/// set to `Err()` if the provider does not support quota or on other errors,
/// set to `Ok()` for valid quota information.
/// Updated by `Action::UpdateRecentQuota`
pub(crate) recent: Result<IndexMap<String, Vec<QuotaResource>>>,
pub(crate) recent: Result<BTreeMap<String, Vec<QuotaResource>>>,
/// Timestamp when structure was modified.
pub(crate) modified: i64,
@@ -52,8 +52,8 @@ pub struct QuotaInfo {
async fn get_unique_quota_roots_and_usage(
folders: Vec<String>,
imap: &mut Imap,
) -> Result<IndexMap<String, Vec<QuotaResource>>> {
let mut unique_quota_roots: IndexMap<String, Vec<QuotaResource>> = IndexMap::new();
) -> Result<BTreeMap<String, Vec<QuotaResource>>> {
let mut unique_quota_roots: BTreeMap<String, Vec<QuotaResource>> = BTreeMap::new();
for folder in folders {
let (quota_roots, quotas) = &imap.get_quota_roots(&folder).await?;
// if there are new quota roots found in this imap folder, add them to the list
@@ -69,7 +69,7 @@ async fn get_unique_quota_roots_and_usage(
// messages could be recieved and so the usage could have been changed
*unique_quota_roots
.entry(quota_root_name.clone())
.or_insert(vec![]) = quota.resources;
.or_insert_with(Vec::new) = quota.resources;
}
}
}
@@ -77,7 +77,7 @@ async fn get_unique_quota_roots_and_usage(
}
fn get_highest_usage<'t>(
unique_quota_roots: &'t IndexMap<String, Vec<QuotaResource>>,
unique_quota_roots: &'t BTreeMap<String, Vec<QuotaResource>>,
) -> Result<(u64, &'t String, &QuotaResource)> {
let mut highest: Option<(u64, &'t String, &QuotaResource)> = None;
for (name, resources) in unique_quota_roots {