1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! A framework for creating updatable data structures with diff, update, and merge capabilities.
//!
//! `structupdate` provides a derive macro and runtime types for building complex data structures
//! that support:
//!
//! - **Type-safe updates**: Modify structures through strongly-typed update operations
//! - **Efficient diffing**: Compute minimal differences between two instances
//! - **Merge operations**: Combine structures for templating scenarios
//! - **Serialization**: Full serde support for all types
//!
//! # Quick Start
//!
//! ```rust
//! use structupdate::{structupdate, Node, Value, ValueMap};
//!
//! #[structupdate]
//! // #[structupdate] only works on types that are Clone + PartialEq + Default
//! #[derive(Debug, Clone, Default, PartialEq)]
//! pub struct Config {
//! pub name: Value<String>,
//! pub settings: ValueMap<String, u32>,
//! }
//!
//! // Create a default instance
//! let mut config = Config::default();
//! // Keep a copy of the original value for the sake of the example
//! let original = config.clone();
//!
//! // Build an update
//! let mut update = Config::build_update();
//! update
//! .name_set("my-config".to_string())
//! .settings_set("timeout".to_string(), 30);
//!
//! // Apply the update
//! config.apply_update(update);
//!
//! // Compute diff between instances
//! if let Some(diff) = original.compute_diff(&config) {
//! // diff contains only the changes
//! }
//! ```
//!
//! # Values vs Records
//!
//! This crate distinguishes between **values** and **records**:
//!
//! - A **value** is a leaf type (e.g., `String`, `u32`, `bool`) that is replaced
//! atomically when updated. Values are wrapped in types like [`Value<V>`],
//! [`OptValue<V>`], [`ValueList<V>`], [`ValueSet<K>`], or [`ValueMap<K, V>`].
//!
//! - A **record** is a nested struct that also uses `#[structupdate]` and implements
//! the [`Node`] trait. Records support in-place updates to their fields without
//! replacing the entire struct. Records appear in types like [`OptRecord<R>`],
//! [`RecordMap<K, R>`], or directly as struct fields.
//!
//! This distinction matters for updates: when you update a value, you replace it
//! entirely; when you update a record, you can modify individual fields within it.
//!
//! # Field Types
//!
//! The macro recognizes these wrapper types for struct fields:
//!
//! | Type | Description |
//! |------|-------------|
//! | [`Value<V>`] | A required value with optional custom default |
//! | [`OptValue<V>`] | An optional value (can be cleared) |
//! | [`OptRecord<R>`] | An optional nested record |
//! | [`ValueList<V>`] | An ordered list of values |
//! | [`ValueSet<K>`] | A set of unique values |
//! | [`ValueMap<K, V>`] | A key-value mapping |
//! | [`RecordMap<K, R>`] | A map of nested records |
//!
//! # The `#[structupdate]` Macro
//!
//! When applied to a struct, the macro generates:
//!
//! - A `{StructName}Update` that represents a set of changes to
//! update a `StructName` value
//! - A `{StructName}Diff` type for representing differences between
//! two `StructName` values
//! - Implementation of the [`Node`] trait
//! - Builder methods on the `{StructName}Update` type
//!
//! ## Macro Attributes
//!
//! ### Struct-level: `#[mark(...)]`
//!
//! This is an optional attribute which adds a metadata field to the
//! struct for tracking purposes:
//!
//! ```rust
//! # use structupdate::structupdate;
//! # use structupdate::Value;
//!
//! #[structupdate]
//! #[mark(serde_skip, type = bool)]
//! #[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
//! pub struct Record {
//! pub field: Value<String>,
//! }
//! ```
//!
//! Options:
//! - `type = T`: The type of the mark field (required)
//! - `serde_skip`: Skip the mark field when serializing/deserializing
//! the type. This option is only valid when the type derives the
//! `serde::Serialize` and/or `serde::Deserialize`
//!
//! ### Field-level: `#[structupdate(init_with = ...)]`
//!
//! Specify a custom default value constructor for [`Value<V>`] fields:
//!
//! ```rust
//! # use structupdate::structupdate;
//! # use structupdate::Value;
//! fn default_timeout() -> u32 { 30 }
//!
//! #[structupdate]
//! #[derive(Debug, PartialEq, Eq, Clone)]
//! pub struct Config {
//! #[structupdate(init_with = default_timeout)]
//! pub timeout: Value<u32>,
//! }
//! ```
//!
//! # Generated Update API
//!
//! For each field, the macro generates builder methods on the update type:
//!
//! | Field Type | Generated Methods |
//! |------------|-------------------|
//! | `Value<V>` | `field_set(v)`, `field_set_to_default()` |
//! | `OptValue<V>` | `field_set(v)`, `field_clear()` |
//! | `OptRecord<R>` | `field_set(r)`, `field_clear()`, `field_update(u)`, `field_amend(f)` |
//! | `ValueList<V>` | `field_append(v)`, `field_prepend(v)`, `field_pop_last()`, etc. |
//! | `ValueSet<K>` | `field_add(k)`, `field_del(k)`, `field_clear()`, `field_extend(iter)` |
//! | `ValueMap<K,V>` | `field_set(k, v)`, `field_del(k)`, `field_clear()` |
//! | `RecordMap<K,R>` | `field_amend(k, f)`, `field_try_amend(k, f)`, `field_del(k)` |
//! | Nested struct | `field_amend(f)` |
//!
//! # The `Node` Trait
//!
//! All updatable types implement the [`Node`] trait, which provides:
//!
//! - [`apply_update`](Node::apply_update): Apply an update to modify the structure
//! - [`compute_diff`](Node::compute_diff): Calculate differences between instances
//! - [`apply_diff`](Node::apply_diff): Apply a diff to transform the structure
//! - [`merge`](Node::merge): Merge values for templating
//!
//! # Default Value Helpers
//!
//! The [`defaults`] module provides helper functions for
//! creating [`Value`] instances with custom defaults:
//!
//! ```rust
//! use structupdate::defaults::{value_true, default_string, default_u32};
//!
//! // These return closures suitable for init_with
//! let make_name = default_string("unnamed");
//! let make_timeout = default_u32(30);
//! ```
extern crate structupdate_macros;
pub use structupdate;
pub use *;