comparable 0.5.6

A library for comparing data structures in Rust, oriented toward testing
Documentation
// use serde;
use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;

use crate::types::{Changed, Comparable};

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Debug)]
pub enum MapChange<Key, Desc, Change> {
	Added(Key, Desc),
	Changed(Key, Change),
	Removed(Key),
}

impl<Key: Ord + Clone + Debug, Value: Comparable> Comparable for BTreeMap<Key, Value> {
	type Desc = BTreeMap<Key, Value::Desc>;

	fn describe(&self) -> Self::Desc {
		self.iter().map(|(k, v)| (k.clone(), v.describe())).collect()
	}

	type Change = Vec<MapChange<Key, Value::Desc, Value::Change>>;

	fn comparison(&self, other: &Self) -> Changed<Self::Change> {
		let mut changes = Vec::new();
		changes.append(
			&mut other
				.iter()
				.flat_map(|(k, v)| {
					if let Some(vo) = self.get(k) {
						vo.comparison(v).map(|changes| MapChange::Changed(k.clone(), changes))
					} else {
						Changed::Changed(MapChange::Added(k.clone(), v.describe()))
					}
				})
				.collect(),
		);
		changes.append(
			&mut self
				.iter()
				.flat_map(|(k, _v)| {
					if !other.contains_key(k) {
						Changed::Changed(MapChange::Removed(k.clone()))
					} else {
						Changed::Unchanged
					}
				})
				.collect(),
		);
		if changes.is_empty() {
			Changed::Unchanged
		} else {
			Changed::Changed(changes)
		}
	}
}

fn to_btreemap<K: Clone + Ord, V>(map: &HashMap<K, V>) -> BTreeMap<K, &V> {
	map.iter().map(|(k, v)| (k.clone(), v)).collect::<BTreeMap<K, &V>>().into_iter().collect()
}

impl<Key: Ord + Clone + Debug, Value: Comparable> Comparable for HashMap<Key, Value> {
	type Desc = BTreeMap<Key, Value::Desc>;

	fn describe(&self) -> Self::Desc {
		self.iter().map(|(k, v)| (k.clone(), v.describe())).collect()
	}

	type Change = Vec<MapChange<Key, Value::Desc, Value::Change>>;

	fn comparison(&self, other: &Self) -> Changed<Self::Change> {
		to_btreemap(self).comparison(&to_btreemap(other))
	}
}