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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// devela::code::result::hook_morph
//
//! Defines [`Hook`], [`hook!`], [`Morph`], [`morph!`].
//!
//! > Threading a value through a sequence of operations.
//
// Based on the code by George Burton, Unlicense licensed.
// https://crates.io/crates/apply/0.3.0
//
// TOC
// - trait Hook
// - macro hook!
// - trait Morph
// - macro morph!
/// Hooks operations into a value without breaking its flow.
///
/// `Hook` provides a way to intercept a value,
/// allowing mutation (`hook`) or observation (`tap`) while preserving identity.
///
/// Use this trait when working with APIs that mutate in place or return `()`,
/// but where fluent sequencing is still desired.
///
/// This is the ergonomic, runtime counterpart of the [`hook!`] macro.
///
/// # Examples
/// ```
/// # extern crate devela as devela;
/// use devela::Hook;
///
/// # #[cfg(feature = "alloc")] {
/// let v = vec![3, 2, 1, 5]
/// .hook(|v| v.sort())
/// .tap(|v| assert_eq![v, &[1, 2, 3, 5]])
/// .hook(|v| v.push(7));
/// assert_eq![v, vec![1, 2, 3, 5, 7]];
/// # }
/// ```
/// # Design
/// `Hook` preserves value identity.
/// For transformations that replace the value, see [`Morph`].
/// Hooks one or more mutation steps into a value and returns it.
///
/// `hook!` binds a value to a local mutable name, applies a sequence of
/// side-effecting operations to it, and then returns the value.
///
/// This macro preserves the value's identity: steps may mutate it, but do not replace it.
///
/// This is the trait-free, const-capable mechanical form of [`Hook`].
///
/// Steps can be written as:
/// - a comma- or semicolon-separated list of expressions, or
/// - a sequence of adjacent `{ ... }` blocks.
///
/// Block syntax is useful when a step requires multiple statements
/// or local control flow.
///
/// All steps are applied in order to the same value.
///
/// # Example
/// ```
/// # use devela::{const_assert, is, hook};
/// /* expression syntax */
/// const ARRAY: [u8; 4] = [3, 1, 4, 1];
/// const DATA: [u8; 4] = hook!(ARRAY; |v| v[0] = 9; v[3] = 7);
/// const_assert![eq_buf &DATA, &[9, 1, 4, 7]];
///
/// /* block syntax */
/// const INPUT: [u8; 4] = [3, 0, 9, 1];
/// const OUTPUT: [u8; 4] = hook!(INPUT, |v| { v[0] = 1; is!(v[2] >7 , v[2] -= 7) } { v[3] += 5 });
/// const_assert![eq_buf &OUTPUT, &[1, 0, 2, 6]];
/// ```
/// For transformations that replace the value, see [`morph!`].
};
// (semicolon separated)
// expr-sequence form
=> ;
// block-sequence form
=> ;
}
pub use hook;
/// Morphs a value by threading it through a function.
///
/// `Morph` provides a fluent way to pass a value (by value, shared reference,
/// or exclusive reference) into a transformation and return the result.
///
/// Unlike [`Hook`], `Morph` does not preserve value identity:
/// each operation yields a new result.
///
/// This is the ergonomic, runtime counterpart of the [`morph!`] macro.
///
/// # Examples
/// ```
/// # extern crate devela as devela;
/// use devela::Morph;
///
/// let x = 3.morph(|v| v * 2).morph(|v| v + 1);
/// assert_eq![x, 7];
/// ```
///
/// ```compile_fail
/// # extern crate devela as devela;
/// use devela::Morph;
///
/// // We can mutate it, but we do not receive the value back.
/// let v: Vec<i32> = vec![3, 2, 1, 5].morph_mut(|it| it.sort());
/// ```
/// Morphs a value through one or more transformation steps and returns the result.
///
/// `morph!` expresses a left-to-right transformation pipeline
/// without explicit intermediate bindings in user code.
///
/// Conceptually, `morph!(x, a, b, c)` corresponds to `c(b(a(x)))`.
///
/// A single binding introduces the pipeline variable,
/// which is reused implicitly by subsequent steps.
/// Each step may change the value's type.
///
/// This macro is const-capable and does not create closures.
/// It is the trait-free mechanical form of [`Morph`].
///
/// Steps can be written as:
/// - a comma-separated list of expressions, or
/// - a semicolon-separated list of expressions.
///
/// # Example
/// ```
/// # use devela::{const_assert, is, morph};
/// const S: &str = morph!(3u8, |v| v as usize, v * 2, v + 1, if v == 7 { "7" } else { "not7" });
/// const_assert![eq_str S, "7"];
/// ```
/// For pipelines that preserve value identity and mutate in place, see [`hook!`].
pub use morph;