value_bag/
visit.rs

1//! Value inspection.
2//!
3//! The [`Visit`] trait provides a simple visitor API that can be used to inspect
4//! the structure of primitives stored in a [`ValueBag`](../struct.ValueBag.html).
5//! More complex datatypes can then be handled using `std::fmt`, `sval`, or `serde`.
6//!
7//! ```
8//! # #[cfg(not(feature = "std"))] fn main() {}
9//! # #[cfg(feature = "std")]
10//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
11//! # fn escape(buf: &[u8]) -> &[u8] { buf }
12//! # fn itoa_fmt<T>(num: T) -> Vec<u8> { vec![] }
13//! # fn ryu_fmt<T>(num: T) -> Vec<u8> { vec![] }
14//! # use std::io::Write;
15//! use value_bag::{ValueBag, Error, visit::Visit};
16//!
17//! // Implement some simple custom serialization
18//! struct MyVisit(Vec<u8>);
19//! impl<'v> Visit<'v> for MyVisit {
20//!     fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> {
21//!         // Fallback to `Debug` if we didn't visit the value specially
22//!         write!(&mut self.0, "{:?}", v).map_err(|_| Error::msg("failed to write value"))
23//!     }
24//!
25//!     fn visit_u64(&mut self, v: u64) -> Result<(), Error> {
26//!         self.0.extend_from_slice(itoa_fmt(v).as_slice());
27//!         Ok(())
28//!     }
29//!
30//!     fn visit_i64(&mut self, v: i64) -> Result<(), Error> {
31//!         self.0.extend_from_slice(itoa_fmt(v).as_slice());
32//!         Ok(())
33//!     }
34//!
35//!     fn visit_f64(&mut self, v: f64) -> Result<(), Error> {
36//!         self.0.extend_from_slice(ryu_fmt(v).as_slice());
37//!         Ok(())
38//!     }
39//!
40//!     fn visit_str(&mut self, v: &str) -> Result<(), Error> {
41//!         self.0.push(b'\"');
42//!         self.0.extend_from_slice(escape(v.as_bytes()));
43//!         self.0.push(b'\"');
44//!         Ok(())
45//!     }
46//!
47//!     fn visit_bool(&mut self, v: bool) -> Result<(), Error> {
48//!         self.0.extend_from_slice(if v { b"true" } else { b"false" });
49//!         Ok(())
50//!     }
51//! }
52//!
53//! let value = ValueBag::from(42i64);
54//!
55//! let mut visitor = MyVisit(vec![]);
56//! value.visit(&mut visitor)?;
57//! # Ok(())
58//! # }
59//! ```
60
61use crate::{
62    internal::{self, InternalVisitor},
63    Error, ValueBag,
64};
65
66/// A visitor for a `ValueBag`.
67pub trait Visit<'v> {
68    /// Visit a `ValueBag`.
69    ///
70    /// This is the only required method on `Visit` and acts as a fallback for any
71    /// more specific methods that aren't overridden.
72    /// The `ValueBag` may be formatted using its `fmt::Debug` or `fmt::Display` implementation,
73    /// or serialized using its `sval::Value` or `serde::Serialize` implementation.
74    fn visit_any(&mut self, value: ValueBag) -> Result<(), Error>;
75
76    /// Visit an empty value.
77    #[inline]
78    fn visit_empty(&mut self) -> Result<(), Error> {
79        self.visit_any(ValueBag::empty())
80    }
81
82    /// Visit an unsigned integer.
83    #[inline]
84    fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
85        self.visit_any(value.into())
86    }
87
88    /// Visit a signed integer.
89    #[inline]
90    fn visit_i64(&mut self, value: i64) -> Result<(), Error> {
91        self.visit_any(value.into())
92    }
93
94    /// Visit a big unsigned integer.
95    #[inline]
96    fn visit_u128(&mut self, value: u128) -> Result<(), Error> {
97        self.visit_any((&value).into())
98    }
99
100    /// Visit a big signed integer.
101    #[inline]
102    fn visit_i128(&mut self, value: i128) -> Result<(), Error> {
103        self.visit_any((&value).into())
104    }
105
106    /// Visit a floating point.
107    #[inline]
108    fn visit_f64(&mut self, value: f64) -> Result<(), Error> {
109        self.visit_any(value.into())
110    }
111
112    /// Visit a boolean.
113    #[inline]
114    fn visit_bool(&mut self, value: bool) -> Result<(), Error> {
115        self.visit_any(value.into())
116    }
117
118    /// Visit a string.
119    #[inline]
120    fn visit_str(&mut self, value: &str) -> Result<(), Error> {
121        self.visit_any(value.into())
122    }
123
124    /// Visit a string.
125    #[inline]
126    fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
127        self.visit_str(value)
128    }
129
130    /// Visit a Unicode character.
131    #[inline]
132    fn visit_char(&mut self, value: char) -> Result<(), Error> {
133        let mut b = [0; 4];
134        self.visit_str(&*value.encode_utf8(&mut b))
135    }
136
137    /// Visit an error.
138    #[inline]
139    #[cfg(feature = "error")]
140    fn visit_error(&mut self, err: &(dyn crate::std::error::Error + 'static)) -> Result<(), Error> {
141        self.visit_any(ValueBag::from_dyn_error(err))
142    }
143
144    /// Visit an error.
145    #[inline]
146    #[cfg(feature = "error")]
147    fn visit_borrowed_error(
148        &mut self,
149        err: &'v (dyn crate::std::error::Error + 'static),
150    ) -> Result<(), Error> {
151        self.visit_any(ValueBag::from_dyn_error(err))
152    }
153}
154
155impl<'a, 'v, T: ?Sized> Visit<'v> for &'a mut T
156where
157    T: Visit<'v>,
158{
159    #[inline]
160    fn visit_any(&mut self, value: ValueBag) -> Result<(), Error> {
161        (**self).visit_any(value)
162    }
163
164    #[inline]
165    fn visit_empty(&mut self) -> Result<(), Error> {
166        (**self).visit_empty()
167    }
168
169    #[inline]
170    fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
171        (**self).visit_u64(value)
172    }
173
174    #[inline]
175    fn visit_i64(&mut self, value: i64) -> Result<(), Error> {
176        (**self).visit_i64(value)
177    }
178
179    #[inline]
180    fn visit_u128(&mut self, value: u128) -> Result<(), Error> {
181        (**self).visit_u128(value)
182    }
183
184    #[inline]
185    fn visit_i128(&mut self, value: i128) -> Result<(), Error> {
186        (**self).visit_i128(value)
187    }
188
189    #[inline]
190    fn visit_f64(&mut self, value: f64) -> Result<(), Error> {
191        (**self).visit_f64(value)
192    }
193
194    #[inline]
195    fn visit_bool(&mut self, value: bool) -> Result<(), Error> {
196        (**self).visit_bool(value)
197    }
198
199    #[inline]
200    fn visit_str(&mut self, value: &str) -> Result<(), Error> {
201        (**self).visit_str(value)
202    }
203
204    #[inline]
205    fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
206        (**self).visit_borrowed_str(value)
207    }
208
209    #[inline]
210    fn visit_char(&mut self, value: char) -> Result<(), Error> {
211        (**self).visit_char(value)
212    }
213
214    #[inline]
215    #[cfg(feature = "error")]
216    fn visit_error(&mut self, err: &(dyn crate::std::error::Error + 'static)) -> Result<(), Error> {
217        (**self).visit_error(err)
218    }
219
220    #[inline]
221    #[cfg(feature = "error")]
222    fn visit_borrowed_error(
223        &mut self,
224        err: &'v (dyn crate::std::error::Error + 'static),
225    ) -> Result<(), Error> {
226        (**self).visit_borrowed_error(err)
227    }
228}
229
230impl<'v> ValueBag<'v> {
231    /// Visit this value using a simple visitor.
232    ///
233    /// The visitor isn't strictly required to inspect the contents of a value bag.
234    /// It's useful for simple cases where a full framework like `serde` or `sval`
235    /// isn't necessary.
236    pub fn visit(&self, visitor: impl Visit<'v>) -> Result<(), Error> {
237        struct Visitor<V>(V);
238
239        impl<'v, V> InternalVisitor<'v> for Visitor<V>
240        where
241            V: Visit<'v>,
242        {
243            fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> {
244                v.fill(crate::fill::Slot::new(self))
245            }
246
247            fn debug(&mut self, v: &dyn internal::fmt::Debug) -> Result<(), Error> {
248                self.0.visit_any(ValueBag::from_dyn_debug(v))
249            }
250
251            fn display(&mut self, v: &dyn internal::fmt::Display) -> Result<(), Error> {
252                self.0.visit_any(ValueBag::from_dyn_display(v))
253            }
254
255            fn u64(&mut self, v: u64) -> Result<(), Error> {
256                self.0.visit_u64(v)
257            }
258
259            fn i64(&mut self, v: i64) -> Result<(), Error> {
260                self.0.visit_i64(v)
261            }
262
263            fn u128(&mut self, v: &u128) -> Result<(), Error> {
264                self.0.visit_u128(*v)
265            }
266
267            fn i128(&mut self, v: &i128) -> Result<(), Error> {
268                self.0.visit_i128(*v)
269            }
270
271            fn f64(&mut self, v: f64) -> Result<(), Error> {
272                self.0.visit_f64(v)
273            }
274
275            fn bool(&mut self, v: bool) -> Result<(), Error> {
276                self.0.visit_bool(v)
277            }
278
279            fn char(&mut self, v: char) -> Result<(), Error> {
280                self.0.visit_char(v)
281            }
282
283            fn str(&mut self, v: &str) -> Result<(), Error> {
284                self.0.visit_str(v)
285            }
286
287            fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {
288                self.0.visit_borrowed_str(v)
289            }
290
291            fn none(&mut self) -> Result<(), Error> {
292                self.0.visit_empty()
293            }
294
295            #[cfg(feature = "error")]
296            fn error(&mut self, v: &(dyn internal::error::Error + 'static)) -> Result<(), Error> {
297                self.0.visit_error(v)
298            }
299
300            #[cfg(feature = "error")]
301            fn borrowed_error(
302                &mut self,
303                v: &'v (dyn internal::error::Error + 'static),
304            ) -> Result<(), Error> {
305                self.0.visit_borrowed_error(v)
306            }
307
308            #[cfg(feature = "sval2")]
309            fn sval2(&mut self, v: &dyn internal::sval::v2::Value) -> Result<(), Error> {
310                if internal::sval::v2::internal_visit(v, self) {
311                    Ok(())
312                } else {
313                    self.0.visit_any(ValueBag::from_dyn_sval2(v))
314                }
315            }
316
317            #[cfg(feature = "sval2")]
318            fn borrowed_sval2(
319                &mut self,
320                v: &'v dyn internal::sval::v2::Value,
321            ) -> Result<(), Error> {
322                if internal::sval::v2::borrowed_internal_visit(v, self) {
323                    Ok(())
324                } else {
325                    self.0.visit_any(ValueBag::from_dyn_sval2(v))
326                }
327            }
328
329            #[cfg(feature = "serde1")]
330            fn serde1(&mut self, v: &dyn internal::serde::v1::Serialize) -> Result<(), Error> {
331                if internal::serde::v1::internal_visit(v, self) {
332                    Ok(())
333                } else {
334                    self.0.visit_any(ValueBag::from_dyn_serde1(v))
335                }
336            }
337
338            #[cfg(feature = "seq")]
339            fn seq(&mut self, v: &dyn internal::seq::Seq) -> Result<(), Error> {
340                self.0.visit_any(ValueBag::from_dyn_seq(v))
341            }
342
343            fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> {
344                Err(Error::msg(msg))
345            }
346        }
347
348        self.internal_visit(&mut Visitor(visitor))
349    }
350}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355    use crate::test::*;
356
357    #[cfg(target_arch = "wasm32")]
358    use wasm_bindgen_test::*;
359
360    #[test]
361    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
362    fn visit_structured() {
363        ValueBag::from(42u64)
364            .visit(TestVisit::default())
365            .expect("failed to visit value");
366        ValueBag::from(-42i64)
367            .visit(TestVisit::default())
368            .expect("failed to visit value");
369        ValueBag::from(&42u128)
370            .visit(TestVisit::default())
371            .expect("failed to visit value");
372        ValueBag::from(&-42i128)
373            .visit(TestVisit::default())
374            .expect("failed to visit value");
375        ValueBag::from(11f64)
376            .visit(TestVisit::default())
377            .expect("failed to visit value");
378        ValueBag::from(true)
379            .visit(TestVisit::default())
380            .expect("failed to visit value");
381        ValueBag::from("some borrowed string")
382            .visit(TestVisit::default())
383            .expect("failed to visit value");
384        ValueBag::from('n')
385            .visit(TestVisit::default())
386            .expect("failed to visit value");
387    }
388
389    #[test]
390    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
391    fn visit_empty() {
392        struct Visitor(bool);
393
394        impl<'v> Visit<'v> for Visitor {
395            fn visit_any(&mut self, _: ValueBag) -> Result<(), Error> {
396                Ok(())
397            }
398
399            fn visit_empty(&mut self) -> Result<(), Error> {
400                self.0 = true;
401                Ok(())
402            }
403        }
404
405        let mut visitor = Visitor(false);
406        ValueBag::empty().visit(&mut visitor).unwrap();
407
408        assert!(visitor.0);
409    }
410
411    #[test]
412    #[cfg(feature = "serde1")]
413    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
414    fn visit_serde1() {
415        use crate::std::string::{String, ToString};
416
417        struct Data;
418
419        impl value_bag_serde1::lib::Serialize for Data {
420            fn serialize<S: value_bag_serde1::lib::Serializer>(
421                &self,
422                serializer: S,
423            ) -> Result<S::Ok, S::Error> {
424                use value_bag_serde1::lib::ser::SerializeStruct;
425
426                let mut s = serializer.serialize_struct("Data", 3)?;
427                s.serialize_field("a", &1)?;
428                s.serialize_field("b", &2)?;
429                s.serialize_field("c", &3)?;
430                s.end()
431            }
432        }
433
434        struct Visitor(String);
435
436        impl<'v> Visit<'v> for Visitor {
437            fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> {
438                self.0 = v.to_string();
439
440                Ok(())
441            }
442        }
443
444        let mut visitor = Visitor("".into());
445        ValueBag::from_serde1(&Data).visit(&mut visitor).unwrap();
446
447        assert_eq!("Data { a: 1, b: 2, c: 3 }", visitor.0);
448    }
449
450    #[test]
451    #[cfg(feature = "sval2")]
452    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
453    fn visit_sval2() {
454        use crate::std::string::{String, ToString};
455
456        struct Data;
457
458        impl value_bag_sval2::lib::Value for Data {
459            fn stream<'sval, S: value_bag_sval2::lib::Stream<'sval> + ?Sized>(
460                &'sval self,
461                stream: &mut S,
462            ) -> value_bag_sval2::lib::Result {
463                stream.map_begin(Some(3))?;
464
465                stream.map_key_begin()?;
466                stream.value("a")?;
467                stream.map_key_end()?;
468
469                stream.map_value_begin()?;
470                stream.value(&1)?;
471                stream.map_value_end()?;
472
473                stream.map_key_begin()?;
474                stream.value("b")?;
475                stream.map_key_end()?;
476
477                stream.map_value_begin()?;
478                stream.value(&2)?;
479                stream.map_value_end()?;
480
481                stream.map_key_begin()?;
482                stream.value("c")?;
483                stream.map_key_end()?;
484
485                stream.map_value_begin()?;
486                stream.value(&3)?;
487                stream.map_value_end()?;
488
489                stream.map_end()
490            }
491        }
492
493        struct Visitor(String);
494
495        impl<'v> Visit<'v> for Visitor {
496            fn visit_any(&mut self, v: ValueBag) -> Result<(), Error> {
497                self.0 = v.to_string();
498
499                Ok(())
500            }
501        }
502
503        let mut visitor = Visitor("".into());
504        ValueBag::from_sval2(&Data).visit(&mut visitor).unwrap();
505
506        assert_eq!("{ \"a\": 1, \"b\": 2, \"c\": 3 }", visitor.0);
507    }
508}