use core::fmt;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
pub(crate) struct OrdMap(BTreeMap<String, String>);
impl Clone for OrdMap {
fn clone(&self) -> Self {
let mut result = BTreeMap::new();
for (k, v) in self.0.iter() {
result.insert(k.clone(), v.clone());
}
Self(result)
}
}
impl Default for OrdMap {
fn default() -> Self {
Self(BTreeMap::new())
}
}
impl PartialEq for OrdMap {
fn eq(&self, other: &Self) -> bool {
if self.0.len() != other.0.len() {
return false;
}
for (k, v) in self.0.iter() {
if let Some(other_v) = other.0.get(k) {
if other_v != v {
return false;
}
} else {
return false;
}
}
true
}
}
impl Eq for OrdMap {}
impl OrdMap {
pub(crate) fn map(&self) -> &BTreeMap<String, String> {
&self.0
}
pub(crate) fn mut_map(&mut self) -> &mut BTreeMap<String, String> {
&mut self.0
}
fn size_le(&self, other: &Self) -> bool {
self.0.len() < other.0.len()
}
fn size_gt(&self, other: &Self) -> bool {
self.0.len() > other.0.len()
}
}
impl PartialOrd for OrdMap {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.size_le(other) {
return Some(Ordering::Less);
} else if self.size_gt(other) {
return Some(Ordering::Greater);
}
for (k, my_val) in self.0.iter() {
let get_opt = other.0.get(k.as_str());
match get_opt {
None => {
return Some(Ordering::Greater);
}
Some(other_val) if my_val < other_val => {
return Some(Ordering::Less);
}
Some(other_val) if my_val > other_val => {
return Some(Ordering::Greater);
}
Some(_) => {}
}
}
Some(Ordering::Equal)
}
fn lt(&self, other: &Self) -> bool {
if let Some(ordering) = self.partial_cmp(other) {
return ordering == Ordering::Less;
}
false
}
fn le(&self, other: &Self) -> bool {
if let Some(ordering) = self.partial_cmp(other) {
return ordering == Ordering::Less || ordering == Ordering::Equal;
}
false
}
fn gt(&self, other: &Self) -> bool {
if let Some(ordering) = self.partial_cmp(other) {
return ordering == Ordering::Greater;
}
false
}
fn ge(&self, other: &Self) -> bool {
if let Some(ordering) = self.partial_cmp(other) {
return ordering == Ordering::Greater || ordering == Ordering::Equal;
}
false
}
}
impl Ord for OrdMap {
fn cmp(&self, other: &Self) -> Ordering {
let ordering = self.partial_cmp(other);
ordering.unwrap()
}
}
impl fmt::Debug for OrdMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Hash for OrdMap {
fn hash<H: Hasher>(&self, state: &mut H) {
for (k, v) in self.0.iter() {
k.hash(state);
v.hash(state);
}
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use super::OrdMap;
#[test]
fn map_insertion_order() {
let mut a = OrdMap(BTreeMap::new());
a.mut_map().insert("0".to_string(), String::new());
a.mut_map().insert("1".to_string(), String::new());
a.mut_map().insert("2".to_string(), String::new());
a.mut_map().insert("3".to_string(), String::new());
a.mut_map().insert("4".to_string(), String::new());
let entries = a.map().keys();
for (i, item) in entries.enumerate() {
assert_eq!(format!("{}", i), item.to_owned());
}
}
#[test]
fn map_equality() {
let mut a = OrdMap(BTreeMap::new());
a.mut_map().insert("0".to_string(), "a".to_string());
a.mut_map().insert("1".to_string(), "b".to_string());
a.mut_map().insert("2".to_string(), "c".to_string());
a.mut_map().insert("3".to_string(), "d".to_string());
a.mut_map().insert("4".to_string(), "e".to_string());
let mut b = OrdMap(BTreeMap::new());
b.mut_map().insert("4".to_string(), "e".to_string());
b.mut_map().insert("3".to_string(), "d".to_string());
b.mut_map().insert("1".to_string(), "b".to_string());
b.mut_map().insert("2".to_string(), "c".to_string());
b.mut_map().insert("0".to_string(), "a".to_string());
assert_eq!(a, b);
}
}