Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/yanganto/struct-patch
A lib help you patch Rust instance, and easy to partial update configures.
https://github.com/yanganto/struct-patch
derive macro overlay patch rust struct
Last synced: 6 days ago
JSON representation
A lib help you patch Rust instance, and easy to partial update configures.
- Host: GitHub
- URL: https://github.com/yanganto/struct-patch
- Owner: yanganto
- License: mit
- Created: 2023-01-17T13:08:36.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-10-29T02:05:45.000Z (16 days ago)
- Last Synced: 2024-10-29T03:17:57.733Z (16 days ago)
- Topics: derive, macro, overlay, patch, rust, struct
- Language: Rust
- Homepage:
- Size: 117 KB
- Stars: 20
- Watchers: 2
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Struct Patch
[![Crates.io][crates-badge]][crate-url]
[![MIT licensed][mit-badge]][mit-url]
[![Docs][doc-badge]][doc-url]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
```rust
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][doc-traits] of document to learn more.
The [examples][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
- show example with serde crates, ex: `humantime_serde` for duration## 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>` trait for `T` where `T` implements `Patch`.
This let you patch a boxed (or not) struct with a boxed patch.
- `option`: implements the `Patch>` trait for `Option` where `T` implements `Patch`, please take a look at the example to learn more.
- default: `T` needs to implement `From`. When patching on None, it will based on `from
` 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.[crates-badge]: https://img.shields.io/crates/v/struct-patch.svg
[crate-url]: https://crates.io/crates/struct-patch
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
[mit-url]: https://github.com/yanganto/struct-patch/blob/readme/LICENSE
[doc-badge]: https://img.shields.io/badge/docs-rs-orange.svg
[doc-url]: https://docs.rs/struct-patch/
[doc-traits]: https://docs.rs/struct-patch/latest/struct_patch/traits/trait.Patch.html#container-attributes
[examples]: /struct-patch/examples