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