inspect/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! This module implements the inspect framework, which allows an object to
5//! expose its state for diagnostics purposes as a hierarchy. All such subtrees
6//! are linked together into a single tree for the process, and clients can
7//! query information from arbitrary portions of the tree by path.
8//!
9//! To participate in the tree, an object implements the [`Inspect`] trait and
10//! arranges for itself to be inspected, usually automatically via an existing
11//! parent-child relationship.
12//!
13//! For most cases, users should use the derive version of [`Inspect`](derive@Inspect)
14//! as this will automatically update the implementation as new fields are added.
15
16#![no_std]
17#![forbid(unsafe_code)]
18
19extern crate alloc;
20
21// Enable `std` for features that depend on it.
22//
23// Don't just have these features depend on the "std" feature, because they
24// might be able to remove their `std` dependency in the future. (Most of them
25// are blocked on `core::error::Error` not being stable yet.)
26#[cfg(any(feature = "std", feature = "initiate", feature = "defer",))]
27extern crate std;
28
29#[cfg(feature = "defer")]
30mod defer;
31#[cfg(feature = "initiate")]
32mod initiate;
33
34#[cfg(all(test, feature = "derive", feature = "initiate"))]
35extern crate self as inspect;
36
37#[cfg(feature = "defer")]
38pub use defer::*;
39#[cfg(feature = "initiate")]
40pub use initiate::*;
41
42/// Derives the [`Inspect`] trait for a struct or enum.
43///
44/// [`InspectMut`](derive@InspectMut) can also be derived using the same
45/// attributes.
46///
47/// # Structs
48///
49/// By default, the macro implements [`Inspect`] or [`InspectMut`] by calling
50/// [`Request::respond`] and then calling [`Response::field`] on each field by
51/// reference. You can use attributes to control this behavior.
52///
53/// Attributes are comma separated and nested inside the `inspect` attribute,
54/// e.g. `#[inspect(hex, rename = "foo")]`.
55///
56/// If you derive `Inspect` on a struct with the `bitfield` attribute, then it
57/// is assumed to be from the `bitfield-struct` crate. The derived
58/// implementation will have a field for each bitfield field, plus one called
59/// `raw` with the raw value in hexadecimal. Be sure to put the `derive`
60/// attribute above the `bitfield` attribute for this to work.
61///
62/// ## Struct attributes
63///
64/// ### `transparent(attrs)`
65///
66/// Forward the request to a single field of the struct.
67///
68/// `(attrs)` is optional. If provided, these are attributes to apply to the
69/// field. This is useful when the field is generated by another macro (such as
70/// `bitflags!`) and you cannot put attributes on it.
71///
72/// This attribute requires that there be exactly one non-skipped field. Fields
73/// of type [`PhantomData`](std::marker::PhantomData) are automatically skipped.
74///
75/// Note that it is not sufficient to mark any extraneous fields' _types_ with
76/// `skip`--you must mark the individual fields with the `skip` attribute.
77///
78/// ### `skip`
79///
80/// Skip this type when inspected so that they do not appear in inspect output.
81/// Calls [`Request::ignore`].
82///
83/// ### `with`
84///
85/// Wraps the type with `expr`, so that the inspect implementation is deferred
86/// to `expr(&field)`.
87///
88/// `expr` is often a type constructor such as [`AsDisplay`] or [`AsDebug`] (but
89/// note that there are shorthand attributes `display` and `debug` for these
90/// types).
91///
92/// ### `display`
93///
94/// Inspect the type by formatting it as a string, using the type's [`ToString`]
95/// implementation.
96///
97/// Usually implementing [`Inspect`] for the type should be preferred to this in
98/// order to preserve structured data. However, this may be useful if the
99/// display string is the canonical way to view a field's data.
100///
101/// This is equivalent to `with = "inspect::AsDisplay"`. See [`AsDisplay`].
102///
103/// ### `debug`
104///
105/// Inspect the type by formatting it as a string, using the type's [`Debug`]
106/// implementation.
107///
108/// Usually implementing [`Inspect`] for the type should be preferred to this in
109/// order to preserve structured data. However, this may be useful if the debug
110/// string is the canonical way to view a field's data, as with `bitfields!` or
111/// `open_enum!`.
112///
113/// This is equivalent to `with = "inspect::AsDebug"`. See [`AsDebug`].
114///
115/// ### `extra = "expr"`
116///
117/// In addition to inspecting each field as normal, call `expr(self, resp)`.
118/// This allows you to add synthetic fields to the struct without manually
119/// implementing inspect for all fields.
120///
121/// ```no_run
122/// # use inspect::Inspect;
123/// #[derive(Inspect)]
124/// #[inspect(extra = "Foo::inspect_extra")]
125/// struct Foo {
126///     x: u32,
127///     y: u32,
128/// }
129///
130/// impl Foo {
131///     fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
132///         resp.field("sum", self.x + self.y);
133///     }
134/// }
135/// ```
136///
137/// ### `hex`
138///
139/// Use hexadecimal formatting by default for all fields, recursively.
140///
141/// ## Field attributes
142///
143/// ### `rename = "custom_name"`
144///
145/// Set the name of the field to "custom_name". By default, fields have the same
146/// name as their Rust identifier.
147///
148/// ### `field`
149///
150/// Inspect the field using its [`Inspect`] implementation, by calling
151/// [`Response::field`] with `&field`.
152///
153/// This is the default.
154///
155/// ### `with = "expr"`
156///
157/// Wraps the field with `expr`, so that `expr(&field)` is the inspected value.
158/// This is useful when the field cannot implement `Inspect`, but you can wrap
159/// it in an object that can.
160///
161/// `expr` is often a type constructor such as [`AsDisplay`] or [`AsDebug`] (but
162/// note that there are shorthand attributes `display` and `debug` for these
163/// types).
164///
165/// This can also be used to implement helper functions that implement
166/// [`Inspect`] to allow complex types to use the the derive macro.
167///
168/// #### Examples
169/// The following structure has a field that is not normally inspectable, but we
170/// can use the derive macro with a helper pattern of making a new helper
171/// function, along with the `with` attribute.
172///
173///
174/// ```no_run
175/// # use inspect::Inspect;
176/// struct NotInspectable {
177///     complex_field: u64 // use your imaginatation to pretend this is a complex field
178/// }
179///
180/// #[derive(Inspect)]
181/// struct Foo {
182///     #[inspect(with = "inspect_awesome_data")]
183///     awesome_data: NotInspectable,
184///     data: String,
185/// }
186///
187/// pub fn inspect_awesome_data(id: &NotInspectable) -> impl Inspect {
188///     // Do some complex field transformation to a string here...
189///     format!("{}, {:x}", (id.complex_field * 42), id.complex_field)
190///     // Since String via str has an implementation for Inspect, we can return the value directly.
191/// }
192///
193/// // In general, inspect helper functions would be defined as the following in another sub module and used
194/// // as `[inspect(with = "inspect_helpers::awesome_data")]` but rustdoc limitations prevent this.
195/// // mod inspect_helpers {
196/// //     use super::*;
197/// //
198/// //     pub(super) fn awesome_data(id: &NotInspectable) -> impl Inspect { ... }
199/// // }
200/// ```
201///
202/// ### `display`
203///
204/// Inspect the field by formatting it as a string, using the field's
205/// [`ToString`] implementation.
206///
207/// This is equivalent to `with = "inspect::AsDisplay"`. See [`AsDisplay`].
208///
209/// ### `debug`
210///
211/// Inspect the field by formatting it as a string, using the field's
212/// [`std::fmt::Debug`] implementation.
213///
214/// In general, implementing [`Inspect`] for the field should be preferred to
215/// this in order to preserve structured data.
216///
217/// This is equivalent to `with = "inspect::AsDebug"`. See [`AsDebug`].
218///
219/// ### `format = "format"`
220///
221/// Inspect the field by formatting it as a string, using the provided format.
222///
223/// For example, `format = "id{:02x}"` might be useful on a field that
224/// represents a 2-digit hex identifier.
225///
226/// ### `hex`
227///
228/// Inspect the field, including all children, recursively, with hexadecimal
229/// formatting.
230///
231/// ### `binary`
232///
233/// Inspect the field, including all children, recursively, with binary
234/// formatting.
235///
236/// ### `bytes`
237///
238/// Inspect the field as a list of bytes. The field must be iterable with an
239/// item type of `u8` or `&u8`.
240///
241/// ### `flatten`
242///
243/// Merge the contents of the field into this inspection node, without an
244/// intermediate child node. Calls [`Response::merge`] with `&field`.
245///
246/// This is useful when your struct is split into an outer and inner type that
247/// are logically the same type from a diagnostics perspective. In this case,
248/// you probably would not want to expose the implementation detail of the inner
249/// type.
250///
251/// ### `iter_by_key`
252///
253/// Inspects a list of items, iterating them by calling
254/// [`into_iter()`](IntoIterator::into_iter) on the field. Each item must have
255/// type `(K, V)`, where `K: Display` and `V: Inspect`. `K` is used as the field
256/// name.
257///
258/// ### `iter_by_index`
259///
260/// Inspects a list of items, enumerating them by calling
261/// [`into_iter()`](IntoIterator::into_iter) on the field. Each item must have
262/// type `V: Inspect`. The field name is the index in the enumeration, starting
263/// with `0`.
264///
265/// #### Example
266///
267/// ```no_run
268/// # use inspect::Inspect;
269/// # use std::sync::Arc;
270/// #[derive(Inspect)]
271/// struct Foo {
272///     id: u32,
273///     #[inspect(flatten)]
274///     inner: Arc<Inner>,
275/// }
276///
277/// #[derive(Inspect)]
278/// struct Inner {
279///     state: String,
280/// }
281/// ```
282///
283/// ### `skip`
284///
285/// Skip inspecting this field.
286///
287/// ### `mut`
288///
289/// Pass the field as a mutable reference to the appropriate method so that its
290/// [`InspectMut`] implementation is called instead of its [`Inspect`]
291/// implementation.
292///
293/// This is only valid in uses of the [`InspectMut`](derive@InspectMut) derive
294/// macro.
295///
296/// This can be used in conjunction with other attributes:
297///
298/// * `field`: calls [`Response::field_mut`] with `&mut field`.
299/// * `flatten`: calls [`Response::merge`] with `&mut field`.
300/// * `transparent` (struct attribute): calls [`InspectMut::inspect_mut`] on the
301///   sole unskipped field.
302/// ## Example
303///
304/// ```no_run
305/// # use inspect::{Inspect, InspectMut};
306/// # use std::sync::Arc;
307/// # use std::path::PathBuf;
308/// #[derive(InspectMut)]
309/// struct Outer {
310///     #[inspect(hex)]
311///     id: u32,                // will be displayed as hex
312///     count: usize,
313///     #[inspect(mut)]
314///     max_buffers: usize,     // can be changed via `update()`
315///     #[inspect(skip)]
316///     signal: Box<dyn Send>,  // won't be present in inspect output
317///     #[inspect(flatten)]
318///     inner: Arc<Inner>,      // contents will be merged in
319/// }
320///
321/// #[derive(Inspect)]
322/// struct Inner {
323///     #[inspect(format = "{:016x}")]
324///     uuid: u128,             // will be displayed as a 0-padded hex string
325/// }
326/// ```
327///
328/// # Unit-only enums
329///
330/// The macro supports enums, with multiple different output formats:
331///
332/// By default, deriving `Inspect` or `InspectMut` on an enum only works if the
333/// enum variants are all unit variants. In this case, the inspect output is a
334/// string containing the name of the enum variant converted from the standard
335/// `PascalCase` to `snake_case`.
336///
337///  For example:
338///
339/// ```no_run
340/// # use inspect::Inspect;
341/// #[derive(Inspect)]
342/// enum State {
343///     NotRunning, // will be displayed as "not_running"
344///     Running,    // will be displayed as "running"
345/// }
346/// ```
347///
348/// For `InspectMut`, the enum variant name is parsed for update requests.
349///
350/// # Enums with fields
351///
352/// To derive `Inspect` for an enum whose variants might contain fields, you
353/// must select an output format.
354///
355/// ## Output formats
356///
357/// In each of the formats below, when the variant name is used in the output,
358/// it is converted from `PascalCase` to `snake_case`. You can specify an
359/// alternate name with the `rename` attribute, e.g. `#[inspect(rename =
360/// "paused")]`.
361///
362/// ### `tag = "tag_name"`
363///
364/// Includes the variant name as a field called `tag_name`, and flattens all the
365/// variant's fields into the object.
366///
367/// ```no_run
368/// # use inspect::Inspect;
369/// #[derive(Inspect)]
370/// #[inspect(tag = "state")]
371/// enum State {
372///     Stopped,
373///     Running { with_optimizations: bool },
374/// }
375/// ```
376///
377/// Example output for `State::Running { with_optimizations: true }`:
378///
379/// ```text
380/// {
381///     state: "running"
382///     with_optimizations: true
383/// }
384/// ```
385///
386/// ### `external_tag`
387///
388/// Writes a single field named for the variant, with the variant's fields as
389/// children.
390///
391/// ```no_run
392/// # use inspect::Inspect;
393/// #[derive(Inspect)]
394/// #[inspect(external_tag)]
395/// enum State {
396///     Stopped,
397///     Running { with_optimizations: bool },
398/// }
399/// ```
400///
401/// Example output for `State::Running { with_optimizations: true }`:
402///
403/// ```text
404/// {
405///     running: {
406///         with_optimizations: true
407///     }
408/// }
409/// ```
410///
411/// ### `untagged`
412///
413/// Flattens the variant's fields as in `tag`, but does not include the variant
414/// name anywhere.
415///
416/// ```no_run
417/// # use inspect::Inspect;
418/// #[derive(Inspect)]
419/// #[inspect(untagged)]
420/// enum DiskBacking {
421///     File { file_path: String },
422///     Memory { ramdisk_size: u64 },
423/// }
424/// ```
425///
426/// Example output for `State::File { file_path: "file.img" }`:
427///
428/// ```text
429/// {
430///     file_path: "file.img"
431/// }
432/// ```
433///
434/// ## Additional attributes
435///
436/// On enums, as with structs, you can put the [`skip`](#skip), [`with`](#with),
437/// [`display`](#display), [`debug`](#debug), or [`extra`](#extra--expr)
438/// attributes to specify alternate inspect behavior.
439///
440/// On each enum variant, you can use [`transparent`](#transparentattrs) as you
441/// would with a struct.
442///
443/// On enum variant fields, you can use any attribute that you would use with a
444/// struct field.
445#[cfg(feature = "derive")]
446pub use inspect_derive::Inspect;
447/// Derives the [`InspectMut`] trait for a struct or enum.
448///
449/// See the [`Inspect`](derive@Inspect) derive macro for more details.
450#[cfg(feature = "derive")]
451pub use inspect_derive::InspectMut;
452
453use alloc::borrow::Cow;
454use alloc::borrow::ToOwned;
455use alloc::boxed::Box;
456use alloc::format;
457use alloc::rc::Rc;
458use alloc::string::String;
459use alloc::string::ToString;
460use alloc::sync::Arc;
461use alloc::vec::Vec;
462use core::fmt;
463use core::fmt::Arguments;
464use core::fmt::Debug;
465use core::fmt::Display;
466use core::num::Wrapping;
467
468/// An inspection request.
469pub struct Request<'a> {
470    path: &'a str,
471    depth: usize,
472    node: &'a mut InternalNode,
473    value: Option<&'a str>,
474    sensitivity: SensitivityLevel,
475    number_format: NumberFormat,
476}
477
478#[cfg_attr(
479    any(feature = "defer", feature = "initiate"),
480    derive(mesh::MeshPayload)
481)]
482#[derive(Debug, Default, Copy, Clone)]
483enum NumberFormat {
484    #[default]
485    Decimal,
486    Hex,
487    Binary,
488    Counter,
489}
490
491#[cfg(any(feature = "defer", feature = "initiate"))]
492struct RequestRoot<'a> {
493    path: &'a str,
494    node: InternalNode,
495    depth: usize,
496    value: Option<&'a str>,
497    sensitivity: SensitivityLevel,
498    number_format: NumberFormat,
499}
500
501/// The sensitivity level for an inspection node or request.
502/// Requests will only return nodes at or below their sensitivity level.
503/// For example, a request set to `SensitivityLevel::Safe` will not return nodes
504/// with `SensitivityLevel::Sensitive` or `SensitivityLevel::Unknown`.
505#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Default)]
506#[cfg_attr(
507    any(feature = "defer", feature = "initiate"),
508    derive(mesh::MeshPayload)
509)]
510#[cfg_attr(
511    any(feature = "defer", feature = "initiate"),
512    mesh(package = "inspect")
513)]
514#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
515pub enum SensitivityLevel {
516    /// The node doesn't contain sensitive information and is always safe to expose.
517    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(1))]
518    Safe,
519    /// The node might contain sensitive information and should only be exposed
520    /// in a secure context.
521    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(2))]
522    #[default]
523    Unspecified,
524    /// The node contains sensitive information and should only be exposed in a
525    /// secure context.
526    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(3))]
527    Sensitive,
528}
529
530#[cfg(any(feature = "defer", feature = "initiate"))]
531impl<'a> RequestRoot<'a> {
532    fn new(
533        path: &'a str,
534        depth: usize,
535        value: Option<&'a str>,
536        sensitivity: SensitivityLevel,
537        number_format: NumberFormat,
538    ) -> Self {
539        Self {
540            path,
541            node: InternalNode::Unevaluated,
542            depth,
543            value,
544            sensitivity,
545            number_format,
546        }
547    }
548
549    fn request(&mut self) -> Request<'_> {
550        Request::new(
551            self.path,
552            self.depth,
553            &mut self.node,
554            self.value,
555            self.sensitivity,
556            self.number_format,
557        )
558    }
559}
560
561/// A type used to build an inspection response.
562pub struct Response<'a> {
563    /// Full remaining path, including leading `/`s.
564    path: &'a str,
565    /// Cache of remaining path without leading '/'s.
566    path_without_slashes: Option<&'a str>,
567    depth: usize,
568    cell: &'a mut InternalNode,
569    value: Option<&'a str>,
570    sensitivity: SensitivityLevel,
571    number_format: NumberFormat,
572}
573
574#[derive(Debug)]
575enum Action<'a, 'b> {
576    Process {
577        name: &'a str,
578        sensitivity: SensitivityLevel,
579        new_path: &'b str,
580        new_depth: usize,
581    },
582    Skip,
583    DepthExhausted {
584        name: &'a str,
585        sensitivity: SensitivityLevel,
586    },
587}
588
589impl<'a, 'b> Action<'a, 'b> {
590    // Determine which action to take for the field with `name`, given the
591    // remaining `path` and the remaining `depth`.
592    fn eval(child: Child<'a>, resp: &Response<'b>) -> Self {
593        let path = resp.path_without_slashes.unwrap();
594        if resp.depth == 0 {
595            // Don't return any subfields if the depth is exhausted, since depth
596            // exhausted will be reported for the current node.
597            return Self::Skip;
598        }
599        if resp.sensitivity < child.sensitivity {
600            // Don't return any subfields if the request's sensitivity level is too low.
601            return Self::Skip;
602        }
603        if let Some(rest) = path.strip_prefix(child.name) {
604            if rest.is_empty() || rest.as_bytes()[0] == b'/' {
605                // Exact or prefix match, e.g. name and path are both "foo", or
606                // name is "foo", path is "foo/bar".
607                Self::Process {
608                    name: child.name,
609                    sensitivity: child.sensitivity,
610                    new_path: rest,
611                    new_depth: resp.depth,
612                }
613            } else {
614                // Mismatch, e.g. name is "foo", path is "foobar", or this is a
615                // prefix match but this node is a value.
616                Self::Skip
617            }
618        } else if child.name.starts_with(path) {
619            let remaining_name = if path.is_empty() {
620                // Path is empty, so allow all names.
621                child.name
622            } else {
623                if child.name.as_bytes()[path.len()] != b'/' {
624                    // Mismatch, e.g. name is "foobar", path is "foo".
625                    return Self::Skip;
626                }
627                // Prefix match, e.g. name is "foo/bar", path is "foo".
628                &child.name[path.len() + 1..]
629            };
630            // Ensure there is enough depth for the name.
631            match remaining_name.match_indices('/').nth(resp.depth - 1) {
632                None => Self::Process {
633                    name: child.name,
634                    sensitivity: child.sensitivity,
635                    new_path: "",
636                    new_depth: resp.depth - 1,
637                },
638                Some((n, _)) => Self::DepthExhausted {
639                    name: &child.name[..child.name.len() - remaining_name.len() + n],
640                    sensitivity: child.sensitivity,
641                },
642            }
643        } else {
644            Self::Skip
645        }
646    }
647}
648
649struct Child<'a> {
650    name: &'a str,
651    sensitivity: SensitivityLevel,
652}
653
654impl Response<'_> {
655    /// Adds a field to the response.
656    ///
657    /// ```no_run
658    /// # use inspect::{Request, Response};
659    /// # use std::path::Path;
660    /// fn inspect_data(a: u32, b: &str, c: bool, maybe: Option<u32>, req: Request) {
661    ///     req.respond()
662    ///        .field("a", a)
663    ///        .field("b", b)
664    ///        .field("c", c)
665    ///        .field("maybe", maybe)
666    ///        .field("computed", format_args!("{a}-{b}"));
667    /// }
668    /// ```
669    pub fn field<T>(&mut self, name: &str, value: T) -> &mut Self
670    where
671        T: Inspect,
672    {
673        self.inspect_field(name, &value)
674    }
675
676    /// Adds a field to the response with a [`SensitivityLevel`].
677    pub fn sensitivity_field<T>(
678        &mut self,
679        name: &str,
680        sensitivity: SensitivityLevel,
681        value: T,
682    ) -> &mut Self
683    where
684        T: Inspect,
685    {
686        self.sensitivity_inspect_field(name, sensitivity, &value)
687    }
688
689    /// Adds a hexadecimal field to the response.
690    pub fn hex<T>(&mut self, name: &str, value: T) -> &mut Self
691    where
692        T: Inspect,
693    {
694        self.field(name, AsHex(value))
695    }
696
697    /// Adds a counter field to the response.
698    pub fn counter<T>(&mut self, name: &str, value: T) -> &mut Self
699    where
700        T: Inspect,
701    {
702        self.field(name, AsCounter(value))
703    }
704
705    /// Adds a counter field to the response.
706    ///
707    /// This is a convenience method for `sensitivity_field(name, sensitivity, Value::counter(value))`.
708    pub fn sensitivity_counter<T>(
709        &mut self,
710        name: &str,
711        sensitivity: SensitivityLevel,
712        value: T,
713    ) -> &mut Self
714    where
715        T: Inspect,
716    {
717        self.sensitivity_field(name, sensitivity, AsCounter(value))
718    }
719
720    /// Adds a binary field to the response.
721    ///
722    /// This is a convenience method for `field(name, Value::binary(value))`.
723    pub fn binary<T>(&mut self, name: &str, value: T) -> &mut Self
724    where
725        T: Inspect,
726    {
727        self.field(name, AsBinary(value))
728    }
729
730    /// Adds a string field that implements [`std::fmt::Display`].
731    ///
732    /// This is a convenience method for `field_with(name, ||
733    /// value.to_string())`. It lazily allocates the string only when the
734    /// inspector requests it, so it is more efficient than using `format!` or
735    /// `to_string()`.
736    ///
737    /// ```no_run
738    /// # use inspect::{Request, Response};
739    /// # use std::path::Path;
740    /// fn inspect_data(path: &Path, id: u32, req: Request) {
741    ///     req.respond().display("path", &path.display());
742    /// }
743    /// ```
744    pub fn display(&mut self, name: &str, value: &impl Display) -> &mut Self {
745        self.field_with(name, || value.to_string())
746    }
747
748    /// Adds a string field that implements [`std::fmt::Debug`].
749    ///
750    /// This is a convenience method for `field(name, format_args!("{value:?}"))`.
751    ///
752    /// Take care not to overuse this. This is best used for fields that have a
753    /// short or natural `Debug` implementation, such as dataless enums. If your
754    /// field is an aggregate type whose `Debug` implementation has a
755    /// complicated structure, consider implementing `Inspect` on the type and
756    /// calling [`field`](`Self::field`).
757    pub fn display_debug(&mut self, name: &str, value: &impl Debug) -> &mut Self {
758        self.field(name, format_args!("{value:?}"))
759    }
760
761    /// Adds a field to the response, calling `f` to get its value.
762    pub fn field_with<F, V>(&mut self, name: &str, f: F) -> &mut Self
763    where
764        F: FnOnce() -> V,
765        V: Inspect,
766    {
767        self.sensitivity_field_with(name, SensitivityLevel::Unspecified, f)
768    }
769
770    /// Adds a field to the response with a [`SensitivityLevel`], calling `f` to get its value.
771    pub fn sensitivity_field_with<F, V>(
772        &mut self,
773        name: &str,
774        sensitivity: SensitivityLevel,
775        f: F,
776    ) -> &mut Self
777    where
778        F: FnOnce() -> V,
779        V: Inspect,
780    {
781        if let Some(req) = self.child_request(Child { name, sensitivity }) {
782            (f)().inspect(req)
783        }
784        self
785    }
786
787    /// Adds a mutable field to the response.
788    pub fn field_mut<T>(&mut self, name: &str, value: &mut T) -> &mut Self
789    where
790        T: InspectMut + ?Sized,
791    {
792        self.inspect_field(name, value)
793    }
794
795    /// Adds a mutable field to the response with a [`SensitivityLevel`].
796    pub fn sensitivity_field_mut<T>(
797        &mut self,
798        name: &str,
799        sensitivity: SensitivityLevel,
800        value: &mut T,
801    ) -> &mut Self
802    where
803        T: InspectMut + ?Sized,
804    {
805        self.sensitivity_inspect_field(name, sensitivity, value)
806    }
807
808    /// Adds a mutable field with custom get/update function.
809    pub fn field_mut_with<F, V, E>(&mut self, name: &str, f: F) -> &mut Self
810    where
811        F: FnOnce(Option<&str>) -> Result<V, E>,
812        V: Into<ValueKind>,
813        E: Into<Box<dyn core::error::Error + Send + Sync>>,
814    {
815        self.child(name, |req| match req.update() {
816            Ok(req) => match (f)(Some(req.new_value())) {
817                Ok(v) => req.succeed(v),
818                Err(err) => req.fail(err),
819            },
820            Err(req) => req.value((f)(None).ok().unwrap()),
821        })
822    }
823
824    fn child_request(&mut self, child: Child<'_>) -> Option<Request<'_>> {
825        if self.path_without_slashes.is_none() {
826            self.path_without_slashes = Some(self.path.trim_start_matches('/'));
827        }
828
829        match Action::eval(child, self) {
830            Action::Process {
831                name,
832                sensitivity,
833                new_path,
834                new_depth,
835            } => {
836                let children = self.cell.as_dir();
837                children.push(InternalEntry {
838                    name: name.to_owned(),
839                    node: InternalNode::Unevaluated,
840                    sensitivity,
841                });
842                let entry = children.last_mut().unwrap();
843                Some(Request::new(
844                    new_path,
845                    new_depth,
846                    &mut entry.node,
847                    self.value,
848                    self.sensitivity,
849                    self.number_format,
850                ))
851            }
852            Action::Skip => None,
853            Action::DepthExhausted { name, sensitivity } => {
854                self.cell.as_dir().push(InternalEntry {
855                    name: name.to_owned(),
856                    node: InternalNode::DepthExhausted,
857                    sensitivity,
858                });
859                None
860            }
861        }
862    }
863
864    /// Inspects a child object.
865    fn inspect_field(&mut self, name: &str, child: impl InspectMut) -> &mut Self {
866        self.sensitivity_inspect_field(name, SensitivityLevel::Unspecified, child)
867    }
868
869    /// Inspects a child object with a [`SensitivityLevel`].
870    #[inline(never)] // Testing shows a significant code size reduction with this.
871    fn sensitivity_inspect_field(
872        &mut self,
873        name: &str,
874        sensitivity: SensitivityLevel,
875        mut child: impl InspectMut,
876    ) -> &mut Self {
877        if let Some(req) = self.child_request(Child { name, sensitivity }) {
878            child.inspect_mut(req);
879        }
880        self
881    }
882
883    /// Inspects a list of children objects as children of the node `name`.
884    ///
885    /// Each element of `children` should be a tuple (`child_name`, `child`).
886    /// `child_name` must be convertible to a string.
887    #[cfg_attr(
888        feature = "initiate",
889        doc = r##"
890```rust
891# use inspect::{inspect, Inspect, Request};
892# use core::time::Duration;
893
894struct Child(u32);
895impl Inspect for Child {
896    fn inspect(&self, req: Request) {
897        req.respond().field("x", self.0);
898    }
899}
900
901struct Parent(Vec<Child>);
902impl Inspect for Parent {
903    fn inspect(&self, req: Request) {
904        req.respond().fields("children", self.0.iter().enumerate());
905    }
906}
907
908assert_eq!(
909    inspect(
910        "",
911        &Parent(vec![Child(5), Child(12)]),
912    )
913    .results()
914    .to_string(),
915    r#"{children: {0: {x: 5}, 1: {x: 12}}}"#
916);
917```
918"##
919    )]
920    pub fn fields<I, N, C>(&mut self, name: &str, children: I) -> &mut Self
921    where
922        I: Iterator<Item = (N, C)>,
923        N: ToString,
924        C: Inspect,
925    {
926        self.child(name, |req| {
927            let mut resp = req.respond();
928            for (name, child) in children {
929                resp.inspect_field(&name.to_string(), &child);
930            }
931        })
932    }
933
934    /// Inspects a list of children objects as children of the node `name`.
935    ///
936    /// Each element of `children` should be a tuple (`child_name`, `child`).
937    /// `child_name` must be convertible to a string.
938    #[cfg_attr(
939        feature = "initiate",
940        doc = r##"
941```rust
942# use inspect::{inspect, InspectMut, Request};
943# use std::time::Duration;
944struct Child(u32);
945impl InspectMut for Child {
946    fn inspect_mut(&mut self, req: Request) {
947        req.respond().field("x", self.0);
948    }
949}
950
951struct Parent(Vec<Child>);
952impl InspectMut for Parent {
953    fn inspect_mut(&mut self, req: Request) {
954        req.respond().fields_mut("children", self.0.iter_mut().enumerate());
955    }
956}
957
958assert_eq!(
959    inspect(
960        "",
961        &mut Parent(vec![Child(5), Child(12)]),
962    )
963    .results()
964    .to_string(),
965    r#"{children: {0: {x: 5}, 1: {x: 12}}}"#
966);
967```
968"##
969    )]
970    pub fn fields_mut<I, N, C>(&mut self, name: &str, children: I) -> &mut Self
971    where
972        I: Iterator<Item = (N, C)>,
973        N: ToString,
974        C: InspectMut,
975    {
976        self.child(name, |req| {
977            let mut resp = req.respond();
978            for (name, child) in children {
979                resp.inspect_field(&name.to_string(), child);
980            }
981        })
982    }
983
984    /// Adds a child node to the inspection response.
985    ///
986    /// If `name` is empty, then the results of the inspection are merged into
987    /// this node.
988    pub fn child<F: FnOnce(Request<'_>)>(&mut self, name: &str, f: F) -> &mut Self {
989        self.sensitivity_child(name, SensitivityLevel::Unspecified, f)
990    }
991
992    /// Adds a child node to the inspection response with a [`SensitivityLevel`].
993    ///
994    /// If `name` is empty, then the results of the inspection are merged into
995    /// this node.
996    pub fn sensitivity_child<F: FnOnce(Request<'_>)>(
997        &mut self,
998        name: &str,
999        sensitivity: SensitivityLevel,
1000        f: F,
1001    ) -> &mut Self {
1002        if let Some(req) = self.child_request(Child { name, sensitivity }) {
1003            f(req);
1004        }
1005        self
1006    }
1007
1008    /// Inspects an object and merges its responses into this node without
1009    /// creating a child node.
1010    pub fn merge(&mut self, mut child: impl InspectMut) -> &mut Self {
1011        child.inspect_mut(self.request());
1012        self
1013    }
1014
1015    /// Gets another request for this response. The response to that request
1016    /// will be merged into this response.
1017    pub fn request(&mut self) -> Request<'_> {
1018        let children = self.cell.as_dir();
1019        children.push(InternalEntry {
1020            name: String::new(),
1021            node: InternalNode::Unevaluated,
1022            sensitivity: SensitivityLevel::Unspecified,
1023        });
1024        let entry = children.last_mut().unwrap();
1025        Request::new(
1026            self.path,
1027            self.depth,
1028            &mut entry.node,
1029            self.value,
1030            self.sensitivity,
1031            self.number_format,
1032        )
1033    }
1034}
1035
1036impl Drop for Response<'_> {
1037    fn drop(&mut self) {
1038        if self.depth > 0 {
1039            // Ensure the children node was created.
1040            let _ = self.cell.as_dir();
1041        } else {
1042            // No children were collected, but this node had to be inspected in
1043            // case it was a value and not a directory node.
1044            *self.cell = InternalNode::DepthExhausted;
1045        }
1046    }
1047}
1048
1049impl<'a> Request<'a> {
1050    fn new(
1051        path: &'a str,
1052        depth: usize,
1053        cell: &'a mut InternalNode,
1054        value: Option<&'a str>,
1055        sensitivity: SensitivityLevel,
1056        number_format: NumberFormat,
1057    ) -> Self {
1058        Self {
1059            path,
1060            depth,
1061            node: cell,
1062            value,
1063            sensitivity,
1064            number_format,
1065        }
1066    }
1067
1068    /// Sets numeric values to be displayed in decimal format.
1069    #[must_use]
1070    pub fn with_decimal_format(mut self) -> Self {
1071        self.number_format = NumberFormat::Decimal;
1072        self
1073    }
1074
1075    /// Sets numeric values to be displayed in hexadecimal format.
1076    #[must_use]
1077    pub fn with_hex_format(mut self) -> Self {
1078        self.number_format = NumberFormat::Hex;
1079        self
1080    }
1081
1082    /// Sets numeric values to be displayed in binary format.
1083    #[must_use]
1084    pub fn with_binary_format(mut self) -> Self {
1085        self.number_format = NumberFormat::Binary;
1086        self
1087    }
1088
1089    /// Sets numeric values to be displayed as counters.
1090    #[must_use]
1091    pub fn with_counter_format(mut self) -> Self {
1092        self.number_format = NumberFormat::Counter;
1093        self
1094    }
1095
1096    /// Responds to the request with a value.
1097    pub fn value(self, value: impl Into<ValueKind>) {
1098        self.value_(value.into());
1099    }
1100    fn value_(self, value: ValueKind) {
1101        let node = if self.path.is_empty() {
1102            if self.value.is_none() {
1103                InternalNode::Value(value.with_format(self.number_format))
1104            } else {
1105                InternalNode::Failed(InternalError::Immutable)
1106            }
1107        } else {
1108            InternalNode::Failed(InternalError::NotADirectory)
1109        };
1110        *self.node = node;
1111    }
1112
1113    /// Returns an object used for handling an update request.
1114    ///
1115    /// If this is not an update request, returns `Err(self)`.
1116    pub fn update(self) -> Result<UpdateRequest<'a>, Self> {
1117        if let Some(value) = self.value {
1118            if !self.path.is_empty() {
1119                return Err(self);
1120            }
1121            Ok(UpdateRequest {
1122                node: self.node,
1123                value,
1124                number_format: self.number_format,
1125            })
1126        } else {
1127            Err(self)
1128        }
1129    }
1130
1131    /// Responds to the inspection request with a directory node.
1132    ///
1133    /// Returns an object that can be used to provide the inspection results.
1134    pub fn respond(self) -> Response<'a> {
1135        Response {
1136            path: self.path,
1137            path_without_slashes: None,
1138            depth: self.depth,
1139            cell: self.node,
1140            value: self.value,
1141            sensitivity: self.sensitivity,
1142            number_format: self.number_format,
1143        }
1144    }
1145
1146    /// Removes this node from the inspection output.
1147    pub fn ignore(self) {
1148        *self.node = InternalNode::Ignored;
1149    }
1150
1151    /// If true, this is an update request.
1152    pub fn is_update(&self) -> bool {
1153        self.value.is_some()
1154    }
1155
1156    /// Gets the sensitivity level for this request.
1157    pub fn sensitivity(&self) -> SensitivityLevel {
1158        self.sensitivity
1159    }
1160}
1161
1162/// An update request, used for updating a value.
1163pub struct UpdateRequest<'a> {
1164    node: &'a mut InternalNode,
1165    value: &'a str,
1166    number_format: NumberFormat,
1167}
1168
1169impl UpdateRequest<'_> {
1170    /// Gets the requested new value.
1171    pub fn new_value(&self) -> &str {
1172        self.value
1173    }
1174
1175    /// Report that the update succeeded, with a new value of `value`.
1176    pub fn succeed(self, value: impl Into<ValueKind>) {
1177        self.succeed_(value.into());
1178    }
1179    fn succeed_(self, value: ValueKind) {
1180        *self.node = InternalNode::Value(value.with_format(self.number_format));
1181    }
1182
1183    /// Report that the update failed, with the reason in `err`.
1184    pub fn fail<E: Into<Box<dyn core::error::Error + Send + Sync>>>(self, err: E) {
1185        *self.node = InternalNode::failed(err.into());
1186    }
1187}
1188
1189/// A child inspection value. This is not constructed directly but exists to
1190/// provide `From` implementations from the allowed value types.
1191#[derive(Debug, Clone, PartialEq)]
1192#[cfg_attr(
1193    any(feature = "defer", feature = "initiate"),
1194    derive(mesh::MeshPayload),
1195    mesh(package = "inspect")
1196)]
1197#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1198pub struct Value {
1199    /// The kind and associated value.
1200    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(1))]
1201    pub kind: ValueKind,
1202    /// Flags affecting how the value is displayed.
1203    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(2))]
1204    pub flags: ValueFlags,
1205}
1206
1207impl Value {
1208    /// Creates a new value from `kind`.
1209    pub fn new(kind: impl Into<ValueKind>) -> Self {
1210        Self {
1211            kind: kind.into(),
1212            flags: Default::default(),
1213        }
1214    }
1215
1216    /// Creates a new hexadecimal value from `kind`.
1217    pub fn hex(kind: impl Into<ValueKind>) -> Self {
1218        Self::new(kind).into_hex()
1219    }
1220
1221    /// Creates a new counter value from `kind`.
1222    pub fn counter(kind: impl Into<ValueKind>) -> Self {
1223        Self::new(kind).into_counter()
1224    }
1225
1226    /// Creates a new binary value from `kind`.
1227    pub fn binary(kind: impl Into<ValueKind>) -> Self {
1228        Self::new(kind).into_binary()
1229    }
1230
1231    /// Returns this value as a hexadecimal.
1232    pub fn into_hex(self) -> Self {
1233        Self {
1234            kind: self.kind,
1235            flags: self.flags.with_hex(true),
1236        }
1237    }
1238
1239    /// Returns this value as a counter.
1240    pub fn into_counter(self) -> Self {
1241        Self {
1242            kind: self.kind,
1243            flags: self.flags.with_count(true),
1244        }
1245    }
1246
1247    /// Returns this value as a binary.
1248    pub fn into_binary(self) -> Self {
1249        Self {
1250            kind: self.kind,
1251            flags: self.flags.with_binary(true),
1252        }
1253    }
1254}
1255
1256/// The different kinds of values that can be emitted.
1257#[derive(Debug, Clone, PartialEq)]
1258#[cfg_attr(
1259    any(feature = "defer", feature = "initiate"),
1260    derive(mesh::MeshPayload),
1261    mesh(package = "inspect")
1262)]
1263#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1264pub enum ValueKind {
1265    /// A signed integer.
1266    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(1))]
1267    Signed(i64),
1268    /// An unsigned integer.
1269    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(2))]
1270    Unsigned(u64),
1271    /// A 32-bit floating point.
1272    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(3))]
1273    Float(f32),
1274    /// A 64-bit floating point.
1275    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(4))]
1276    Double(f64),
1277    /// A Boolean value.
1278    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(5))]
1279    Bool(bool),
1280    /// A string.
1281    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(6))]
1282    String(String),
1283    /// Opaque binary data.
1284    #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(7))]
1285    Bytes(Vec<u8>),
1286}
1287
1288impl ValueKind {
1289    fn with_format(self, format: NumberFormat) -> Value {
1290        match self {
1291            Self::Signed(_) | Self::Unsigned(_) => match format {
1292                NumberFormat::Decimal => Value::new(self),
1293                NumberFormat::Hex => Value::hex(self).into_hex(),
1294                NumberFormat::Binary => Value::binary(self).into_binary(),
1295                NumberFormat::Counter => Value::counter(self).into_counter(),
1296            },
1297            v => v.into(),
1298        }
1299    }
1300}
1301
1302/// Flags specifying additional metadata on values.
1303#[bitfield_struct::bitfield(u64)]
1304#[derive(PartialEq)]
1305#[cfg_attr(
1306    any(feature = "defer", feature = "initiate"),
1307    derive(mesh::MeshPayload),
1308    mesh(package = "inspect")
1309)]
1310#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1311pub struct ValueFlags {
1312    /// This value should be displayed as hexadecimal.
1313    pub hex: bool,
1314    /// This value is a count and should be displayed as a rate.
1315    pub count: bool,
1316    /// This value should be displayed as binary.
1317    pub binary: bool,
1318
1319    #[bits(61)]
1320    _reserved: u64,
1321}
1322
1323impl Display for Value {
1324    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1325        match &self.kind {
1326            ValueKind::Signed(n) => {
1327                if self.flags.hex() {
1328                    write!(f, "{:#x}", &n)
1329                } else if self.flags.binary() {
1330                    write!(f, "{:#b}", &n)
1331                } else {
1332                    Display::fmt(&n, f)
1333                }
1334            }
1335            ValueKind::Unsigned(n) => {
1336                if self.flags.hex() {
1337                    write!(f, "{:#x}", &n)
1338                } else if self.flags.binary() {
1339                    write!(f, "{:#b}", &n)
1340                } else {
1341                    Display::fmt(&n, f)
1342                }
1343            }
1344            ValueKind::Float(n) => Display::fmt(&n, f),
1345            ValueKind::Double(n) => Display::fmt(&n, f),
1346            ValueKind::Bool(b) => Display::fmt(&b, f),
1347            ValueKind::String(s) => Debug::fmt(&s, f),
1348            ValueKind::Bytes(b) => {
1349                f.write_str("<")?;
1350                for &b in b {
1351                    write!(f, "{:02x}", b)?;
1352                }
1353                f.write_str(">")
1354            }
1355        }
1356    }
1357}
1358
1359impl<T> From<T> for Value
1360where
1361    ValueKind: From<T>,
1362{
1363    fn from(v: T) -> Self {
1364        Value {
1365            kind: v.into(),
1366            flags: Default::default(),
1367        }
1368    }
1369}
1370
1371macro_rules! from_as {
1372    ($x:ident, $to:ty, $($ty:ty),* $(,)?) => {
1373        $(
1374            impl From<$ty> for ValueKind {
1375                fn from(v: $ty) -> Self {
1376                    Self::$x(v as $to)
1377                }
1378            }
1379        )*
1380    };
1381}
1382
1383from_as!(Unsigned, u64, u8, u16, u32, u64, usize);
1384from_as!(Signed, i64, i8, i16, i32, i64, isize);
1385
1386macro_rules! from_get {
1387    ($x:ident, $to:ty, $($ty:ty),* $(,)?) => {
1388        $(
1389            impl From<$ty> for ValueKind {
1390                fn from(v: $ty) -> Self {
1391                    Self::$x(v.get() as $to)
1392                }
1393            }
1394        )*
1395    };
1396}
1397
1398from_get!(
1399    Unsigned,
1400    u64,
1401    core::num::NonZeroU8,
1402    core::num::NonZeroU16,
1403    core::num::NonZeroU32,
1404    core::num::NonZeroU64,
1405    core::num::NonZeroUsize
1406);
1407from_get!(
1408    Signed,
1409    i64,
1410    core::num::NonZeroI8,
1411    core::num::NonZeroI16,
1412    core::num::NonZeroI32,
1413    core::num::NonZeroI64,
1414    core::num::NonZeroIsize
1415);
1416
1417impl From<f32> for ValueKind {
1418    fn from(v: f32) -> Self {
1419        Self::Float(v)
1420    }
1421}
1422
1423impl From<f64> for ValueKind {
1424    fn from(v: f64) -> Self {
1425        Self::Double(v)
1426    }
1427}
1428
1429impl From<bool> for ValueKind {
1430    fn from(v: bool) -> Self {
1431        Self::Bool(v)
1432    }
1433}
1434
1435impl From<&'_ str> for ValueKind {
1436    fn from(v: &str) -> Self {
1437        Self::String(v.to_owned())
1438    }
1439}
1440
1441impl From<String> for ValueKind {
1442    fn from(v: String) -> Self {
1443        Self::String(v)
1444    }
1445}
1446
1447#[cfg(feature = "std")]
1448impl From<&'_ std::ffi::CStr> for ValueKind {
1449    fn from(v: &std::ffi::CStr) -> Self {
1450        Self::String(v.to_string_lossy().to_string())
1451    }
1452}
1453
1454#[cfg(feature = "std")]
1455impl From<std::ffi::CString> for ValueKind {
1456    fn from(v: std::ffi::CString) -> Self {
1457        Self::String(v.to_string_lossy().to_string())
1458    }
1459}
1460
1461impl From<&'_ [u8]> for ValueKind {
1462    fn from(v: &[u8]) -> Self {
1463        Self::Bytes(v.to_vec())
1464    }
1465}
1466
1467impl<const N: usize> From<[u8; N]> for ValueKind {
1468    fn from(v: [u8; N]) -> Self {
1469        Self::Bytes(v.to_vec())
1470    }
1471}
1472
1473impl From<Vec<u8>> for ValueKind {
1474    fn from(v: Vec<u8>) -> Self {
1475        Self::Bytes(v)
1476    }
1477}
1478
1479impl From<Arguments<'_>> for ValueKind {
1480    fn from(v: Arguments<'_>) -> Self {
1481        Self::String(v.to_string())
1482    }
1483}
1484
1485impl<T: Into<ValueKind> + Clone> From<&'_ T> for ValueKind {
1486    fn from(v: &T) -> Self {
1487        v.clone().into()
1488    }
1489}
1490
1491impl Inspect for () {
1492    fn inspect(&self, req: Request<'_>) {
1493        req.respond();
1494    }
1495}
1496
1497impl InspectMut for () {
1498    fn inspect_mut(&mut self, req: Request<'_>) {
1499        req.respond();
1500    }
1501}
1502
1503macro_rules! inspect_value_immut {
1504    ($($(#[$attr:meta])* $ty:ty),* $(,)?) => {
1505        $(
1506        $(#[$attr])*
1507        impl Inspect for $ty {
1508            fn inspect(&self, req: Request<'_>) {
1509                req.value(self)
1510            }
1511        }
1512        )*
1513    };
1514}
1515
1516macro_rules! inspect_value {
1517    ($($(#[$attr:meta])* $ty:ty),* $(,)?) => {
1518        inspect_value_immut!($($ty,)*);
1519        $(
1520        $(#[$attr])*
1521        impl InspectMut for $ty {
1522            fn inspect_mut(&mut self, req: Request<'_>) {
1523                match req.update() {
1524                    Ok(req) => match req.new_value().parse::<Self>() {
1525                        Ok(v) => {
1526                            *self = v.clone();
1527                            req.succeed(v);
1528                        }
1529                        Err(err) => req.fail(err),
1530                    }
1531                    Err(req) => req.value(&*self),
1532                }
1533            }
1534        }
1535        )*
1536    };
1537}
1538
1539inspect_value_immut! {
1540    str,
1541    #[cfg(feature = "std")]
1542    std::ffi::CStr,
1543    #[cfg(feature = "std")]
1544    std::ffi::CString,
1545    [u8],
1546    Vec<u8>,
1547    Arguments<'_>,
1548}
1549
1550inspect_value! {
1551    u8,
1552    u16,
1553    u32,
1554    u64,
1555    usize,
1556    i8,
1557    i16,
1558    i32,
1559    i64,
1560    isize,
1561    core::num::NonZeroU8,
1562    core::num::NonZeroU16,
1563    core::num::NonZeroU32,
1564    core::num::NonZeroU64,
1565    core::num::NonZeroUsize,
1566    core::num::NonZeroI8,
1567    core::num::NonZeroI16,
1568    core::num::NonZeroI32,
1569    core::num::NonZeroI64,
1570    core::num::NonZeroIsize,
1571    f32,
1572    f64,
1573    bool,
1574    String,
1575}
1576
1577impl<const N: usize> Inspect for [u8; N] {
1578    fn inspect(&self, req: Request<'_>) {
1579        self.as_slice().inspect(req)
1580    }
1581}
1582
1583/// Inspect wrapper for an atomic value (e.g.,
1584/// [`AtomicBool`](core::sync::atomic::AtomicBool), allowing updates.
1585pub struct AtomicMut<T>(pub T);
1586
1587macro_rules! inspect_atomic_value {
1588    ($(($ty:ident, $backing:ty)),* $(,)?) => {
1589        $(
1590
1591        impl Inspect for core::sync::atomic::$ty {
1592            fn inspect(&self, req: Request<'_>) {
1593                req.value(self.load(core::sync::atomic::Ordering::Relaxed))
1594            }
1595        }
1596
1597        // It doesn't make much sense to impl InspectMut, since if you have a &mut
1598        // reference to the Atomic, it's most likely that type didn't need to be
1599        // atomic in the first place.
1600
1601        impl Inspect for AtomicMut<&core::sync::atomic::$ty> {
1602            fn inspect(&self, req: Request<'_>) {
1603                let mut value = self.0.load(core::sync::atomic::Ordering::Relaxed);
1604                let is_update = req.is_update();
1605                value.inspect_mut(req);
1606                if is_update {
1607                    self.0.store(value, core::sync::atomic::Ordering::Relaxed);
1608                }
1609            }
1610        }
1611
1612        )*
1613    };
1614}
1615
1616inspect_atomic_value! {
1617    (AtomicBool,  bool),
1618    (AtomicU8,    u8),
1619    (AtomicU16,   u16),
1620    (AtomicU32,   u32),
1621    (AtomicU64,   u64),
1622    (AtomicUsize, usize),
1623    (AtomicI8,    i8),
1624    (AtomicI16,   i16),
1625    (AtomicI32,   i32),
1626    (AtomicI64,   i64),
1627    (AtomicIsize, isize),
1628}
1629
1630impl<T: Inspect> Inspect for Wrapping<T> {
1631    fn inspect(&self, req: Request<'_>) {
1632        self.0.inspect(req)
1633    }
1634}
1635
1636impl<T: InspectMut> InspectMut for Wrapping<T> {
1637    fn inspect_mut(&mut self, req: Request<'_>) {
1638        self.0.inspect_mut(req)
1639    }
1640}
1641
1642#[cfg(feature = "filepath")]
1643impl Inspect for std::fs::File {
1644    fn inspect(&self, req: Request<'_>) {
1645        use filepath::FilePath;
1646        if let Ok(path) = self.path() {
1647            req.value(path.display().to_string());
1648        } else {
1649            req.ignore();
1650        }
1651    }
1652}
1653
1654/// Wrapper around `T` that implements [`Inspect`] by calling
1655/// [`ToString::to_string()`].
1656pub struct AsDisplay<T>(pub T);
1657
1658impl<T: Display> Inspect for AsDisplay<T> {
1659    fn inspect(&self, req: Request<'_>) {
1660        req.value(self.0.to_string())
1661    }
1662}
1663
1664/// Wrapper around `T` that implements [`Inspect`] by formatting with the
1665/// [`Debug`] trait.
1666pub struct AsDebug<T>(pub T);
1667
1668impl<T: Debug> InspectMut for AsDebug<T> {
1669    fn inspect_mut(&mut self, req: Request<'_>) {
1670        req.value(format!("{:?}", self.0))
1671    }
1672}
1673
1674impl<T: Debug> Inspect for AsDebug<T> {
1675    fn inspect(&self, req: Request<'_>) {
1676        req.value(format!("{:?}", self.0))
1677    }
1678}
1679
1680macro_rules! hexbincount {
1681    ($tr:ident, $fmt:expr) => {
1682        impl<T: Inspect> Inspect for $tr<T> {
1683            fn inspect(&self, mut req: Request<'_>) {
1684                req.number_format = $fmt;
1685                self.0.inspect(req);
1686            }
1687        }
1688
1689        impl<T: InspectMut> InspectMut for $tr<T> {
1690            fn inspect_mut(&mut self, mut req: Request<'_>) {
1691                req.number_format = $fmt;
1692                self.0.inspect_mut(req);
1693            }
1694        }
1695    };
1696}
1697
1698/// Wrapper around `T` that implements [`Inspect`] by writing a value with
1699/// [`ValueFlags::hex`].
1700#[derive(Clone, Copy)]
1701pub struct AsHex<T>(pub T);
1702
1703hexbincount!(AsHex, NumberFormat::Hex);
1704
1705/// Wrapper around `T` that implements [`Inspect`] by writing a value with
1706/// [`ValueFlags::binary`].
1707pub struct AsBinary<T>(pub T);
1708
1709hexbincount!(AsBinary, NumberFormat::Binary);
1710
1711/// Wrapper around `T` that implements [`Inspect`] by writing a value with
1712/// [`ValueFlags::count`].
1713pub struct AsCounter<T>(pub T);
1714
1715hexbincount!(AsCounter, NumberFormat::Counter);
1716
1717/// Wrapper around `T` that implements [`Inspect`] by writing a
1718/// [`ValueKind::Bytes`] value.
1719///
1720/// `T` must be iterable with `u8` or `&u8`.
1721pub struct AsBytes<T>(pub T);
1722
1723impl<T> Inspect for AsBytes<T>
1724where
1725    T: Clone + IntoIterator,
1726    Vec<u8>: Extend<T::Item>,
1727{
1728    fn inspect(&self, req: Request<'_>) {
1729        let mut v = Vec::new();
1730        v.extend(self.0.clone());
1731        req.value(ValueKind::Bytes(v))
1732    }
1733}
1734
1735#[doc(hidden)]
1736pub mod derive_helpers {
1737    /// Helps with type inference in inspect_derive output.
1738    pub fn call<T, F, R>(t: T, f: F) -> R
1739    where
1740        F: Fn(T) -> R,
1741    {
1742        f(t)
1743    }
1744}
1745
1746/// Implementation of [`Inspect`] a type that implements [`Iterator`] with an
1747/// item type `(K, V)`.
1748///
1749/// Inspecting this type will respond with a field for each entry in the
1750/// iterator, with `K` for the field's name and `V` for the field's value.
1751///
1752/// Construct with [`iter_by_key`] or [`iter_by_index`].
1753#[derive(Default)]
1754pub struct Iterated<I>(I);
1755
1756/// Wraps an iterator for inspection.
1757///
1758/// # Example
1759///
1760/// ```rust
1761/// # use std::collections::BTreeMap;
1762/// fn inspect(req: inspect::Request<'_>) {
1763///     let v = BTreeMap::from([("foo", 1), ("bar", 2)]);
1764///     // Responds with { foo: 1, bar: 2 }.
1765///     req.respond().field("v", inspect::iter_by_key(&v));
1766/// }
1767/// ```
1768pub fn iter_by_key<I, K, V>(iter: impl IntoIterator<IntoIter = I>) -> Iterated<I>
1769where
1770    I: Clone + Iterator<Item = (K, V)>,
1771{
1772    Iterated(iter.into_iter())
1773}
1774
1775/// Wraps an iterator for inspection, using the index in the enumeration as
1776/// the field name.
1777///
1778/// # Example
1779///
1780/// ```rust
1781/// fn inspect(req: inspect::Request<'_>) {
1782///     let v = vec!["foo", "bar", "baz"];
1783///     // Responds with { 0: "foo", 1: "bar", 2: "baz" }.
1784///     req.respond().field("v", inspect::iter_by_index(&v));
1785/// }
1786/// ```
1787pub fn iter_by_index<I, V>(
1788    iter: impl IntoIterator<IntoIter = I>,
1789) -> Iterated<core::iter::Enumerate<I>>
1790where
1791    I: Clone + Iterator<Item = V>,
1792{
1793    iter_by_key(iter.into_iter().enumerate())
1794}
1795
1796impl<I, K, V> Iterated<I>
1797where
1798    I: Clone + Iterator<Item = (K, V)>,
1799{
1800    /// Maps the key of the iterator with `f`.
1801    ///
1802    /// # Example
1803    ///
1804    /// ```rust
1805    /// fn inspect(req: inspect::Request<'_>) {
1806    ///     let v = vec!["foo", "bar", "baz"];
1807    ///     // Responds with { 1: "foo", 2: "bar", 3: "baz" }.
1808    ///     req.respond().field("v", inspect::iter_by_index(&v).map_key(|k| k + 1));
1809    /// }
1810    /// ```
1811    pub fn map_key<F, K2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K2, V)>>
1812    where
1813        F: Clone + FnMut(K) -> K2,
1814    {
1815        iter_by_key(self.0.map(move |(k, v)| (f(k), v)))
1816    }
1817
1818    /// Maps the value of the iterator with `f`.
1819    ///
1820    /// # Example
1821    ///
1822    /// ```rust
1823    /// fn inspect(req: inspect::Request<'_>) {
1824    ///     let v = vec![10, 20, 30];
1825    ///     // Responds with { 0: 20, 1: 40, 2: 60 }.
1826    ///     req.respond().field("v", inspect::iter_by_index(&v).map_value(|v| v * 2));
1827    /// }
1828    /// ```
1829    pub fn map_value<F, V2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K, V2)>>
1830    where
1831        F: Clone + FnMut(V) -> V2,
1832    {
1833        iter_by_key(self.0.map(move |(k, v)| (k, f(v))))
1834    }
1835
1836    /// Prefixes each key with the string `prefix`.
1837    ///
1838    /// # Example
1839    ///
1840    /// ```rust
1841    /// fn inspect(req: inspect::Request<'_>) {
1842    ///     let v = vec![10, 20, 30];
1843    ///     // Responds with { n0: 10, n1: 20, n2: 30 }.
1844    ///     req.respond().field("v", inspect::iter_by_index(&v).prefix("n"));
1845    /// }
1846    /// ```
1847    pub fn prefix<'a>(
1848        self,
1849        prefix: &'a str,
1850    ) -> Iterated<impl 'a + Clone + Iterator<Item = (String, V)>>
1851    where
1852        K: Display,
1853        I: 'a,
1854        K: 'a,
1855        V: 'a,
1856    {
1857        self.map_key(move |k| format!("{}{}", prefix, k))
1858    }
1859}
1860
1861impl<I, K, V> Inspect for Iterated<I>
1862where
1863    I: Clone + Iterator<Item = (K, V)>,
1864    K: ToString,
1865    V: Inspect,
1866{
1867    fn inspect(&self, req: Request<'_>) {
1868        let mut resp = req.respond();
1869        for (name, value) in self.0.clone() {
1870            resp.field(&name.to_string(), value);
1871        }
1872    }
1873}
1874
1875#[derive(Debug)]
1876#[cfg_attr(
1877    any(feature = "defer", feature = "initiate"),
1878    derive(mesh::MeshPayload)
1879)]
1880#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1881enum InternalNode {
1882    Unevaluated,
1883    Failed(InternalError),
1884    DepthExhausted,
1885    Value(Value),
1886    Dir(Vec<InternalEntry>),
1887    Ignored,
1888    #[cfg(any(feature = "defer", feature = "initiate"))]
1889    Deferred(mesh::OneshotReceiver<InternalNode>),
1890    #[cfg(any(feature = "defer", feature = "initiate"))]
1891    DirResolved(Vec<InternalEntry>),
1892}
1893
1894#[derive(Debug)]
1895#[cfg_attr(
1896    any(feature = "defer", feature = "initiate"),
1897    derive(mesh::MeshPayload)
1898)]
1899// Without the initiate feature we never read fields of the InternalEntry
1900// to produce a user-visible Entry, but we still need those fields.
1901#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1902struct InternalEntry {
1903    name: String,
1904    node: InternalNode,
1905    sensitivity: SensitivityLevel,
1906}
1907
1908impl InternalNode {
1909    fn as_dir(&mut self) -> &mut Vec<InternalEntry> {
1910        match self {
1911            Self::Dir(children) => children,
1912            _ => {
1913                *self = Self::Dir(Vec::new());
1914                let Self::Dir(children) = self else {
1915                    unreachable!()
1916                };
1917                children
1918            }
1919        }
1920    }
1921}
1922
1923#[derive(Debug)]
1924#[cfg_attr(
1925    any(feature = "defer", feature = "initiate"),
1926    derive(mesh::MeshPayload)
1927)]
1928#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1929enum InternalError {
1930    Immutable,
1931    Update(String),
1932    NotADirectory,
1933    Unresolved,
1934    Mesh(String),
1935}
1936
1937impl InternalNode {
1938    fn failed(err: Box<dyn core::error::Error + Send + Sync>) -> Self {
1939        use core::fmt::Write;
1940
1941        let mut s = err.to_string();
1942        let mut src = err.source();
1943        while let Some(err) = src {
1944            src = err.source();
1945            let _ = write!(&mut s, ": {err}");
1946        }
1947        InternalNode::Failed(InternalError::Update(s))
1948    }
1949}
1950
1951/// Trait implemented by objects whose state can be inspected and mutated. Most users should not implement this trait
1952/// directly, but instead derive [`InspectMut`](derive@InspectMut).
1953///
1954/// See the [`Inspect`] trait for more information on implementation strategies.
1955pub trait InspectMut {
1956    /// Inspects the object.
1957    fn inspect_mut(&mut self, req: Request<'_>);
1958}
1959
1960impl<T: Inspect + ?Sized> InspectMut for &'_ T {
1961    fn inspect_mut(&mut self, req: Request<'_>) {
1962        self.inspect(req);
1963    }
1964}
1965
1966impl<T: InspectMut + ?Sized> InspectMut for &'_ mut T {
1967    fn inspect_mut(&mut self, req: Request<'_>) {
1968        T::inspect_mut(*self, req)
1969    }
1970}
1971
1972impl<T: InspectMut + ?Sized> InspectMut for Box<T> {
1973    fn inspect_mut(&mut self, req: Request<'_>) {
1974        T::inspect_mut(self.as_mut(), req)
1975    }
1976}
1977
1978impl<T: InspectMut> InspectMut for Option<T> {
1979    fn inspect_mut(&mut self, req: Request<'_>) {
1980        if let Some(val) = self {
1981            val.inspect_mut(req);
1982        } else {
1983            req.ignore();
1984        }
1985    }
1986}
1987
1988/// Trait implemented by objects whose state can be inspected but not mutated.
1989///
1990/// For most cases, users should use the derive version of [`Inspect`](derive@Inspect)
1991/// as this will automatically update the implementation as new fields are added.
1992///
1993/// However there are cases where a user may want to manually implement this trait, such as when
1994/// an inspection result may require multiple struct fields for a single inspection field.
1995/// Users should take advantage of Rust's struct destructuring to introduce compiler errors to
1996/// keep manual `Inspect` trait implementations up to date as the struct changes.
1997///
1998/// # Example
1999/// The following code compiles.
2000/// ```no_run
2001/// # use inspect::Inspect;
2002/// struct Foo {
2003///     id: u32,
2004///     more_stuff: usize,
2005///     super_string: String,
2006/// }
2007///
2008/// impl Inspect for Foo {
2009///     fn inspect(&self, req: inspect::Request<'_>) {
2010///         let Foo {
2011///             id,
2012///             more_stuff,
2013///             super_string,
2014///         } = self;
2015///
2016///         let mut resp = req.respond();
2017///         resp.hex("id", id);
2018///         resp.field("more_stuff", more_stuff);
2019///
2020///         // Only provide the super_string field if id is 2.
2021///         if *id == 2 {
2022///             resp.field("super_string", super_string);
2023///         }
2024///     }
2025/// }
2026/// ```
2027///
2028/// However, someone adding a new field to `Foo` without updating the inspect implementation will no longer compile.
2029/// ```compile_fail
2030/// # use inspect::Inspect;
2031/// struct Foo {
2032///     id: u32,
2033///     more_stuff: usize,
2034///     super_string: String,
2035///     awesome_new_field: String,
2036/// }
2037///
2038/// impl Inspect for Foo {
2039///     fn inspect(&self, req: inspect::Request<'_>) {
2040///         let Foo {
2041///             id,
2042///             more_stuff,
2043///             super_string,
2044///             // Missing awesome_new_field!
2045///         } = self;
2046///
2047///         let mut resp = respond();
2048///         resp.hex("id", id);
2049///         resp.field("more_stuff", more_stuff);
2050///
2051///         // Only provide the super_string field if id is 2.
2052///         if id == 2 {
2053///             resp.field("super_string", super_string);
2054///         }
2055///     }
2056/// }
2057/// ```
2058pub trait Inspect {
2059    /// Inspects the object.
2060    fn inspect(&self, req: Request<'_>);
2061}
2062
2063impl<T: Inspect + ?Sized> Inspect for &'_ T {
2064    fn inspect(&self, req: Request<'_>) {
2065        T::inspect(*self, req)
2066    }
2067}
2068
2069impl<T: Inspect + ?Sized> Inspect for &'_ mut T {
2070    fn inspect(&self, req: Request<'_>) {
2071        T::inspect(*self, req)
2072    }
2073}
2074
2075impl<T: Inspect + ?Sized> Inspect for Box<T> {
2076    fn inspect(&self, req: Request<'_>) {
2077        T::inspect(self.as_ref(), req)
2078    }
2079}
2080
2081impl<T: Inspect + ?Sized> Inspect for Rc<T> {
2082    fn inspect(&self, req: Request<'_>) {
2083        T::inspect(self.as_ref(), req)
2084    }
2085}
2086
2087impl<T: Inspect + ?Sized> Inspect for Arc<T> {
2088    fn inspect(&self, req: Request<'_>) {
2089        T::inspect(self.as_ref(), req)
2090    }
2091}
2092
2093impl<T: Inspect + ?Sized> Inspect for parking_lot::Mutex<T> {
2094    fn inspect(&self, req: Request<'_>) {
2095        T::inspect(&*self.lock(), req)
2096    }
2097}
2098
2099impl<T: Inspect + ?Sized> Inspect for parking_lot::RwLock<T> {
2100    fn inspect(&self, req: Request<'_>) {
2101        T::inspect(&*self.read(), req)
2102    }
2103}
2104
2105#[cfg(feature = "std")]
2106impl<T: Inspect> Inspect for std::sync::OnceLock<T> {
2107    fn inspect(&self, req: Request<'_>) {
2108        <_ as Inspect>::inspect(&self.get(), req)
2109    }
2110}
2111
2112impl<T: Inspect> Inspect for Option<T> {
2113    fn inspect(&self, req: Request<'_>) {
2114        if let Some(val) = self {
2115            val.inspect(req);
2116        } else {
2117            req.ignore();
2118        }
2119    }
2120}
2121
2122impl<T: ?Sized + Inspect + ToOwned> Inspect for Cow<'_, T> {
2123    fn inspect(&self, req: Request<'_>) {
2124        self.as_ref().inspect(req)
2125    }
2126}
2127
2128impl<T> Inspect for *mut T {
2129    fn inspect(&self, req: Request<'_>) {
2130        req.with_hex_format().value(*self as usize)
2131    }
2132}
2133
2134impl<T> Inspect for *const T {
2135    fn inspect(&self, req: Request<'_>) {
2136        req.with_hex_format().value(*self as usize)
2137    }
2138}
2139
2140impl Inspect for ValueKind {
2141    fn inspect(&self, req: Request<'_>) {
2142        req.value(self.clone());
2143    }
2144}
2145
2146impl Inspect for Value {
2147    fn inspect(&self, req: Request<'_>) {
2148        let req = if self.flags.count() {
2149            req.with_counter_format()
2150        } else if self.flags.hex() {
2151            req.with_hex_format()
2152        } else if self.flags.binary() {
2153            req.with_binary_format()
2154        } else {
2155            req
2156        };
2157        req.value(self.kind.clone());
2158    }
2159}
2160
2161/// Returned by [`adhoc`] or [`adhoc_mut`].
2162pub struct Adhoc<F>(F);
2163
2164impl<F> InspectMut for Adhoc<F>
2165where
2166    F: FnMut(Request<'_>),
2167{
2168    fn inspect_mut(&mut self, req: Request<'_>) {
2169        (self.0)(req)
2170    }
2171}
2172
2173impl<F> Inspect for Adhoc<F>
2174where
2175    F: Fn(Request<'_>),
2176{
2177    fn inspect(&self, req: Request<'_>) {
2178        (self.0)(req)
2179    }
2180}
2181
2182/// Returns an object that implements `Inspect` by calling `f` with the
2183/// inspection request.
2184pub fn adhoc<F>(f: F) -> Adhoc<F>
2185where
2186    F: Fn(Request<'_>),
2187{
2188    Adhoc(f)
2189}
2190
2191/// Returns an object that implements `InspectMut` by calling `f` with the
2192/// inspection request.
2193pub fn adhoc_mut<F>(f: F) -> Adhoc<F>
2194where
2195    F: FnMut(Request<'_>),
2196{
2197    Adhoc(f)
2198}
2199
2200#[cfg(all(test, feature = "derive", feature = "initiate"))]
2201mod tests {
2202    use crate::AsBytes;
2203    use crate::AtomicMut;
2204    use crate::Error;
2205    use crate::Inspect;
2206    use crate::InspectMut;
2207    use crate::InspectionBuilder;
2208    use crate::Node;
2209    use crate::Request;
2210    use crate::SensitivityLevel;
2211    use crate::ValueKind;
2212    use crate::adhoc;
2213    use crate::adhoc_mut;
2214    use crate::inspect;
2215    use crate::update;
2216    use alloc::boxed::Box;
2217    use alloc::string::String;
2218    use alloc::string::ToString;
2219    use alloc::vec;
2220    use alloc::vec::Vec;
2221    use core::time::Duration;
2222    use expect_test::Expect;
2223    use expect_test::expect;
2224    use futures::FutureExt;
2225    use pal_async::DefaultDriver;
2226    use pal_async::async_test;
2227    use pal_async::timer::Instant;
2228    use pal_async::timer::PolledTimer;
2229
2230    fn expected_node(node: Node, expect: Expect) -> Node {
2231        expect.assert_eq(&std::format!("{node:#}"));
2232        node
2233    }
2234
2235    async fn inspect_async(
2236        driver: &DefaultDriver,
2237        path: &str,
2238        depth: Option<usize>,
2239        timeout: Duration,
2240        obj: impl InspectMut,
2241    ) -> Node {
2242        let deadline = Instant::now() + timeout;
2243        let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2244        let mut timer = PolledTimer::new(driver);
2245        futures::select! { // race semantics
2246            _ = result.resolve().fuse() => {}
2247            _ = timer.sleep_until(deadline).fuse() => {}
2248        };
2249        result.results()
2250    }
2251
2252    async fn inspect_async_expect(
2253        driver: &DefaultDriver,
2254        path: &str,
2255        depth: Option<usize>,
2256        timeout: Duration,
2257        obj: impl InspectMut,
2258        expect: Expect,
2259    ) -> Node {
2260        expected_node(
2261            inspect_async(driver, path, depth, timeout, obj).await,
2262            expect,
2263        )
2264    }
2265
2266    fn inspect_sync(path: &str, depth: Option<usize>, obj: impl InspectMut) -> Node {
2267        let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2268        result.resolve().now_or_never();
2269        result.results()
2270    }
2271
2272    fn inspect_sync_expect(
2273        path: &str,
2274        depth: Option<usize>,
2275        obj: impl InspectMut,
2276        expect: Expect,
2277    ) -> Node {
2278        expected_node(inspect_sync(path, depth, obj), expect)
2279    }
2280
2281    #[derive(Default)]
2282    struct Foo {
2283        xx: u32,
2284        xy: bool,
2285        xz: Vec<Foo>,
2286    }
2287
2288    impl Inspect for Foo {
2289        fn inspect(&self, req: Request<'_>) {
2290            let mut resp = req.respond();
2291            resp.field("xx", self.xx)
2292                .field("xy", self.xy)
2293                .fields("", self.xz.iter().enumerate());
2294        }
2295    }
2296
2297    #[test]
2298    fn test() {
2299        let f = Foo {
2300            xx: 1,
2301            xy: true,
2302            xz: vec![
2303                Foo {
2304                    xx: 3,
2305                    xy: false,
2306                    xz: vec![],
2307                },
2308                Foo {
2309                    xx: 5,
2310                    xy: true,
2311                    xz: vec![],
2312                },
2313            ],
2314        };
2315        let node = inspect_sync_expect(
2316            "",
2317            None,
2318            &f,
2319            expect!([r#"
2320                {
2321                    0: {
2322                        xx: 3,
2323                        xy: false,
2324                    },
2325                    1: {
2326                        xx: 5,
2327                        xy: true,
2328                    },
2329                    xx: 1,
2330                    xy: true,
2331                }"#]),
2332        );
2333        let expected_json =
2334            expect!([r#"{"0":{"xx":3,"xy":false},"1":{"xx":5,"xy":true},"xx":1,"xy":true}"#]);
2335        expected_json.assert_eq(&node.json().to_string());
2336    }
2337
2338    #[async_test]
2339    async fn test_deferred(driver: DefaultDriver) {
2340        inspect_async_expect(
2341            &driver,
2342            "",
2343            None,
2344            Duration::from_secs(1),
2345            adhoc(|req| {
2346                let foo = req.defer();
2347                std::thread::spawn(|| foo.inspect(&Foo::default()));
2348            }),
2349            expect!([r#"
2350                {
2351                    xx: 0,
2352                    xy: false,
2353                }"#]),
2354        )
2355        .await;
2356    }
2357
2358    #[async_test]
2359    async fn test_dropped(driver: DefaultDriver) {
2360        inspect_async_expect(
2361            &driver,
2362            "",
2363            None,
2364            Duration::from_secs(86400),
2365            adhoc(|req| {
2366                drop(req.defer());
2367            }),
2368            expect!("error (unresolved)"),
2369        )
2370        .await;
2371    }
2372
2373    #[test]
2374    fn test_path() {
2375        let mut obj = adhoc(|req| {
2376            req.respond().field("a", 1).child("b", |req| {
2377                req.respond().field("c", 2).field("d", 2).child("e", |req| {
2378                    req.respond();
2379                });
2380            });
2381        });
2382        inspect_sync_expect("a", None, &mut obj, expect!("1"));
2383        inspect_sync_expect("///a", None, &mut obj, expect!("1"));
2384        inspect_sync_expect(
2385            "b",
2386            None,
2387            &mut obj,
2388            expect!([r#"
2389            {
2390                c: 2,
2391                d: 2,
2392                e: {},
2393            }"#]),
2394        );
2395        inspect_sync_expect("b/c", None, &mut obj, expect!("2"));
2396        inspect_sync_expect("b////c", None, &mut obj, expect!("2"));
2397        inspect_sync_expect("b/c/", None, &mut obj, expect!("error (not a directory)"));
2398        inspect_sync_expect("b/c/x", None, &mut obj, expect!("error (not a directory)"));
2399        inspect_sync_expect("b/e", None, &mut obj, expect!("{}"));
2400        inspect_sync_expect("b/e/", None, &mut obj, expect!("{}"));
2401        inspect_sync_expect("b/e///", None, &mut obj, expect!("{}"));
2402        inspect_sync_expect("b/f", None, &mut obj, expect!("error (not found)"));
2403    }
2404
2405    #[async_test]
2406    async fn test_timeout(driver: DefaultDriver) {
2407        inspect_async_expect(
2408            &driver,
2409            "",
2410            None,
2411            Duration::from_millis(10),
2412            adhoc(|req| {
2413                let foo = req.defer();
2414                std::thread::spawn(|| {
2415                    std::thread::sleep(Duration::from_millis(250));
2416                    foo.inspect(&Foo::default())
2417                });
2418            }),
2419            expect!("error (unresolved)"),
2420        )
2421        .await;
2422    }
2423
2424    #[test]
2425    fn test_merge() {
2426        let mut obj = adhoc(|req| {
2427            req.respond()
2428                .field("a", 1)
2429                .request()
2430                .respond()
2431                .field("b", 2);
2432        });
2433
2434        inspect_sync_expect(
2435            "",
2436            None,
2437            &mut obj,
2438            expect!([r#"
2439            {
2440                a: 1,
2441                b: 2,
2442            }"#]),
2443        );
2444        inspect_sync_expect("a", None, &mut obj, expect!("1"));
2445        inspect_sync_expect("b", None, &mut obj, expect!("2"));
2446        inspect_sync_expect("c", None, &mut obj, expect!("error (not found)"));
2447    }
2448
2449    #[test]
2450    fn test_named_merge() {
2451        let mut obj = adhoc(|req| {
2452            req.respond()
2453                .field("a", 1)
2454                .field("a", 2)
2455                .child("x", |req| {
2456                    req.respond().field("b", 3).child("c", |req| {
2457                        req.respond().field("y", 4);
2458                    });
2459                })
2460                .child("x", |req| {
2461                    req.respond().field("b", 4).child("d", |req| {
2462                        req.respond().field("y", 5);
2463                    });
2464                });
2465        });
2466
2467        inspect_sync_expect(
2468            "",
2469            None,
2470            &mut obj,
2471            expect!([r#"
2472                {
2473                    a: 2,
2474                    x: {
2475                        b: 4,
2476                        c: {
2477                            y: 4,
2478                        },
2479                        d: {
2480                            y: 5,
2481                        },
2482                    },
2483                }"#]),
2484        );
2485        inspect_sync_expect(
2486            "x",
2487            None,
2488            &mut obj,
2489            expect!([r#"
2490            {
2491                b: 4,
2492                c: {
2493                    y: 4,
2494                },
2495                d: {
2496                    y: 5,
2497                },
2498            }"#]),
2499        );
2500    }
2501
2502    #[test]
2503    fn test_update() {
2504        struct Foo {
2505            immut: u32,
2506            mut_: u32,
2507            child: Option<Box<Foo>>,
2508        }
2509
2510        impl InspectMut for Foo {
2511            fn inspect_mut(&mut self, req: Request<'_>) {
2512                let mut resp = req.respond();
2513                resp.field("immut", self.immut)
2514                    .field_mut("mut", &mut self.mut_)
2515                    .field_mut("child", &mut self.child);
2516            }
2517        }
2518
2519        let mut foo = Foo {
2520            immut: 1,
2521            mut_: 2,
2522            child: Some(Box::new(Foo {
2523                immut: 101,
2524                mut_: 102,
2525                child: None,
2526            })),
2527        };
2528        assert_eq!(
2529            update("immut", "12", &mut foo)
2530                .now_or_never()
2531                .unwrap()
2532                .unwrap_err(),
2533            Error::Immutable
2534        );
2535        assert_eq!(
2536            update("mut/", "4", &mut foo)
2537                .now_or_never()
2538                .unwrap()
2539                .unwrap_err(),
2540            Error::NotADirectory
2541        );
2542        assert_eq!(
2543            update("mut", "3", &mut foo)
2544                .now_or_never()
2545                .unwrap()
2546                .unwrap()
2547                .kind,
2548            ValueKind::Unsigned(3)
2549        );
2550        assert_eq!(
2551            update("//child/mut", "103", &mut foo)
2552                .now_or_never()
2553                .unwrap()
2554                .unwrap()
2555                .kind,
2556            ValueKind::Unsigned(103)
2557        );
2558        assert_eq!(foo.mut_, 3);
2559        assert_eq!(foo.child.as_ref().unwrap().mut_, 103);
2560    }
2561
2562    #[test]
2563    fn test_nest() {
2564        let mut obj = adhoc(|req| {
2565            req.respond().field("x/a/b", 1).field("x/a/c", 2);
2566        });
2567
2568        inspect_sync_expect(
2569            "",
2570            None,
2571            &mut obj,
2572            expect!([r#"
2573            {
2574                x: {
2575                    a: {
2576                        b: 1,
2577                        c: 2,
2578                    },
2579                },
2580            }"#]),
2581        );
2582        inspect_sync_expect(
2583            "x/a",
2584            None,
2585            &mut obj,
2586            expect!([r#"
2587            {
2588                b: 1,
2589                c: 2,
2590            }"#]),
2591        );
2592        inspect_sync_expect(
2593            "x",
2594            Some(0),
2595            &mut obj,
2596            expect!([r#"
2597            {
2598                a: _,
2599            }"#]),
2600        );
2601        inspect_sync_expect(
2602            "x",
2603            Some(2),
2604            &mut obj,
2605            expect!([r#"
2606            {
2607                a: {
2608                    b: 1,
2609                    c: 2,
2610                },
2611            }"#]),
2612        );
2613    }
2614
2615    #[test]
2616    fn test_depth() {
2617        let mut obj = adhoc(|req| {
2618            req.respond()
2619                .field("1a", 0)
2620                .field("1b", 0)
2621                .field("1c", 0)
2622                .child("1d", |req| {
2623                    req.respond().field("2a", 0).child("2b", |req| {
2624                        req.respond().child("3a", |req| {
2625                            req.respond().field_with("xxx", || -> u32 { panic!() });
2626                        });
2627                    });
2628                })
2629                .field("1d/2b/3b", 0);
2630        });
2631
2632        inspect_sync_expect(
2633            "1d",
2634            Some(0),
2635            &mut obj,
2636            expect!([r#"
2637            {
2638                2a: 0,
2639                2b: _,
2640            }"#]),
2641        );
2642        inspect_sync_expect(
2643            "",
2644            Some(0),
2645            &mut obj,
2646            expect!([r#"
2647                {
2648                    1a: 0,
2649                    1b: 0,
2650                    1c: 0,
2651                    1d: _,
2652                }"#]),
2653        );
2654        inspect_sync_expect(
2655            "",
2656            Some(1),
2657            &mut obj,
2658            expect!([r#"
2659                {
2660                    1a: 0,
2661                    1b: 0,
2662                    1c: 0,
2663                    1d: {
2664                        2a: 0,
2665                        2b: _,
2666                    },
2667                }"#]),
2668        );
2669    }
2670
2671    #[test]
2672    fn test_hex() {
2673        let mut obj = adhoc(|req| {
2674            req.respond().hex("a", 0x1234);
2675        });
2676        inspect_sync_expect(
2677            "",
2678            Some(0),
2679            &mut obj,
2680            expect!([r#"
2681            {
2682                a: 0x1234,
2683            }"#]),
2684        );
2685    }
2686
2687    #[test]
2688    fn test_binary() {
2689        let mut obj = adhoc(|req| {
2690            req.respond().binary("a", 0b1001000110100);
2691        });
2692        inspect_sync_expect(
2693            "",
2694            Some(0),
2695            &mut obj,
2696            expect!([r#"
2697            {
2698                a: 0b1001000110100,
2699            }"#]),
2700        );
2701    }
2702
2703    #[test]
2704    fn test_since() {
2705        let mut n = 500_u32;
2706        let mut b = false;
2707        let mut obj = adhoc_mut(|req| {
2708            req.respond()
2709                .counter("c", n)
2710                .field("f", n)
2711                .child("d", |req| {
2712                    let mut resp = req.respond();
2713                    if !b {
2714                        resp.field("1_a", true).field("1_b", true);
2715                    } else {
2716                        resp.field("1_c", true);
2717                    }
2718                    resp.field("2", true).counter("3", n);
2719                    if !b {
2720                        resp.field("4_a", true);
2721                    } else {
2722                        resp.field("4_b", true).field("4_c", true);
2723                    }
2724                });
2725            n += 100;
2726            b = true;
2727        });
2728        let old = inspect_sync("", Some(1), &mut obj);
2729        let new = inspect_sync("", Some(1), &mut obj);
2730
2731        let diff = new.since(&old, Duration::from_secs(2));
2732
2733        expected_node(
2734            diff,
2735            expect!([r#"
2736                {
2737                    c: 50,
2738                    d: {
2739                        1_c: true,
2740                        2: true,
2741                        3: 50,
2742                        4_b: true,
2743                        4_c: true,
2744                    },
2745                    f: 600,
2746                }"#]),
2747        );
2748    }
2749
2750    #[test]
2751    fn test_bytes() {
2752        inspect_sync_expect(
2753            "",
2754            Some(1),
2755            &AsBytes([0xab, 0xcd, 0xef]),
2756            expect!("<abcdef>"),
2757        );
2758    }
2759
2760    #[test]
2761    fn test_sensitivity() {
2762        let mut obj = adhoc(|req| {
2763            req.respond()
2764                .sensitivity_field("1a", SensitivityLevel::Safe, 0)
2765                .sensitivity_field("1b", SensitivityLevel::Unspecified, 0)
2766                .sensitivity_field("1c", SensitivityLevel::Sensitive, 0)
2767                .sensitivity_child("1d", SensitivityLevel::Safe, |req| {
2768                    req.respond()
2769                        .sensitivity_field("2a", SensitivityLevel::Sensitive, 0)
2770                        .sensitivity_child("2b", SensitivityLevel::Safe, |req| {
2771                            req.respond().sensitivity_child(
2772                                "3a",
2773                                SensitivityLevel::Sensitive,
2774                                |req| {
2775                                    req.respond().sensitivity_field(
2776                                        "4a",
2777                                        SensitivityLevel::Safe,
2778                                        0,
2779                                    );
2780                                },
2781                            );
2782                        });
2783                })
2784                .sensitivity_field("1d/2b/3b", SensitivityLevel::Unspecified, 0)
2785                .sensitivity_child("", SensitivityLevel::Sensitive, |req| {
2786                    req.respond()
2787                        .sensitivity_field("1e", SensitivityLevel::Safe, 0);
2788                });
2789        });
2790
2791        fn inspect_sync(
2792            path: &str,
2793            sensitivity: Option<SensitivityLevel>,
2794            obj: impl InspectMut,
2795        ) -> Node {
2796            let mut result = InspectionBuilder::new(path)
2797                .sensitivity(sensitivity)
2798                .inspect(obj);
2799            result.resolve().now_or_never();
2800            result.results()
2801        }
2802
2803        expected_node(
2804            inspect_sync("", Some(SensitivityLevel::Safe), &mut obj),
2805            expect!([r#"
2806                {
2807                    1a: 0,
2808                    1d: {
2809                        2b: {},
2810                    },
2811                }"#]),
2812        );
2813        expected_node(
2814            inspect_sync("", Some(SensitivityLevel::Unspecified), &mut obj),
2815            expect!([r#"
2816                {
2817                    1a: 0,
2818                    1b: 0,
2819                    1d: {
2820                        2b: {
2821                            3b: 0,
2822                        },
2823                    },
2824                }"#]),
2825        );
2826        expected_node(
2827            inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2828            expect!([r#"
2829                {
2830                    1a: 0,
2831                    1b: 0,
2832                    1c: 0,
2833                    1d: {
2834                        2a: 0,
2835                        2b: {
2836                            3a: {
2837                                4a: 0,
2838                            },
2839                            3b: 0,
2840                        },
2841                    },
2842                    1e: 0,
2843                }"#]),
2844        );
2845        expected_node(
2846            inspect_sync("", None, &mut obj),
2847            expect!([r#"
2848                {
2849                    1a: 0,
2850                    1b: 0,
2851                    1c: 0,
2852                    1d: {
2853                        2a: 0,
2854                        2b: {
2855                            3a: {
2856                                4a: 0,
2857                            },
2858                            3b: 0,
2859                        },
2860                    },
2861                    1e: 0,
2862                }"#]),
2863        );
2864        expected_node(
2865            inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2866            expect!([r#"
2867                {
2868                    1a: 0,
2869                    1b: 0,
2870                    1c: 0,
2871                    1d: {
2872                        2a: 0,
2873                        2b: {
2874                            3a: {
2875                                4a: 0,
2876                            },
2877                            3b: 0,
2878                        },
2879                    },
2880                    1e: 0,
2881                }"#]),
2882        );
2883    }
2884
2885    #[test]
2886    fn test_derive() {
2887        use std::marker::PhantomData;
2888
2889        #[derive(InspectMut)]
2890        struct Derived {
2891            dec: u32,
2892            #[inspect(hex, rename = "hex")]
2893            val2: u64,
2894            #[inspect(binary)]
2895            bin: u8,
2896            inner: Inner,
2897            #[inspect(mut)]
2898            inner_mut: InnerMut,
2899            #[inspect(flatten)]
2900            flattened: Inner,
2901            #[inspect(skip)]
2902            _skip: bool,
2903            t: Transparent,
2904            t2: Newtype,
2905            #[inspect(format = "{:02x}")]
2906            minute: u8,
2907            #[inspect(debug)]
2908            debug: (),
2909            #[inspect(display)]
2910            display: u8,
2911            var: Enum,
2912            ignored: Ignored,
2913            tr1: Tr1,
2914            tr2: Tr2,
2915            #[inspect(iter_by_index, hex)]
2916            hex_array: [u8; 4],
2917            hex_inner: HexInner,
2918            #[inspect(hex)]
2919            inner_as_hex: Inner,
2920        }
2921
2922        #[derive(Clone, Inspect)]
2923        struct Inner {
2924            val: u32,
2925        }
2926
2927        #[derive(InspectMut)]
2928        struct InnerMut {
2929            val: String,
2930        }
2931
2932        #[derive(Inspect)]
2933        #[inspect(hex)]
2934        struct HexInner {
2935            val: u32,
2936        }
2937
2938        #[derive(Inspect)]
2939        #[inspect(transparent)]
2940        struct Transparent {
2941            inner: Inner,
2942        }
2943
2944        #[derive(Inspect)]
2945        #[inspect(transparent)]
2946        struct Newtype(Inner, PhantomData<()>);
2947
2948        #[derive(Inspect)]
2949        #[inspect(transparent(hex))]
2950        struct Tr1(u32, PhantomData<()>);
2951
2952        #[derive(Inspect)]
2953        #[inspect(transparent)]
2954        struct Tr2(#[inspect(debug)] ());
2955
2956        #[derive(Inspect)]
2957        #[expect(dead_code)]
2958        enum Enum {
2959            Foo,
2960            BarBaz,
2961            #[inspect(rename = "brother")]
2962            Other,
2963        }
2964
2965        #[derive(Inspect)]
2966        #[inspect(skip)]
2967        struct Ignored {
2968            _x: fn(),
2969        }
2970
2971        let mut obj = Derived {
2972            dec: 5,
2973            val2: 4,
2974            bin: 3,
2975            inner: Inner { val: 3 },
2976            inner_mut: InnerMut {
2977                val: "hi".to_string(),
2978            },
2979            _skip: true,
2980            flattened: Inner { val: 8 },
2981            t: Transparent {
2982                inner: Inner { val: 1 },
2983            },
2984            t2: Newtype(Inner { val: 2 }, PhantomData),
2985            debug: (),
2986            display: 10,
2987            minute: 7,
2988            var: Enum::BarBaz,
2989            ignored: Ignored { _x: || () },
2990            tr1: Tr1(10, PhantomData),
2991            tr2: Tr2(()),
2992            hex_array: [100, 101, 102, 103],
2993            hex_inner: HexInner { val: 100 },
2994            inner_as_hex: Inner { val: 100 },
2995        };
2996
2997        inspect_sync_expect(
2998            "",
2999            None,
3000            &mut obj,
3001            expect!([r#"
3002                {
3003                    bin: 0b11,
3004                    debug: "()",
3005                    dec: 5,
3006                    display: "10",
3007                    hex: 0x4,
3008                    hex_array: {
3009                        0: 0x64,
3010                        1: 0x65,
3011                        2: 0x66,
3012                        3: 0x67,
3013                    },
3014                    hex_inner: {
3015                        val: 0x64,
3016                    },
3017                    inner: {
3018                        val: 3,
3019                    },
3020                    inner_as_hex: {
3021                        val: 0x64,
3022                    },
3023                    inner_mut: {
3024                        val: "hi",
3025                    },
3026                    minute: "07",
3027                    t: {
3028                        val: 1,
3029                    },
3030                    t2: {
3031                        val: 2,
3032                    },
3033                    tr1: 0xa,
3034                    tr2: "()",
3035                    val: 8,
3036                    var: "bar_baz",
3037                }"#]),
3038        );
3039    }
3040
3041    #[test]
3042    fn test_derive_enum() {
3043        #[expect(dead_code)]
3044        #[derive(Inspect)]
3045        enum EmptyUnitEmum {}
3046
3047        #[expect(dead_code)]
3048        #[derive(Inspect)]
3049        #[inspect(untagged)]
3050        enum EmptyUntaggedEmum {}
3051
3052        #[expect(dead_code)]
3053        #[derive(Inspect)]
3054        enum UnitEnum {
3055            A,
3056            B,
3057            C,
3058        }
3059
3060        inspect_sync_expect("", None, &UnitEnum::B, expect!([r#""b""#]));
3061
3062        #[expect(dead_code)]
3063        #[derive(Inspect)]
3064        #[inspect(tag = "tag")]
3065        enum TaggedEnum {
3066            A { x: u32 },
3067            B(#[inspect(rename = "y")] bool),
3068        }
3069
3070        inspect_sync_expect(
3071            "",
3072            None,
3073            &TaggedEnum::B(true),
3074            expect!([r#"
3075                {
3076                    tag: "b",
3077                    y: true,
3078                }"#]),
3079        );
3080
3081        #[expect(dead_code)]
3082        #[derive(Inspect)]
3083        #[inspect(external_tag)]
3084        enum ExternallyTaggedEnum {
3085            A {
3086                x: u32,
3087            },
3088            B(#[inspect(rename = "y")] bool),
3089            #[inspect(transparent)]
3090            C(u32),
3091        }
3092
3093        inspect_sync_expect(
3094            "",
3095            None,
3096            &ExternallyTaggedEnum::B(true),
3097            expect!([r#"
3098                {
3099                    b: {
3100                        y: true,
3101                    },
3102                }"#]),
3103        );
3104
3105        inspect_sync_expect(
3106            "",
3107            None,
3108            &ExternallyTaggedEnum::C(5),
3109            expect!([r#"
3110            {
3111                c: 5,
3112            }"#]),
3113        );
3114
3115        #[expect(dead_code)]
3116        #[derive(Inspect)]
3117        #[inspect(untagged)]
3118        enum UntaggedEnum {
3119            A { x: u32 },
3120            B(#[inspect(rename = "y")] bool),
3121        }
3122
3123        inspect_sync_expect(
3124            "",
3125            None,
3126            &UntaggedEnum::B(true),
3127            expect!([r#"
3128            {
3129                y: true,
3130            }"#]),
3131        );
3132    }
3133
3134    #[test]
3135    fn test_derive_extra() {
3136        #[derive(Inspect)]
3137        #[inspect(extra = "Foo::inspect_extra")]
3138        struct Foo {
3139            x: u32,
3140            y: u32,
3141        }
3142
3143        impl Foo {
3144            fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
3145                resp.field("sum", self.x + self.y);
3146            }
3147        }
3148
3149        inspect_sync_expect(
3150            "",
3151            None,
3152            &Foo { x: 2, y: 5 },
3153            expect!([r#"
3154                {
3155                    sum: 7,
3156                    x: 2,
3157                    y: 5,
3158                }"#]),
3159        );
3160    }
3161
3162    #[test]
3163    fn test_derive_sensitivity() {
3164        #[derive(Inspect)]
3165        struct Foo {
3166            #[inspect(safe)]
3167            a: u32,
3168            b: u32,
3169            #[inspect(sensitive)]
3170            c: u32,
3171            #[inspect(safe)]
3172            d: Bar,
3173        }
3174        #[derive(Inspect)]
3175        struct Bar {
3176            #[inspect(sensitive)]
3177            a: u32,
3178            #[inspect(safe)]
3179            b: Baz,
3180        }
3181        #[derive(Inspect)]
3182        struct Baz {
3183            #[inspect(sensitive)]
3184            a: Qux,
3185            b: u32,
3186        }
3187        #[derive(Inspect)]
3188        struct Qux {
3189            #[inspect(safe)]
3190            a: u32,
3191        }
3192
3193        fn inspect_sync(
3194            path: &str,
3195            sensitivity: Option<SensitivityLevel>,
3196            obj: impl Inspect,
3197        ) -> Node {
3198            let mut result = InspectionBuilder::new(path)
3199                .sensitivity(sensitivity)
3200                .inspect(&obj);
3201            result.resolve().now_or_never();
3202            result.results()
3203        }
3204
3205        let obj = Foo {
3206            a: 0,
3207            b: 0,
3208            c: 0,
3209            d: Bar {
3210                a: 0,
3211                b: Baz {
3212                    a: Qux { a: 0 },
3213                    b: 0,
3214                },
3215            },
3216        };
3217
3218        expected_node(
3219            inspect_sync("", Some(SensitivityLevel::Safe), &obj),
3220            expect!([r#"
3221                {
3222                    a: 0,
3223                    d: {
3224                        b: {},
3225                    },
3226                }"#]),
3227        );
3228        expected_node(
3229            inspect_sync("", Some(SensitivityLevel::Unspecified), &obj),
3230            expect!([r#"
3231                {
3232                    a: 0,
3233                    b: 0,
3234                    d: {
3235                        b: {
3236                            b: 0,
3237                        },
3238                    },
3239                }"#]),
3240        );
3241        let node = expected_node(
3242            inspect_sync("", Some(SensitivityLevel::Sensitive), &obj),
3243            expect!([r#"
3244                {
3245                    a: 0,
3246                    b: 0,
3247                    c: 0,
3248                    d: {
3249                        a: 0,
3250                        b: {
3251                            a: {
3252                                a: 0,
3253                            },
3254                            b: 0,
3255                        },
3256                    },
3257                }"#]),
3258        );
3259        assert_eq!(
3260            node,
3261            inspect_sync("", Some(SensitivityLevel::Sensitive), &obj)
3262        );
3263    }
3264
3265    /// Test that you can update via AtomicMut.
3266    #[test]
3267    fn test_atomic_mut() {
3268        let mut v = core::sync::atomic::AtomicBool::new(false);
3269        let obj = AtomicMut(&v);
3270        update("", "true", &obj).now_or_never().unwrap().unwrap();
3271        assert!(*v.get_mut());
3272    }
3273}