object-merge 0.1.0-alpha1

Traits useful for recursively merging document-like objects
Documentation
use crate::{
    Combine, CombineByKey, Merge, MergeByKey, MergeCombine, MergeCombineByKey, ShallowMerge,
};

use std::hash::Hash;

fn merge_with<T>(lhs: &mut Option<T>, rhs: &Option<T>, merge: impl FnOnce(&mut T, &T))
where
    T: Clone,
{
    match (lhs, rhs) {
        (Some(lhs), Some(rhs)) => merge(lhs, rhs),
        (lhs @ None, rhs) => *lhs = rhs.clone(),
        (_, None) => (),
    }
}

impl<T> Merge for Option<T>
where
    T: Merge + Clone,
{
    fn merge(&mut self, template: &Self) {
        merge_with(self, template, |lhs, rhs| lhs.merge(rhs));
    }
}

impl<T> ShallowMerge for Option<T>
where
    T: Clone,
{
    fn shallow_merge(&mut self, template: &Self) {
        merge_with(self, template, |_, _| ());
    }
}

impl<T> Combine for Option<T>
where
    T: Combine + Clone,
{
    fn combine(&mut self, template: &Self) {
        merge_with(self, template, |lhs, rhs| lhs.combine(rhs));
    }
}

impl<T> MergeCombine for Option<T>
where
    T: MergeCombine + Clone,
{
    fn merge_combine(&mut self, template: &Self) {
        merge_with(self, template, |lhs, rhs| lhs.merge_combine(rhs));
    }
}

impl<T> MergeByKey for Option<T>
where
    T: MergeByKey + Clone,
{
    type Elem = T::Elem;

    fn merge_by_key<F, K>(&mut self, template: &Self, get_key: F)
    where
        F: FnMut(&Self::Elem) -> K,
        K: Hash + Eq,
    {
        merge_with(self, template, |lhs, rhs| lhs.merge_by_key(rhs, get_key));
    }
}

impl<T> MergeCombineByKey for Option<T>
where
    T: MergeCombineByKey + Clone,
{
    type Elem = T::Elem;

    fn merge_combine_by_key<F, K>(&mut self, template: &Self, get_key: F)
    where
        F: FnMut(&Self::Elem) -> K,
        K: Hash + Eq,
    {
        merge_with(self, template, |lhs, rhs| {
            lhs.merge_combine_by_key(rhs, get_key)
        });
    }
}

impl<T> CombineByKey for Option<T>
where
    T: CombineByKey + Clone,
{
    type Elem = T::Elem;

    fn combine_by_key<F, K>(&mut self, template: &Self, get_key: F)
    where
        F: FnMut(&Self::Elem) -> K,
        K: Hash + Eq,
    {
        merge_with(self, template, |lhs, rhs| lhs.combine_by_key(rhs, get_key));
    }
}