#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
#[cfg(feature = "derive")]
pub use merge2_derive::*;
pub trait Merge: Sized {
fn merge(&mut self, other: &mut Self);
}
pub mod any {
#[inline]
pub fn overwrite<T: Default>(left: &mut T, right: &mut T) {
*left = ::core::mem::take(right);
}
#[inline]
pub fn overwrite_default<T: Default + PartialEq>(left: &mut T, right: &mut T) {
if *left == T::default() {
::core::mem::swap(left, right);
}
}
#[inline]
pub fn swap<T>(left: &mut T, right: &mut T) {
::core::mem::swap(left, right);
}
}
impl<T> Merge for Option<T> {
#[inline]
fn merge(&mut self, right: &mut Self) {
if self.is_none() {
::core::mem::swap(self, right);
}
}
}
pub mod option {
#[inline]
pub fn recursive<T: super::Merge>(left: &mut Option<T>, right: &mut Option<T>) {
if let Some(original) = left {
if let Some(new) = right {
original.merge(new);
}
} else {
::core::mem::swap(left, right);
}
}
}
macro_rules! skip_merge {
($($t:ty)*) => {$(
impl Merge for $t {
#[inline(always)]
fn merge(&mut self, _: &mut Self) {}
}
)*};
}
skip_merge!(u8 i8 u16 i16 u32 i32 usize isize u64 i64 u128 i128 f32 f64 bool);
pub mod bool {
#[inline]
pub fn overwrite_false(left: &mut bool, right: &mut bool) {
if !*left {
*left = *right;
}
}
#[inline]
pub fn overwrite_true(left: &mut bool, right: &mut bool) {
if *left {
*left = *right;
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "num")))]
#[cfg(feature = "num")]
pub mod num {
#[inline]
pub fn saturating_add<T: num_traits::SaturatingAdd>(left: &mut T, right: &mut T) {
*left = left.saturating_add(right);
}
}
pub mod ord {
use ::core::cmp;
#[inline]
pub fn max<T: cmp::PartialOrd>(left: &mut T, right: &mut T) {
if cmp::PartialOrd::partial_cmp(left, right) == Some(cmp::Ordering::Less) {
::core::mem::swap(left, right);
}
}
#[inline]
pub fn min<T: cmp::PartialOrd>(left: &mut T, right: &mut T) {
if cmp::PartialOrd::partial_cmp(left, right) == Some(cmp::Ordering::Greater) {
::core::mem::swap(left, right);
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(feature = "std")]
mod std {
use super::Merge;
impl Merge for &str {
#[inline]
fn merge(&mut self, right: &mut Self) {
if self.is_empty() {
::core::mem::swap(self, right);
}
}
}
impl Merge for String {
#[inline]
fn merge(&mut self, right: &mut Self) {
if self.is_empty() {
::core::mem::swap(self, right);
}
}
}
pub mod string {
#[inline]
pub fn append(left: &mut String, right: &mut String) {
if left.is_empty() {
::core::mem::swap(left, right);
} else {
let new = ::core::mem::take(right);
left.push_str(&new);
}
}
#[inline]
pub fn prepend(left: &mut String, right: &mut String) {
if left.is_empty() {
::core::mem::swap(left, right);
} else if !right.is_empty() {
right.push_str(left);
*left = ::core::mem::take(right);
}
}
}
impl<T> Merge for Vec<T> {
#[inline]
fn merge(&mut self, right: &mut Self) {
if self.is_empty() {
::core::mem::swap(self, right);
}
}
}
pub mod vec {
#[inline]
pub fn append<T>(left: &mut Vec<T>, right: &mut Vec<T>) {
if left.is_empty() {
::core::mem::swap(left, right);
} else {
left.append(right);
}
}
#[inline]
pub fn prepend<T>(left: &mut Vec<T>, right: &mut Vec<T>) {
if left.is_empty() {
::core::mem::swap(left, right);
} else if !right.is_empty() {
right.append(left);
::core::mem::swap(left, right);
}
}
}
use ::std::collections::HashMap;
impl<K, V> Merge for HashMap<K, V> {
#[inline]
fn merge(&mut self, right: &mut Self) {
if self.is_empty() {
::core::mem::swap(self, right);
}
}
}
pub mod hashmap {
use super::HashMap;
use ::core::hash::BuildHasher;
use ::core::hash::Hash;
#[inline]
pub fn merge<K: Eq + Hash, V, S: BuildHasher + Default>(
left: &mut HashMap<K, V, S>,
right: &mut HashMap<K, V, S>,
) {
let map = ::core::mem::take(right);
for (k, v) in map {
left.entry(k).or_insert(v);
}
}
#[inline]
pub fn replace<K: Eq + Hash, V, S: BuildHasher + Default>(
left: &mut HashMap<K, V, S>,
right: &mut HashMap<K, V, S>,
) {
left.extend(::core::mem::take(right))
}
pub fn recursive<K: Eq + Hash, V: super::Merge, S: BuildHasher + Default>(
left: &mut HashMap<K, V, S>,
right: &mut HashMap<K, V, S>,
) {
use ::std::collections::hash_map::Entry;
let map = ::core::mem::take(right);
for (k, mut v) in map {
match left.entry(k) {
Entry::Occupied(mut existing) => existing.get_mut().merge(&mut v),
Entry::Vacant(empty) => {
empty.insert(v);
}
}
}
}
pub fn intersection<K: Eq + Hash, V: super::Merge, S: BuildHasher + Default>(
left: &mut HashMap<K, V, S>,
right: &mut HashMap<K, V, S>,
) {
use ::std::collections::hash_map::Entry;
let map = ::core::mem::take(right);
for (k, mut v) in map {
if let Entry::Occupied(mut existing) = left.entry(k) {
existing.get_mut().merge(&mut v);
}
}
}
}
}
pub use std::*;