serde-reflect-intermediate 1.2.4

Reflection utils of intermediate representation for Serde serialization
Documentation
#![cfg(test)]

use super::*;
use crate as serde_reflect_intermediate;
use serde::{Deserialize, Serialize};
use serde_intermediate::to_intermediate;
use std::collections::{
    hash_map::RandomState,
    {HashMap, HashSet},
};

macro_rules! map {
    ( $( $key:expr => $value:expr ),* ) => {{
        let mut result = HashMap::<_,_,RandomState>::default();
        $(
            result.insert($key, $value);
        )*
        result
    }}
}

macro_rules! set {
    ( $( $value:expr ),* ) => {{
        let mut result = HashSet::default();
        $(
            result.insert($value);
        )*
        result
    }}
}

fn patch<T>(mut prev: T, next: T)
where
    T: ReflectIntermediate + PartialEq + std::fmt::Debug + Serialize,
{
    let change = Change::difference(
        &to_intermediate(&prev).unwrap(),
        &to_intermediate(&next).unwrap(),
    );
    prev.patch_change(&change);
    assert_eq!(prev, next);
}

#[test]
fn test_general() {
    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct Foo {
        a: bool,
        b: usize,
    }

    impl ReflectIntermediate for Foo {
        fn patch_change(&mut self, change: &Change) {
            match change {
                Change::Changed(v) => {
                    if let Ok(v) = from_intermediate(v) {
                        *self = v;
                    }
                }
                Change::PartialStruct(v) => {
                    for (name, change) in v {
                        match name.as_str() {
                            "a" => self.a.patch_change(change),
                            "b" => self.b.patch_change(change),
                            _ => {}
                        }
                    }
                }
                _ => {}
            }
        }
    }

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    enum Bar {
        A,
        B(bool),
        C(bool, usize),
        D { a: bool, b: usize },
    }

    impl ReflectIntermediate for Bar {
        fn patch_change(&mut self, change: &Change) {
            match change {
                Change::Changed(v) => {
                    if let Ok(v) = from_intermediate(v) {
                        *self = v;
                    }
                }
                Change::PartialChange(change) => {
                    if let Self::B(content) = self {
                        content.patch_change(change);
                    }
                }
                Change::PartialStruct(v) => {
                    if let Self::D { a, b } = self {
                        for (name, change) in v {
                            match name.as_str() {
                                "a" => a.patch_change(change),
                                "b" => b.patch_change(change),
                                _ => {}
                            }
                        }
                    }
                }
                _ => {}
            }
        }
    }

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct Zee(bool, usize);

    impl ReflectIntermediate for Zee {
        fn patch_change(&mut self, change: &Change) {
            match change {
                Change::Changed(v) => {
                    if let Ok(v) = from_intermediate(v) {
                        *self = v;
                    }
                }
                Change::PartialSeq(v) => {
                    for (index, change) in v {
                        match *index {
                            0 => self.0.patch_change(change),
                            1 => self.1.patch_change(change),
                            _ => {}
                        }
                    }
                }
                _ => {}
            }
        }
    }

    patch(false, true);
    patch('a', 'b');
    patch(1.2, 3.0);
    patch(4usize, 5usize);
    patch("hello".to_owned(), "@".to_owned());
    patch(None, Some(true));
    patch(Err(true), Ok(42usize));
    patch([1, 2, 3], [1, 0, 3]);
    patch((1, 2, 3), (1, 0, 3));
    patch(vec![1, 2, 3], vec![1, 0, 3]);
    patch(vec![1, 2, 3], vec![1, 3]);
    patch(vec![1, 2, 3], vec![1, 2, 3, 4]);
    patch(set![1, 2, 3], set![1, 0, 3]);
    patch(set![1, 2, 3], set![1, 3]);
    patch(set![1, 2, 3], set![1, 2, 3, 4]);
    patch(
        map! {'a' => 1, 'b' => 2, 'c' => 3},
        map! {'a' => 1, 'b' => 0, 'c' => 3},
    );
    patch(
        map! {'a' => 1, 'b' => 2, 'c' => 3},
        map! {'a' => 1, 'c' => 3},
    );
    patch(
        map! {'a' => 1, 'b' => 2, 'c' => 3},
        map! {'a' => 1, 'b' => 0, 'c' => 3, 'd' => 4},
    );
    patch(Box::new(false), Box::new(true));
    patch(Foo { a: false, b: 0 }, Foo { a: true, b: 0 });
    patch(Foo { a: false, b: 0 }, Foo { a: true, b: 42 });
    patch(Foo { a: false, b: 0 }, Foo { a: false, b: 42 });
    patch(Bar::A, Bar::B(false));
    patch(Bar::B(false), Bar::B(true));
    patch(Bar::B(true), Bar::C(true, 0));
    patch(Bar::C(true, 0), Bar::C(true, 42));
    patch(Bar::C(true, 42), Bar::D { a: true, b: 0 });
    patch(Bar::D { a: true, b: 0 }, Bar::D { a: true, b: 42 });
    patch(Bar::D { a: true, b: 42 }, Bar::A);
    patch(Zee(false, 0), Zee(true, 0));
    patch(Zee(false, 0), Zee(true, 42));
    patch(Zee(false, 0), Zee(false, 42));
}

