valuable/visit.rs
1use crate::*;
2
3/// Traverse a value's fields and variants.
4///
5/// Each method of the `Visit` trait is a hook that enables the implementor to
6/// observe value fields. By default, most methods are implemented as a no-op.
7/// The `visit_primitive_slice` default implementation will iterate the slice,
8/// calling `visit_value` with each item.
9///
10/// To recurse, the implementor must implement methods to visit the arguments.
11///
12/// # Examples
13///
14/// Recursively printing a Rust value.
15///
16/// ```
17/// use valuable::{NamedValues, Valuable, Value, Visit};
18///
19/// struct Print(String);
20///
21/// impl Print {
22/// fn indent(&self) -> Print {
23/// Print(format!("{} ", self.0))
24/// }
25/// }
26///
27/// impl Visit for Print {
28/// fn visit_value(&mut self, value: Value<'_>) {
29/// match value {
30/// Value::Structable(v) => {
31/// let def = v.definition();
32/// // Print the struct name
33/// println!("{}{}:", self.0, def.name());
34///
35/// // Visit fields
36/// let mut visit = self.indent();
37/// v.visit(&mut visit);
38/// }
39/// Value::Enumerable(v) => {
40/// let def = v.definition();
41/// let variant = v.variant();
42/// // Print the enum name
43/// println!("{}{}::{}:", self.0, def.name(), variant.name());
44///
45/// // Visit fields
46/// let mut visit = self.indent();
47/// v.visit(&mut visit);
48/// }
49/// Value::Listable(v) => {
50/// println!("{}", self.0);
51///
52/// // Visit fields
53/// let mut visit = self.indent();
54/// v.visit(&mut visit);
55/// }
56/// Value::Mappable(v) => {
57/// println!("{}", self.0);
58///
59/// // Visit fields
60/// let mut visit = self.indent();
61/// v.visit(&mut visit);
62/// }
63/// // Primitive or unknown type, just render Debug
64/// v => println!("{:?}", v),
65/// }
66/// }
67///
68/// fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) {
69/// for (field, value) in named_values {
70/// print!("{}- {}: ", self.0, field.name());
71/// value.visit(self);
72/// }
73/// }
74///
75/// fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) {
76/// for value in values {
77/// print!("{}- ", self.0);
78/// value.visit(self);
79/// }
80/// }
81///
82/// fn visit_entry(&mut self, key: Value<'_>, value: Value<'_>) {
83/// print!("{}- {:?}: ", self.0, key);
84/// value.visit(self);
85/// }
86/// }
87///
88/// #[derive(Valuable)]
89/// struct Person {
90/// name: String,
91/// age: u32,
92/// addresses: Vec<Address>,
93/// }
94///
95/// #[derive(Valuable)]
96/// struct Address {
97/// street: String,
98/// city: String,
99/// zip: String,
100/// }
101///
102/// let person = Person {
103/// name: "Angela Ashton".to_string(),
104/// age: 31,
105/// addresses: vec![
106/// Address {
107/// street: "123 1st Ave".to_string(),
108/// city: "Townsville".to_string(),
109/// zip: "12345".to_string(),
110/// },
111/// Address {
112/// street: "555 Main St.".to_string(),
113/// city: "New Old Town".to_string(),
114/// zip: "55555".to_string(),
115/// },
116/// ],
117/// };
118///
119/// let mut print = Print("".to_string());
120/// valuable::visit(&person, &mut print);
121/// ```
122pub trait Visit {
123 /// Visit a single value.
124 ///
125 /// The `visit_value` method is called once when visiting single primitive
126 /// values. When visiting `Listable` types, the `visit_value` method is
127 /// called once per item in the listable type.
128 ///
129 /// Note, in the case of Listable types containing primitive types,
130 /// `visit_primitive_slice` can be implemented instead for less overhead.
131 ///
132 /// # Examples
133 ///
134 /// Visiting a single value.
135 ///
136 /// ```
137 /// use valuable::{Valuable, Visit, Value};
138 ///
139 /// struct Print;
140 ///
141 /// impl Visit for Print {
142 /// fn visit_value(&mut self, value: Value<'_>) {
143 /// println!("{:?}", value);
144 /// }
145 /// }
146 ///
147 /// let my_val = 123;
148 /// my_val.visit(&mut Print);
149 /// ```
150 ///
151 /// Visiting multiple values in a list.
152 ///
153 /// ```
154 /// use valuable::{Valuable, Value, Visit};
155 ///
156 /// struct PrintList { comma: bool };
157 ///
158 /// impl Visit for PrintList {
159 /// fn visit_value(&mut self, value: Value<'_>) {
160 /// match value {
161 /// Value::Listable(v) => v.visit(self),
162 /// value => {
163 /// if self.comma {
164 /// println!(", {:?}", value);
165 /// } else {
166 /// print!("{:?}", value);
167 /// self.comma = true;
168 /// }
169 /// }
170 /// }
171 /// }
172 /// }
173 ///
174 /// let my_list = vec![1, 2, 3, 4, 5];
175 /// valuable::visit(&my_list, &mut PrintList { comma: false });
176 /// ```
177 fn visit_value(&mut self, value: Value<'_>);
178
179 /// Visit a struct or enum's named fields.
180 ///
181 /// When the struct/enum is statically defined, all fields are known ahead
182 /// of time and `visit_named_fields` is called once with all field values.
183 /// When the struct/enum is dynamic, then the `visit_named_fields` method
184 /// may be called multiple times.
185 ///
186 /// See [`Structable`] and [`Enumerable`] for static vs. dynamic details.
187 ///
188 /// # Examples
189 ///
190 /// Visiting all fields in a struct.
191 ///
192 /// ```
193 /// use valuable::{NamedValues, Valuable, Value, Visit};
194 ///
195 /// #[derive(Valuable)]
196 /// struct MyStruct {
197 /// hello: String,
198 /// world: u32,
199 /// }
200 ///
201 /// struct Print;
202 ///
203 /// impl Visit for Print {
204 /// fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) {
205 /// for (field, value) in named_values {
206 /// println!("{:?}: {:?}", field, value);
207 /// }
208 /// }
209 ///
210 /// fn visit_value(&mut self, value: Value<'_>) {
211 /// match value {
212 /// Value::Structable(v) => v.visit(self),
213 /// _ => {} // do nothing for other types
214 /// }
215 /// }
216 /// }
217 ///
218 /// let my_struct = MyStruct {
219 /// hello: "Hello world".to_string(),
220 /// world: 42,
221 /// };
222 ///
223 /// valuable::visit(&my_struct, &mut Print);
224 /// ```
225 fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) {
226 let _ = named_values;
227 }
228
229 /// Visit a struct or enum's unnamed fields.
230 ///
231 /// When the struct/enum is statically defined, all fields are known ahead
232 /// of time and `visit_unnamed_fields` is called once with all field values.
233 /// When the struct/enum is dynamic, then the `visit_unnamed_fields` method
234 /// may be called multiple times.
235 ///
236 /// See [`Structable`] and [`Enumerable`] for static vs. dynamic details.
237 ///
238 /// # Examples
239 ///
240 /// Visiting all fields in a struct.
241 ///
242 /// ```
243 /// use valuable::{Valuable, Value, Visit};
244 ///
245 /// #[derive(Valuable)]
246 /// struct MyStruct(String, u32);
247 ///
248 /// struct Print;
249 ///
250 /// impl Visit for Print {
251 /// fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) {
252 /// for value in values {
253 /// println!("{:?}", value);
254 /// }
255 /// }
256 ///
257 /// fn visit_value(&mut self, value: Value<'_>) {
258 /// match value {
259 /// Value::Structable(v) => v.visit(self),
260 /// _ => {} // do nothing for other types
261 /// }
262 /// }
263 /// }
264 ///
265 /// let my_struct = MyStruct("Hello world".to_string(), 42);
266 ///
267 /// valuable::visit(&my_struct, &mut Print);
268 /// ```
269 fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) {
270 let _ = values;
271 }
272
273 /// Visit a primitive slice.
274 ///
275 /// This method exists as an optimization when visiting [`Listable`] types.
276 /// By default, `Listable` types are visited by passing each item to
277 /// `visit_value`. However, if the listable stores a **primitive** type
278 /// within contiguous memory, then `visit_primitive_slice` is called
279 /// instead.
280 ///
281 /// When implementing `visit_primitive_slice`, be aware that the method may
282 /// be called multiple times for a single `Listable` type.
283 ///
284 /// # Examples
285 ///
286 /// A vec calls `visit_primitive_slice` one time, but a `VecDeque` will call
287 /// `visit_primitive_slice` twice.
288 ///
289 /// ```
290 /// use valuable::{Valuable, Value, Visit, Slice};
291 /// use std::collections::VecDeque;
292 ///
293 /// struct Count(u32);
294 ///
295 /// impl Visit for Count {
296 /// fn visit_primitive_slice(&mut self, slice: Slice<'_>) {
297 /// self.0 += 1;
298 /// }
299 ///
300 /// fn visit_value(&mut self, value: Value<'_>) {
301 /// match value {
302 /// Value::Listable(v) => v.visit(self),
303 /// _ => {} // do nothing for other types
304 /// }
305 /// }
306 /// }
307 ///
308 /// let vec = vec![1, 2, 3, 4, 5];
309 ///
310 /// let mut count = Count(0);
311 /// valuable::visit(&vec, &mut count);
312 /// assert_eq!(1, count.0);
313 ///
314 /// let mut vec_deque = VecDeque::from(vec);
315 ///
316 /// let mut count = Count(0);
317 /// valuable::visit(&vec_deque, &mut count);
318 ///
319 /// assert_eq!(2, count.0);
320 /// ```
321 fn visit_primitive_slice(&mut self, slice: Slice<'_>) {
322 for value in slice {
323 self.visit_value(value);
324 }
325 }
326
327 /// Visit a `Mappable`'s entries.
328 ///
329 /// The `visit_entry` method is called once for each entry contained by a
330 /// `Mappable.`
331 ///
332 /// # Examples
333 ///
334 /// Visit a map's entries
335 ///
336 /// ```
337 /// use valuable::{Valuable, Value, Visit};
338 /// use std::collections::HashMap;
339 ///
340 /// let mut map = HashMap::new();
341 /// map.insert("hello", 123);
342 /// map.insert("world", 456);
343 ///
344 /// struct Print;
345 ///
346 /// impl Visit for Print {
347 /// fn visit_entry(&mut self, key: Value<'_>, value: Value<'_>) {
348 /// println!("{:?} => {:?}", key, value);
349 /// }
350 ///
351 /// fn visit_value(&mut self, value: Value<'_>) {
352 /// match value {
353 /// Value::Mappable(v) => v.visit(self),
354 /// _ => {} // do nothing for other types
355 /// }
356 /// }
357 /// }
358 ///
359 /// valuable::visit(&map, &mut Print);
360 /// ```
361 fn visit_entry(&mut self, key: Value<'_>, value: Value<'_>) {
362 let _ = (key, value);
363 }
364}
365
366macro_rules! deref {
367 (
368 $(
369 $(#[$attrs:meta])*
370 $ty:ty,
371 )*
372 ) => {
373 $(
374 $(#[$attrs])*
375 impl<T: ?Sized + Visit> Visit for $ty {
376 fn visit_value(&mut self, value: Value<'_>) {
377 T::visit_value(&mut **self, value)
378 }
379
380 fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) {
381 T::visit_named_fields(&mut **self, named_values)
382 }
383
384 fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) {
385 T::visit_unnamed_fields(&mut **self, values)
386 }
387
388 fn visit_primitive_slice(&mut self, slice: Slice<'_>) {
389 T::visit_primitive_slice(&mut **self, slice)
390 }
391
392 fn visit_entry(&mut self, key: Value<'_>, value: Value<'_>) {
393 T::visit_entry(&mut **self, key, value)
394 }
395 }
396 )*
397 };
398}
399
400deref! {
401 &mut T,
402 #[cfg(feature = "alloc")]
403 alloc::boxed::Box<T>,
404}
405
406/// Inspects a value by calling the relevant [`Visit`] methods with `value`'s
407/// data.
408///
409/// This method calls [`Visit::visit_value()`] with the provided [`Valuable`]
410/// instance. See [`Visit`] documentation for more details.
411///
412/// # Examples
413///
414/// Extract a single field from a struct. Note: if the same field is repeatedly
415/// extracted from a struct, it is preferable to obtain the associated
416/// [`NamedField`] once and use it repeatedly.
417///
418/// ```
419/// use valuable::{NamedValues, Valuable, Value, Visit};
420///
421/// #[derive(Valuable)]
422/// struct MyStruct {
423/// foo: usize,
424/// bar: usize,
425/// }
426///
427/// struct GetFoo(usize);
428///
429/// impl Visit for GetFoo {
430/// fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) {
431/// if let Some(foo) = named_values.get_by_name("foo") {
432/// if let Some(val) = foo.as_usize() {
433/// self.0 = val;
434/// }
435/// }
436/// }
437///
438/// fn visit_value(&mut self, value: Value<'_>) {
439/// if let Value::Structable(v) = value {
440/// v.visit(self);
441/// }
442/// }
443/// }
444///
445/// let my_struct = MyStruct {
446/// foo: 123,
447/// bar: 456,
448/// };
449///
450/// let mut get_foo = GetFoo(0);
451/// valuable::visit(&my_struct, &mut get_foo);
452///
453/// assert_eq!(123, get_foo.0);
454/// ```
455///
456/// [`Visit`]: Visit [`NamedField`]: crate::NamedField
457pub fn visit(value: &impl Valuable, visit: &mut dyn Visit) {
458 visit.visit_value(value.as_value());
459}