diff --git a/meli/src/contacts/editor.rs b/meli/src/contacts/editor.rs
index 45329a6d..57b4ee6b 100644
--- a/meli/src/contacts/editor.rs
+++ b/meli/src/contacts/editor.rs
@@ -19,8 +19,7 @@
* along with meli. If not, see .
*/
-use std::collections::HashMap;
-
+use indexmap::IndexMap;
use melib::Card;
use crate::{
@@ -200,7 +199,7 @@ impl Component for ContactManager {
None => {}
Some(true) => {
let fields = std::mem::take(&mut self.form).collect().unwrap();
- let fields: HashMap = fields
+ let fields: IndexMap = fields
.into_iter()
.map(|(s, v)| {
(
diff --git a/meli/src/mail/view.rs b/meli/src/mail/view.rs
index c0236e5b..efed3360 100644
--- a/meli/src/mail/view.rs
+++ b/meli/src/mail/view.rs
@@ -260,7 +260,7 @@ impl MailView {
}
let envelope: EnvelopeRef = account.collection.get_env(coordinates.2);
- let mut entries = Vec::new();
+ let mut entries: IndexMap = IndexMap::default();
for addr in envelope.from().iter().chain(envelope.to().iter()) {
let mut new_card: Card = Card::new();
new_card
@@ -269,12 +269,12 @@ impl MailView {
if let Some(display_name) = addr.get_display_name() {
new_card.set_name(display_name);
}
- entries.push((new_card, format!("{}", addr)));
+ entries.insert(new_card.clone(), (new_card, format!("{}", addr)));
}
drop(envelope);
self.contact_selector = Some(Box::new(Selector::new(
"select contacts to add",
- entries,
+ entries.into_iter().map(|(_, v)| v).collect(),
false,
Some(Box::new(move |id: ComponentId, results: &[Card]| {
Some(UIEvent::FinishedUIDialog(id, Box::new(results.to_vec())))
diff --git a/melib/src/addressbook.rs b/melib/src/addressbook.rs
index d40cf0d0..c2bb0559 100644
--- a/melib/src/addressbook.rs
+++ b/melib/src/addressbook.rs
@@ -23,8 +23,13 @@ pub mod mutt;
#[cfg(feature = "vcard")]
pub mod vcard;
-use std::{collections::HashMap, ops::Deref};
+use std::{
+ collections::HashMap,
+ hash::{Hash, Hasher},
+ ops::Deref,
+};
+use indexmap::IndexMap;
use uuid::Uuid;
use crate::utils::{
@@ -57,11 +62,7 @@ impl From for String {
impl From for CardId {
fn from(s: String) -> Self {
- use std::{
- collections::hash_map::DefaultHasher,
- hash::{Hash, Hasher},
- str::FromStr,
- };
+ use std::{collections::hash_map::DefaultHasher, str::FromStr};
if let Ok(u) = Uuid::parse_str(s.as_str()) {
Self::Uuid(u)
@@ -80,7 +81,7 @@ pub struct AddressBook {
display_name: String,
created: UnixTimestamp,
last_edited: UnixTimestamp,
- pub cards: HashMap,
+ pub cards: IndexMap,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
@@ -97,7 +98,7 @@ pub struct Card {
key: String,
color: u8,
last_edited: UnixTimestamp,
- extra_properties: HashMap,
+ extra_properties: IndexMap,
/// If `true`, we can't make any changes because we do not manage this
/// resource.
external_resource: bool,
@@ -115,13 +116,24 @@ impl std::fmt::Display for Card {
}
}
+impl Hash for Card {
+ fn hash(&self, state: &mut H) {
+ let mut serialized = serde_json::json! { self };
+ // The following anonymous let bind is just to make sure at compile-time that
+ // `id` field is present in Self and serialized["id"] will be a valid access.
+ let _: &CardId = &self.id;
+ serialized["id"] = serde_json::json! { CardId::Hash(0) };
+ serialized.to_string().hash(state);
+ }
+}
+
impl AddressBook {
pub fn new(display_name: String) -> Self {
Self {
display_name,
created: now(),
last_edited: now(),
- cards: HashMap::default(),
+ cards: IndexMap::default(),
}
}
@@ -199,9 +211,9 @@ impl AddressBook {
}
impl Deref for AddressBook {
- type Target = HashMap;
+ type Target = IndexMap;
- fn deref(&self) -> &HashMap {
+ fn deref(&self) -> &IndexMap {
&self.cards
}
}
@@ -223,6 +235,12 @@ macro_rules! set_fn {
};
}
+impl Default for Card {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
impl Card {
pub fn new() -> Self {
Self {
@@ -240,7 +258,7 @@ impl Card {
last_edited: now(),
external_resource: false,
- extra_properties: HashMap::default(),
+ extra_properties: IndexMap::default(),
color: 0,
}
}
@@ -266,7 +284,7 @@ impl Card {
self.extra_properties.get(key).map(String::as_str)
}
- pub fn extra_properties(&self) -> &HashMap {
+ pub fn extra_properties(&self) -> &IndexMap {
&self.extra_properties
}
@@ -299,8 +317,8 @@ impl Card {
}
}
-impl From> for Card {
- fn from(mut map: HashMap) -> Self {
+impl From> for Card {
+ fn from(mut map: IndexMap) -> Self {
let mut card = Self::new();
macro_rules! get {
($key:literal, $field:tt) => {
@@ -322,8 +340,9 @@ impl From> for Card {
}
}
-impl Default for Card {
- fn default() -> Self {
- Self::new()
+impl From> for Card {
+ fn from(map: HashMap) -> Self {
+ let map: IndexMap = map.into_iter().collect();
+ Self::from(map)
}
}
diff --git a/melib/src/addressbook/vcard.rs b/melib/src/addressbook/vcard.rs
index d1a47d5c..79bb6735 100644
--- a/melib/src/addressbook/vcard.rs
+++ b/melib/src/addressbook/vcard.rs
@@ -186,7 +186,6 @@ impl TryInto for VCard {
fn try_into(mut self) -> crate::error::Result {
let mut card = Card::new();
card.set_id(CardId::Hash({
- use std::hash::Hasher;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
if let Some(val) = self.0.get("FN") {
hasher.write(val.value.as_bytes());