#macro-derive #patch #struct #overlay #struct-fields #derive #macro

no-std struct-patch

A library that helps you implement partial updates for your structs

22 releases (7 breaking)

0.8.6 Oct 2, 2024
0.8.4 Aug 27, 2024
0.6.0 Jul 29, 2024
0.4.1 Oct 2, 2023
0.2.3 Mar 4, 2023

#126 in Encoding

Download history 2627/week @ 2024-07-21 3018/week @ 2024-07-28 2679/week @ 2024-08-04 2624/week @ 2024-08-11 2408/week @ 2024-08-18 2320/week @ 2024-08-25 2422/week @ 2024-09-01 2497/week @ 2024-09-08 2328/week @ 2024-09-15 2079/week @ 2024-09-22 4373/week @ 2024-09-29 5298/week @ 2024-10-06 7329/week @ 2024-10-13 7528/week @ 2024-10-20 4194/week @ 2024-10-27 3755/week @ 2024-11-03

22,937 downloads per month
Used in 2 crates

MIT license

35KB
743 lines

Struct Patch

Crates.io MIT licensed Docs

A lib help you patch Rust instance, and easy to partial update configures.

Introduction

This crate provides the Patch trait and an accompanying derive macro.

Deriving Patch on a struct will generate a struct similar to the original one, but with all fields wrapped in an Option.
An instance of such a patch struct can be applied onto the original struct, replacing values only if they are set to Some, leaving them unchanged otherwise.

Quick Example

use struct_patch::Patch;
use serde::{Deserialize, Serialize};

#[derive(Default, Debug, PartialEq, Patch)]
#[patch(attribute(derive(Debug, Default, Deserialize, Serialize)))]
struct Item {
    field_bool: bool,
    field_int: usize,
    field_string: String,
}

fn patch_json() {
    let mut item = Item {
        field_bool: true,
        field_int: 42,
        field_string: String::from("hello"),
    };

    let data = r#"{
        "field_int": 7
    }"#;

    let patch: ItemPatch = serde_json::from_str(data).unwrap();

    item.apply(patch);
    // You can do 
    // `let new_item = item << patch;`

    // For multiple patches,
    // you can do this
    // `let new_item = item << patch_1 << patch_2;`
    // or make an aggregated one, but please make sure the patch fields do not conflict, else will panic
    // ```
    // let overall_patch = patch_1 + patch_2 + patch_3;
    // let new_item = item << overall_patch;
    // ```

    assert_eq!(
        item,
        Item {
            field_bool: true,
            field_int: 7,
            field_string: String::from("hello")
        }
    );
}

Documentation and Examples

Also, you can modify the patch structure by defining #[patch(...)] attributes on the original struct or fields.

Struct attributes:

  • #[patch(name = "...")]: change the name of the generated patch struct.
  • #[patch(attribute(...))]: add attributes to the generated patch struct.
  • #[patch(attribute(derive(...)))]: add derives to the generated patch struct.

Field attributes:

  • #[patch(skip)]: skip the field in the generated patch struct.
  • #[patch(name = "...")]: change the type of the field in the generated patch struct.
  • #[patch(attribute(...))]: add attributes to the field in the generated patch struct.
  • #[patch(attribute(derive(...)))]: add derives to the field in the generated patch struct.

Please check the traits of document to learn more.

The examples demo following scenarios.

  • diff two instance for a patch
  • create a patch from json string
  • rename the patch structure
  • check a patch is empty or not
  • add attribute to patch struct
  • show option field behavior
  • show operators about patches

Features

This crate also includes the following optional features:

  • status(default): implements the PatchStatus trait for the patch struct, which provides the is_empty method.
  • op (default): provide operators << between instance and patch, and + for patches
    • default: when there is a field conflict between patches, + will add together if the #[patch(addable)] or #[patch(add=fn)] is provided, else it will panic.
    • merge (optional): implements the Merge trait for the patch struct, which provides the merge method, and << between patches.
  • std(optional):
    • box: implements the Patch<Box<P>> trait for T where T implements Patch<P>. This let you patch a boxed (or not) struct with a boxed patch.
    • option: implements the Patch<Option<P>> trait for Option<T> where T implements Patch<P>, please take a look at the example to learn more.
      • default: T needs to implement From<P>. When patching on None, it will based on from<P> to cast T, and this let you patch structs containing fields with optional values.
      • none_as_default: T needs to implement Default. When patching on None, it will patch on a default instance, and this also let you patch structs containing fields with optional values.
      • keep_none: When patching on None, it is still None.

Dependencies

~230–680KB
~16K SLoC