structupdate 0.4.0

A library for defining complex updatable datastructures
Documentation
//! 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_macros::structupdate;
pub use structupdate_support::*;