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
//! Immutable nested update with structural sharing.
//!
//! `update_in` walks a path into a JSON-like tree, transforms the value at the
//! end, and returns a new root. Every subtree that did not change is shared by
//! pointer, so a one-leaf edit clones only the nodes along the path.
//!
//! # Model
//!
//! Values are [`Value`]: maps, arrays, and scalars, plus an explicit
//! `Undefined` for an absent root and for removal. Arrays and maps sit behind
//! `Rc`, so [`Value::ptr_eq`] reports whether two values share a node.
//!
//! # Behavior
//!
//! - Immutable. The input is never mutated. The result is a mixed clone: deep
//! along the path, shared off it.
//! - No-op identity. If the edit produces no change under `SameValue`, the
//! original root is returned by the same pointer.
//! - Upsert. Missing intermediates are created: a map for a key, an array for
//! an index.
//! - Type coercion. An incompatible container is replaced. A key needs a map,
//! an index needs an array.
//! - Removal. An absent updater, or an updater returning `Undefined`, removes
//! the addressed key or index.
//! - Predicate paths. A path step may be a predicate that selects matching
//! children, branching the update.
//! - Reserved keys. Steps equal to `__proto__`, `constructor`, or `prototype`
//! make the whole call a no-op.
//!
//! # Example
//!
//! ```
//! use simple_update_in::{update_in, Accessor, Value};
//!
//! let from = Value::from_pairs([
//! ("odd", Value::from_pairs([("one", 1.0.into()), ("three", 3.0.into())])),
//! ("even", Value::from_pairs([("two", 2.0.into())])),
//! ]);
//!
//! let path = [Accessor::key("odd"), Accessor::key("one")];
//! let actual = update_in(from.clone(), &path, Some(&|v| match v {
//! Value::Number(n) => Value::Number(n * 10.0),
//! other => other,
//! }));
//!
//! // The off-path subtree is shared.
//! let from_even = from.as_object().unwrap().get("even").unwrap().clone();
//! let actual_even = actual.as_object().unwrap().get("even").unwrap().clone();
//! assert!(from_even.ptr_eq(&actual_even));
//! ```
pub use ;
pub use ;
/// Update the value at `path` and return a new root.
///
/// `path` is a list of [`Accessor`] steps. `updater` is called with the current
/// value at the resolved leaf and returns the new value. `None` removes the
/// leaf. `Some` returning [`Value::Undefined`] also removes it.
///
/// When the edit makes no change under `SameValue`, the original `obj` is
/// returned by the same pointer. Untouched sibling subtrees are shared by
/// pointer too.
///
/// # Example
///
/// ```
/// use simple_update_in::{update_in, Accessor, Value};
///
/// let from = Value::array(vec![0.0.into(), 1.0.into(), 2.0.into()]);
/// let actual = update_in(from, &[Accessor::index(1)], Some(&|_| 3.0.into()));
/// assert_eq!(actual, Value::array(vec![0.0.into(), 3.0.into(), 2.0.into()]));
/// ```
/// Async wrapper over [`update_in`].
///
/// The engine does no IO, so this resolves immediately and returns the same
/// result as [`update_in`]. It exists so async callers can await a single entry
/// point that matches the sync one. The updater and predicates stay synchronous,
/// so the function holds no await point. It is kept `async` on purpose so the
/// call site reads `update_in_async(...).await`.
///
/// # Example
///
/// ```
/// use simple_update_in::{update_in_async, Accessor, Value};
///
/// # async fn run() {
/// let from = Value::from_pairs([("abc", 123.0.into())]);
/// let actual = update_in_async(from, &[Accessor::key("xyz")], Some(&|_| 789.0.into())).await;
/// assert_eq!(
/// actual,
/// Value::from_pairs([("abc", 123.0.into()), ("xyz", 789.0.into())]),
/// );
/// # }
/// ```
pub async