use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::ffi::OsString;
use std::hash::Hash;
pub trait Monoid: Sized {
fn ident() -> Self;
fn combine(self, rhs: Self) -> Self;
fn combine_assign(&mut self, rhs: Self) {
*self = std::mem::replace(self, Self::ident()).combine(rhs);
}
fn combine_assign_to(self, rhs: &mut Self) {
*rhs = self.combine(std::mem::replace(rhs, Self::ident()));
}
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(Self::combine).unwrap_or_else(Self::ident)
}
fn combine_iter_assign<I: Iterator<Item = Self>>(&mut self, iter: I) {
self.combine_assign(Self::combine_iter(iter))
}
}
impl Monoid for () {
#[inline]
fn ident() {}
#[inline]
fn combine(self, (): Self) {}
#[inline]
fn combine_assign(&mut self, (): Self) {}
#[inline]
fn combine_assign_to(self, (): &mut Self) {}
#[inline]
fn combine_iter<I: Iterator<Item = Self>>(_iter: I) {}
#[inline]
fn combine_iter_assign<I: Iterator<Item = Self>>(&mut self, _iter: I) {}
}
impl<M1: Monoid, M2: Monoid> Monoid for (M1, M2) {
#[inline]
fn ident() -> Self {
(M1::ident(), M2::ident())
}
#[inline]
fn combine(self, rhs: Self) -> Self {
(self.0.combine(rhs.0), self.1.combine(rhs.1))
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0.combine_assign(rhs.0);
self.1.combine_assign(rhs.1);
}
fn combine_assign_to(self, rhs: &mut Self) {
self.0.combine_assign_to(&mut rhs.0);
self.1.combine_assign_to(&mut rhs.1);
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Opposite<M: Monoid>(pub M);
impl<M: Monoid> Monoid for Opposite<M> {
fn ident() -> Self {
Self(M::ident())
}
fn combine(self, rhs: Self) -> Self {
Self(M::combine(rhs.0, self.0))
}
fn combine_assign(&mut self, rhs: Self) {
M::combine_assign_to(rhs.0, &mut self.0);
}
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0.combine_assign(self.0);
}
}
impl<M: Monoid> Monoid for Option<M> {
#[inline]
fn ident() -> Self {
None
}
fn combine(self, rhs: Self) -> Self {
self.zip(rhs).map(|(l, r)| l.combine(r))
}
fn combine_assign(&mut self, rhs: Self) {
if let Some(rhs) = rhs {
match self {
None => *self = Some(rhs),
Some(lhs) => lhs.combine_assign(rhs),
}
}
}
fn combine_assign_to(self, rhs: &mut Self) {
if let Some(lhs) = self {
match rhs {
None => *rhs = Some(lhs),
Some(rhs) => lhs.combine_assign_to(rhs),
}
}
}
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.flatten().reduce(M::combine)
}
}
#[cfg(feature = "syn")]
impl Monoid for Option<syn::Error> {
#[inline]
fn ident() -> Self {
None
}
fn combine(self, rhs: Self) -> Self {
self.zip(rhs).map(|(mut l, r)| {
l.combine(r);
l
})
}
fn combine_assign(&mut self, rhs: Self) {
if let Some(rhs) = rhs {
match self {
None => *self = Some(rhs),
Some(lhs) => lhs.combine(rhs),
}
}
}
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.flatten().reduce(|mut l, r| {
l.combine(r);
l
})
}
}
impl<T> Monoid for Vec<T> {
#[inline]
fn ident() -> Self {
Vec::new()
}
#[inline]
fn combine(mut self, mut rhs: Self) -> Self {
self.append(&mut rhs);
self
}
#[inline]
fn combine_assign(&mut self, mut rhs: Self) {
self.append(&mut rhs);
}
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.flatten().collect()
}
fn combine_iter_assign<I: Iterator<Item = Self>>(&mut self, iter: I) {
self.extend(iter.flatten());
}
}
impl Monoid for String {
#[inline]
fn ident() -> Self {
String::new()
}
#[inline]
fn combine(self, rhs: Self) -> Self {
self + &rhs
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.push_str(&rhs);
}
#[inline]
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.collect()
}
#[inline]
fn combine_iter_assign<I: Iterator<Item = Self>>(&mut self, iter: I) {
self.extend(iter);
}
}
impl Monoid for OsString {
#[inline]
fn ident() -> Self {
OsString::new()
}
#[inline]
fn combine(mut self, rhs: Self) -> Self {
self.push(rhs);
self
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.push(rhs);
}
#[inline]
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.collect()
}
#[inline]
fn combine_iter_assign<I: Iterator<Item = Self>>(&mut self, iter: I) {
self.extend(iter);
}
}
impl<T: Hash + Eq> Monoid for HashSet<T> {
#[inline]
fn ident() -> Self {
HashSet::new()
}
#[inline]
fn combine(mut self, rhs: Self) -> Self {
self.extend(rhs);
self
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.extend(rhs);
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.extend(self);
}
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.flatten().collect()
}
fn combine_iter_assign<I: Iterator<Item = Self>>(&mut self, iter: I) {
self.extend(iter.flatten())
}
}
impl<T: Ord> Monoid for BTreeSet<T> {
#[inline]
fn ident() -> Self {
BTreeSet::new()
}
#[inline]
fn combine(mut self, mut rhs: Self) -> Self {
self.append(&mut rhs);
self
}
#[inline]
fn combine_assign(&mut self, mut rhs: Self) {
self.append(&mut rhs);
}
#[inline]
fn combine_assign_to(mut self, rhs: &mut Self) {
rhs.append(&mut self);
}
fn combine_iter<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.flatten().collect()
}
fn combine_iter_assign<I: Iterator<Item = Self>>(&mut self, iter: I) {
self.extend(iter.flatten())
}
}
impl<K: Hash + Eq, M: Monoid> Monoid for HashMap<K, M> {
#[inline]
fn ident() -> Self {
HashMap::new()
}
fn combine(mut self, rhs: Self) -> Self {
self.combine_assign(rhs);
self
}
fn combine_assign(&mut self, rhs: Self) {
use std::collections::hash_map::Entry;
for (k, vr) in rhs {
match self.entry(k) {
Entry::Occupied(e) => {
let (k, vl) = e.remove_entry();
self.insert(k, vl.combine(vr));
}
Entry::Vacant(e) => {
e.insert(vr);
}
}
}
}
fn combine_assign_to(self, rhs: &mut Self) {
use std::collections::hash_map::Entry;
for (k, vl) in self {
match rhs.entry(k) {
Entry::Occupied(e) => {
let (k, vr) = e.remove_entry();
rhs.insert(k, vl.combine(vr));
}
Entry::Vacant(e) => {
e.insert(vl);
}
}
}
}
}
impl<K: Ord, M: Monoid> Monoid for BTreeMap<K, M> {
#[inline]
fn ident() -> Self {
BTreeMap::new()
}
fn combine(mut self, rhs: Self) -> Self {
self.combine_assign(rhs);
self
}
fn combine_assign(&mut self, rhs: Self) {
use std::collections::btree_map::Entry;
for (k, vr) in rhs {
match self.entry(k) {
Entry::Occupied(e) => {
let (k, vl) = e.remove_entry();
self.insert(k, vl.combine(vr));
}
Entry::Vacant(e) => {
e.insert(vr);
}
}
}
}
fn combine_assign_to(self, rhs: &mut Self) {
use std::collections::btree_map::Entry;
for (k, vl) in self {
match rhs.entry(k) {
Entry::Occupied(e) => {
let (k, vr) = e.remove_entry();
rhs.insert(k, vl.combine(vr));
}
Entry::Vacant(e) => {
e.insert(vl);
}
}
}
}
}
impl<'a, T: 'a> Monoid for Box<dyn 'a + FnMut(T) -> T> {
fn ident() -> Self {
Box::new(std::convert::identity)
}
fn combine(mut self, mut rhs: Self) -> Self {
Box::new(move |t| (*self)((*rhs)(t)))
}
}
impl<'a, T: 'a> Monoid for Box<dyn 'a + Fn(T) -> T> {
fn ident() -> Self {
Box::new(std::convert::identity)
}
fn combine(self, rhs: Self) -> Self {
Box::new(move |t| (*self)((*rhs)(t)))
}
}