rust-patch 0.1.3

Patch structs with other structs
Documentation
use std::fmt::Debug;

use rust_patch::Patch;

#[derive(Copy, Clone, Debug, PartialEq)]
struct Item {
    data: u32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct IdItem {
    id: u32,
    data: u32,
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct UnnamedItem(u32);

#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitItem;

#[derive(Copy, Clone, Debug, PartialEq)]
struct OptItem {
    data: Option<u32>,
}

#[derive(Patch)]
#[patch = "Item"]
#[patch = "IdItem"]
#[patch = "item::ModItem"]
struct ItemPatch {
    data: Option<u32>,
}

#[derive(Patch)]
#[patch = "IdItem"]
struct DataPatch {
    data: u32,
}

#[derive(Patch)]
#[patch = "UnnamedItem"]
struct UnnamedPatch(Option<u32>);

#[derive(Patch)]
#[patch = "Item"]
#[patch = "IdItem"]
#[patch = "UnitItem"]
struct UnitPatch;

#[derive(Patch)]
#[patch = "OptItem"]
struct DirectPatch {
    #[patch(direct)]
    data: Option<u32>,
}

#[derive(Patch)]
#[patch = "OptItem"]
struct OptPatch {
    #[patch(as_option)]
    data: Option<u32>,
}

mod item {
    #[derive(Copy, Clone, Debug, PartialEq)]
    pub struct ModItem {
        pub data: u32,
    }
}

fn test_patch<T: PartialEq + Debug, P: Patch<T>>(data: T, patch: P, expected: T) {
    let res = patch.apply(data);
    assert_eq!(expected, res);
}

#[test]
fn basic() {
    test_patch(
        Item { data: 0 },
        ItemPatch { data: Some(1) },
        Item { data: 1 },
    );
}

#[test]
fn empty_patch() {
    test_patch(Item { data: 0 }, ItemPatch { data: None }, Item { data: 0 });
}

#[test]
fn extra_field() {
    test_patch(
        IdItem { id: 10, data: 0 },
        ItemPatch { data: Some(1) },
        IdItem { id: 10, data: 1 },
    );
}

#[test]
fn mandatory_field() {
    test_patch(
        IdItem { id: 10, data: 0 },
        DataPatch { data: 1 },
        IdItem { id: 10, data: 1 },
    );
}

#[test]
fn unnamed_struct() {
    test_patch(UnnamedItem(0), UnnamedPatch(Some(1)), UnnamedItem(1));
}

#[test]
fn unit_struct() {
    test_patch(UnitItem, UnitPatch, UnitItem);
}

#[test]
fn patch_mod() {
    test_patch(
        item::ModItem { data: 10 },
        ItemPatch { data: Some(5) },
        item::ModItem { data: 5 },
    )
}

#[test]
fn patch_direct() {
    test_patch(
        OptItem { data: Some(1) },
        DirectPatch { data: None },
        OptItem { data: None },
    );
    test_patch(
        OptItem { data: Some(1) },
        DirectPatch { data: Some(0) },
        OptItem { data: Some(0) },
    );
}

#[test]
fn patch_as_option() {
    test_patch(
        OptItem { data: Some(1) },
        OptPatch { data: None },
        OptItem { data: Some(1) },
    );
    test_patch(
        OptItem { data: Some(1) },
        OptPatch { data: Some(0) },
        OptItem { data: Some(0) },
    );
}