#[cfg(feature = "derive")]
#[test]
fn test_derive() {
    use crate::ReflectIntermediate;

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct Invalid;

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct Indirect(String, f32);

    #[derive(Debug, Serialize, Deserialize, ReflectIntermediate, PartialEq)]
    #[reflect_intermediate(
        before_patch_change = "pre_patch_change",
        after_patch_change = "post_patch_change"
    )]
    struct Foo {
        a: bool,
        b: usize,
        #[reflect_intermediate(ignore)]
        c: Invalid,
        #[reflect_intermediate(indirect)]
        d: Indirect,
    }

    impl Foo {
        fn pre_patch_change(&mut self) {
            println!("* Pre patch change: {:?}", self);
        }

        fn post_patch_change(&mut self) {
            println!("* Post patch change: {:?}", self);
        }
    }

    #[derive(Debug, Serialize, Deserialize, ReflectIntermediate, PartialEq)]
    enum Bar {
        A,
        B(bool),
        C(bool, usize, #[reflect_intermediate(ignore)] Invalid),
        D {
            a: bool,
            b: usize,
            #[reflect_intermediate(ignore)]
            c: Invalid,
        },
        #[reflect_intermediate(ignore)]
        Invalid,
    }

    #[derive(Debug, Serialize, Deserialize, ReflectIntermediate, PartialEq)]
    struct Zee(bool, usize, #[reflect_intermediate(ignore)] Invalid);

    #[derive(Debug, Serialize, Deserialize, ReflectIntermediate, PartialEq)]
    struct Unit;

    patch(Unit, Unit);
    patch(
        Foo {
            a: false,
            b: 0,
            c: Invalid,
            d: Indirect(Default::default(), 0.0),
        },
        Foo {
            a: true,
            b: 0,
            c: Invalid,
            d: Indirect("hello".to_owned(), 1.2),
        },
    );
    // patch(
    //     Foo {
    //         a: false,
    //         b: 0,
    //         c: Invalid,
    //     },
    //     Foo {
    //         a: true,
    //         b: 42,
    //         c: Invalid,
    //     },
    // );
    // patch(
    //     Foo {
    //         a: false,
    //         b: 0,
    //         c: Invalid,
    //     },
    //     Foo {
    //         a: false,
    //         b: 42,
    //         c: Invalid,
    //     },
    // );
    patch(Bar::A, Bar::B(false));
    patch(Bar::B(false), Bar::B(true));
    patch(Bar::B(true), Bar::C(true, 0, Invalid));
    patch(Bar::C(true, 0, Invalid), Bar::C(true, 42, Invalid));
    patch(
        Bar::C(true, 42, Invalid),
        Bar::D {
            a: true,
            b: 0,
            c: Invalid,
        },
    );
    patch(
        Bar::D {
            a: true,
            b: 0,
            c: Invalid,
        },
        Bar::D {
            a: true,
            b: 42,
            c: Invalid,
        },
    );
    patch(
        Bar::D {
            a: true,
            b: 42,
            c: Invalid,
        },
        Bar::A,
    );
    patch(Zee(false, 0, Invalid), Zee(true, 0, Invalid));
    patch(Zee(false, 0, Invalid), Zee(true, 42, Invalid));
    patch(Zee(false, 0, Invalid), Zee(false, 42, Invalid));
}