4 releases
0.1.3 | Feb 27, 2023 |
---|---|
0.1.2 | Feb 23, 2023 |
0.1.1 | Feb 23, 2023 |
0.1.0 | Feb 22, 2023 |
#783 in Development tools
954 downloads per month
Used in 2 crates
(via pagefind)
10KB
rust-patch
Patch structs with other structs
rust-patch
allows you to avoid boilerplate code when implementing partial updates of Rust structs.
Simply define a patch struct containing a subset of your fields, derive the Patch
trait,
and specify the original struct using the #[patch]
attribute.
Fields of a patch struct may either be of the same type T
as in the original struct or Option<T>
.
In the latter case, the field to be patched will be left unchanged if the corresponding field in the patch is None
This crate is no_std
compatible.
Container attributes
#[patch = "..."]
Set target struct to be patched
use rust_patch::Patch;
struct Item { data: u32 }
#[derive(Patch)]
#[patch = "Item"]
struct ItemPatch { data: Option<u32> }
Field attributes
By default, any fields in the patch of type Option<T>
will be applied as such:
if let Some(val) = patch.field {
target.field = val;
}
this behavior can be changed by the following field attributes.
#[patch(as_option)]
The as_option
attribute allows patching structs where a field itself is already an Option<T>
with the following logic:
if patch.field.is_some() {
target.field = patch.field;
}
Applying this attribute to a field with a type without an is_some()
method results in an error.
#[patch(direct)]
The direct
attribute makes it so that the field is treated like any other T
, meaning it will be applied like this:
target.field = patch.field;
Applying this attribute to a field where the type is not Option<T>
is a no-op.
Example
use rust_patch::Patch;
use serde::Deserialize;
#[derive(PartialEq, Debug)]
struct User {
id: String,
name: String,
email: String,
}
#[derive(Deserialize, Patch)]
#[patch = "User"]
struct UserPatch {
name: Option<String>,
email: Option<String>,
}
let user = User {
id: "6bf25b70-bffa-49e0-905b-2d2e608e3abd".to_string(),
name: "Max Mustermann".to_string(),
email: "max.mustermann@example.org".to_string(),
};
let raw_patch = r#"{
"id": "some invalid id",
"email": "max.mustermann@example.com"
}"#;
let patch: UserPatch = serde_json::from_str(raw_patch).unwrap();
let patched_user = patch.apply(user);
// Since `id` is not part of our `UserPatch` struct it stays unchanged
assert_eq! {
patched_user,
User {
id: "6bf25b70-bffa-49e0-905b-2d2e608e3abd".to_string(),
name: "Max Mustermann".to_string(),
email: "max.mustermann@example.com".to_string()
}
};
Dependencies
~1.5MB
~38K SLoC