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
1623/// Wrapper around `T` that implements [`Inspect`] by calling
1624/// [`ToString::to_string()`].
1625pub struct AsDisplay<T>(pub T);
1626
1627impl<T: Display> Inspect for AsDisplay<T> {
1628    fn inspect(&self, req: Request<'_>) {
1629        req.value(self.0.to_string())
1630    }
1631}
1632
1633/// Wrapper around `T` that implements [`Inspect`] by formatting with the
1634/// [`Debug`] trait.
1635pub struct AsDebug<T>(pub T);
1636
1637impl<T: Debug> InspectMut for AsDebug<T> {
1638    fn inspect_mut(&mut self, req: Request<'_>) {
1639        req.value(format!("{:?}", self.0))
1640    }
1641}
1642
1643impl<T: Debug> Inspect for AsDebug<T> {
1644    fn inspect(&self, req: Request<'_>) {
1645        req.value(format!("{:?}", self.0))
1646    }
1647}
1648
1649macro_rules! hexbincount {
1650    ($tr:ident, $fmt:expr) => {
1651        impl<T: Inspect> Inspect for $tr<T> {
1652            fn inspect(&self, mut req: Request<'_>) {
1653                req.params.number_format = $fmt;
1654                self.0.inspect(req);
1655            }
1656        }
1657
1658        impl<T: InspectMut> InspectMut for $tr<T> {
1659            fn inspect_mut(&mut self, mut req: Request<'_>) {
1660                req.params.number_format = $fmt;
1661                self.0.inspect_mut(req);
1662            }
1663        }
1664    };
1665}
1666
1667/// Wrapper around `T` that implements [`Inspect`] by writing a value with
1668/// [`ValueFlags::hex`].
1669#[derive(Clone, Copy)]
1670pub struct AsHex<T>(pub T);
1671
1672hexbincount!(AsHex, NumberFormat::Hex);
1673
1674/// Wrapper around `T` that implements [`Inspect`] by writing a value with
1675/// [`ValueFlags::binary`].
1676pub struct AsBinary<T>(pub T);
1677
1678hexbincount!(AsBinary, NumberFormat::Binary);
1679
1680/// Wrapper around `T` that implements [`Inspect`] by writing a value with
1681/// [`ValueFlags::count`].
1682pub struct AsCounter<T>(pub T);
1683
1684hexbincount!(AsCounter, NumberFormat::Counter);
1685
1686/// Wrapper around `T` that implements [`Inspect`] by writing a
1687/// [`ValueKind::Bytes`] value.
1688///
1689/// `T` must be iterable with `u8` or `&u8`.
1690pub struct AsBytes<T>(pub T);
1691
1692impl<T> Inspect for AsBytes<T>
1693where
1694    T: Clone + IntoIterator,
1695    Vec<u8>: Extend<T::Item>,
1696{
1697    fn inspect(&self, req: Request<'_>) {
1698        let mut v = Vec::new();
1699        v.extend(self.0.clone());
1700        req.value(ValueKind::Bytes(v))
1701    }
1702}
1703
1704#[doc(hidden)]
1705pub mod derive_helpers {
1706    /// Helps with type inference in inspect_derive output.
1707    pub fn call<T, F, R>(t: T, f: F) -> R
1708    where
1709        F: Fn(T) -> R,
1710    {
1711        f(t)
1712    }
1713}
1714
1715/// Implementation of [`Inspect`] a type that implements [`Iterator`] with an
1716/// item type `(K, V)`.
1717///
1718/// Inspecting this type will respond with a field for each entry in the
1719/// iterator, with `K` for the field's name and `V` for the field's value.
1720///
1721/// Construct with [`iter_by_key`] or [`iter_by_index`].
1722#[derive(Default)]
1723pub struct Iterated<I>(I);
1724
1725/// Wraps an iterator for inspection.
1726///
1727/// # Example
1728///
1729/// ```rust
1730/// # use std::collections::BTreeMap;
1731/// fn inspect(req: inspect::Request<'_>) {
1732///     let v = BTreeMap::from([("foo", 1), ("bar", 2)]);
1733///     // Responds with { foo: 1, bar: 2 }.
1734///     req.respond().field("v", inspect::iter_by_key(&v));
1735/// }
1736/// ```
1737pub fn iter_by_key<I, K, V>(iter: impl IntoIterator<IntoIter = I>) -> Iterated<I>
1738where
1739    I: Clone + Iterator<Item = (K, V)>,
1740{
1741    Iterated(iter.into_iter())
1742}
1743
1744/// Wraps an iterator for inspection, using the index in the enumeration as
1745/// the field name.
1746///
1747/// # Example
1748///
1749/// ```rust
1750/// fn inspect(req: inspect::Request<'_>) {
1751///     let v = vec!["foo", "bar", "baz"];
1752///     // Responds with { 0: "foo", 1: "bar", 2: "baz" }.
1753///     req.respond().field("v", inspect::iter_by_index(&v));
1754/// }
1755/// ```
1756pub fn iter_by_index<I, V>(
1757    iter: impl IntoIterator<IntoIter = I>,
1758) -> Iterated<core::iter::Enumerate<I>>
1759where
1760    I: Clone + Iterator<Item = V>,
1761{
1762    iter_by_key(iter.into_iter().enumerate())
1763}
1764
1765impl<I, K, V> Iterated<I>
1766where
1767    I: Clone + Iterator<Item = (K, V)>,
1768{
1769    /// Maps the key of the iterator with `f`.
1770    ///
1771    /// # Example
1772    ///
1773    /// ```rust
1774    /// fn inspect(req: inspect::Request<'_>) {
1775    ///     let v = vec!["foo", "bar", "baz"];
1776    ///     // Responds with { 1: "foo", 2: "bar", 3: "baz" }.
1777    ///     req.respond().field("v", inspect::iter_by_index(&v).map_key(|k| k + 1));
1778    /// }
1779    /// ```
1780    pub fn map_key<F, K2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K2, V)>>
1781    where
1782        F: Clone + FnMut(K) -> K2,
1783    {
1784        iter_by_key(self.0.map(move |(k, v)| (f(k), v)))
1785    }
1786
1787    /// Maps the value of the iterator with `f`.
1788    ///
1789    /// # Example
1790    ///
1791    /// ```rust
1792    /// fn inspect(req: inspect::Request<'_>) {
1793    ///     let v = vec![10, 20, 30];
1794    ///     // Responds with { 0: 20, 1: 40, 2: 60 }.
1795    ///     req.respond().field("v", inspect::iter_by_index(&v).map_value(|v| v * 2));
1796    /// }
1797    /// ```
1798    pub fn map_value<F, V2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K, V2)>>
1799    where
1800        F: Clone + FnMut(V) -> V2,
1801    {
1802        iter_by_key(self.0.map(move |(k, v)| (k, f(v))))
1803    }
1804
1805    /// Prefixes each key with the string `prefix`.
1806    ///
1807    /// # Example
1808    ///
1809    /// ```rust
1810    /// fn inspect(req: inspect::Request<'_>) {
1811    ///     let v = vec![10, 20, 30];
1812    ///     // Responds with { n0: 10, n1: 20, n2: 30 }.
1813    ///     req.respond().field("v", inspect::iter_by_index(&v).prefix("n"));
1814    /// }
1815    /// ```
1816    pub fn prefix<'a>(
1817        self,
1818        prefix: &'a str,
1819    ) -> Iterated<impl 'a + Clone + Iterator<Item = (String, V)>>
1820    where
1821        K: Display,
1822        I: 'a,
1823        K: 'a,
1824        V: 'a,
1825    {
1826        self.map_key(move |k| format!("{}{}", prefix, k))
1827    }
1828}
1829
1830impl<I, K, V> Inspect for Iterated<I>
1831where
1832    I: Clone + Iterator<Item = (K, V)>,
1833    K: ToString,
1834    V: Inspect,
1835{
1836    fn inspect(&self, req: Request<'_>) {
1837        let mut resp = req.respond();
1838        for (name, value) in self.0.clone() {
1839            resp.field(&name.to_string(), value);
1840        }
1841    }
1842}
1843
1844#[derive(Debug)]
1845#[cfg_attr(
1846    any(feature = "defer", feature = "initiate"),
1847    derive(mesh::MeshPayload)
1848)]
1849#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1850enum InternalNode {
1851    Unevaluated,
1852    Failed(InternalError),
1853    DepthExhausted,
1854    Value(Value),
1855    Dir(Vec<InternalEntry>),
1856    Ignored,
1857    #[cfg(any(feature = "defer", feature = "initiate"))]
1858    Deferred(mesh::OneshotReceiver<InternalNode>),
1859    #[cfg(any(feature = "defer", feature = "initiate"))]
1860    DirResolved(Vec<InternalEntry>),
1861}
1862
1863#[derive(Debug)]
1864#[cfg_attr(
1865    any(feature = "defer", feature = "initiate"),
1866    derive(mesh::MeshPayload)
1867)]
1868// Without the initiate feature we never read fields of the InternalEntry
1869// to produce a user-visible Entry, but we still need those fields.
1870#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1871struct InternalEntry {
1872    name: String,
1873    node: InternalNode,
1874    sensitivity: SensitivityLevel,
1875}
1876
1877#[derive(Debug)]
1878#[cfg_attr(
1879    any(feature = "defer", feature = "initiate"),
1880    derive(mesh::MeshPayload)
1881)]
1882#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1883enum InternalError {
1884    Immutable,
1885    Update(String),
1886    NotADirectory,
1887    Unresolved,
1888    Mesh(String),
1889}
1890
1891impl InternalNode {
1892    fn failed(err: Box<dyn core::error::Error + Send + Sync>) -> Self {
1893        use core::fmt::Write;
1894
1895        let mut s = err.to_string();
1896        let mut src = err.source();
1897        while let Some(err) = src {
1898            src = err.source();
1899            let _ = write!(&mut s, ": {err}");
1900        }
1901        InternalNode::Failed(InternalError::Update(s))
1902    }
1903}
1904
1905/// Trait implemented by objects whose state can be inspected and mutated. Most users should not implement this trait
1906/// directly, but instead derive [`InspectMut`](derive@InspectMut).
1907///
1908/// See the [`Inspect`] trait for more information on implementation strategies.
1909pub trait InspectMut {
1910    /// Inspects the object.
1911    fn inspect_mut(&mut self, req: Request<'_>);
1912}
1913
1914impl<T: Inspect + ?Sized> InspectMut for &'_ T {
1915    fn inspect_mut(&mut self, req: Request<'_>) {
1916        self.inspect(req);
1917    }
1918}
1919
1920impl<T: InspectMut + ?Sized> InspectMut for &'_ mut T {
1921    fn inspect_mut(&mut self, req: Request<'_>) {
1922        T::inspect_mut(*self, req)
1923    }
1924}
1925
1926impl<T: InspectMut + ?Sized> InspectMut for Box<T> {
1927    fn inspect_mut(&mut self, req: Request<'_>) {
1928        T::inspect_mut(self.as_mut(), req)
1929    }
1930}
1931
1932impl<T: InspectMut> InspectMut for Option<T> {
1933    fn inspect_mut(&mut self, req: Request<'_>) {
1934        if let Some(val) = self {
1935            val.inspect_mut(req);
1936        } else {
1937            req.ignore();
1938        }
1939    }
1940}
1941
1942/// Trait implemented by objects whose state can be inspected but not mutated.
1943///
1944/// For most cases, users should use the derive version of [`Inspect`](derive@Inspect)
1945/// as this will automatically update the implementation as new fields are added.
1946///
1947/// However there are cases where a user may want to manually implement this trait, such as when
1948/// an inspection result may require multiple struct fields for a single inspection field.
1949/// Users should take advantage of Rust's struct destructuring to introduce compiler errors to
1950/// keep manual `Inspect` trait implementations up to date as the struct changes.
1951///
1952/// # Example
1953/// The following code compiles.
1954/// ```no_run
1955/// # use inspect::Inspect;
1956/// struct Foo {
1957///     id: u32,
1958///     more_stuff: usize,
1959///     super_string: String,
1960/// }
1961///
1962/// impl Inspect for Foo {
1963///     fn inspect(&self, req: inspect::Request<'_>) {
1964///         let Foo {
1965///             id,
1966///             more_stuff,
1967///             super_string,
1968///         } = self;
1969///
1970///         let mut resp = req.respond();
1971///         resp.hex("id", id);
1972///         resp.field("more_stuff", more_stuff);
1973///
1974///         // Only provide the super_string field if id is 2.
1975///         if *id == 2 {
1976///             resp.field("super_string", super_string);
1977///         }
1978///     }
1979/// }
1980/// ```
1981///
1982/// However, someone adding a new field to `Foo` without updating the inspect implementation will no longer compile.
1983/// ```compile_fail
1984/// # use inspect::Inspect;
1985/// struct Foo {
1986///     id: u32,
1987///     more_stuff: usize,
1988///     super_string: String,
1989///     awesome_new_field: String,
1990/// }
1991///
1992/// impl Inspect for Foo {
1993///     fn inspect(&self, req: inspect::Request<'_>) {
1994///         let Foo {
1995///             id,
1996///             more_stuff,
1997///             super_string,
1998///             // Missing awesome_new_field!
1999///         } = self;
2000///
2001///         let mut resp = respond();
2002///         resp.hex("id", id);
2003///         resp.field("more_stuff", more_stuff);
2004///
2005///         // Only provide the super_string field if id is 2.
2006///         if id == 2 {
2007///             resp.field("super_string", super_string);
2008///         }
2009///     }
2010/// }
2011/// ```
2012pub trait Inspect {
2013    /// Inspects the object.
2014    fn inspect(&self, req: Request<'_>);
2015}
2016
2017impl<T: Inspect + ?Sized> Inspect for &'_ T {
2018    fn inspect(&self, req: Request<'_>) {
2019        T::inspect(*self, req)
2020    }
2021}
2022
2023impl<T: Inspect + ?Sized> Inspect for &'_ mut T {
2024    fn inspect(&self, req: Request<'_>) {
2025        T::inspect(*self, req)
2026    }
2027}
2028
2029impl<T: Inspect + ?Sized> Inspect for Box<T> {
2030    fn inspect(&self, req: Request<'_>) {
2031        T::inspect(self.as_ref(), req)
2032    }
2033}
2034
2035impl<T: Inspect + ?Sized> Inspect for Rc<T> {
2036    fn inspect(&self, req: Request<'_>) {
2037        T::inspect(self.as_ref(), req)
2038    }
2039}
2040
2041impl<T: Inspect + ?Sized> Inspect for Arc<T> {
2042    fn inspect(&self, req: Request<'_>) {
2043        T::inspect(self.as_ref(), req)
2044    }
2045}
2046
2047impl<T: Inspect + ?Sized> Inspect for parking_lot::Mutex<T> {
2048    fn inspect(&self, req: Request<'_>) {
2049        T::inspect(&*self.lock(), req)
2050    }
2051}
2052
2053impl<T: Inspect + ?Sized> Inspect for parking_lot::RwLock<T> {
2054    fn inspect(&self, req: Request<'_>) {
2055        T::inspect(&*self.read(), req)
2056    }
2057}
2058
2059#[cfg(feature = "std")]
2060impl<T: Inspect> Inspect for std::sync::OnceLock<T> {
2061    fn inspect(&self, req: Request<'_>) {
2062        <_ as Inspect>::inspect(&self.get(), req)
2063    }
2064}
2065
2066impl<T: Inspect> Inspect for Option<T> {
2067    fn inspect(&self, req: Request<'_>) {
2068        if let Some(val) = self {
2069            val.inspect(req);
2070        } else {
2071            req.ignore();
2072        }
2073    }
2074}
2075
2076impl<T: ?Sized + Inspect + ToOwned> Inspect for Cow<'_, T> {
2077    fn inspect(&self, req: Request<'_>) {
2078        self.as_ref().inspect(req)
2079    }
2080}
2081
2082impl<T> Inspect for *mut T {
2083    fn inspect(&self, req: Request<'_>) {
2084        req.with_hex_format().value(*self as usize)
2085    }
2086}
2087
2088impl<T> Inspect for *const T {
2089    fn inspect(&self, req: Request<'_>) {
2090        req.with_hex_format().value(*self as usize)
2091    }
2092}
2093
2094impl Inspect for ValueKind {
2095    fn inspect(&self, req: Request<'_>) {
2096        req.value(self.clone());
2097    }
2098}
2099
2100impl Inspect for Value {
2101    fn inspect(&self, req: Request<'_>) {
2102        let req = if self.flags.count() {
2103            req.with_counter_format()
2104        } else if self.flags.hex() {
2105            req.with_hex_format()
2106        } else if self.flags.binary() {
2107            req.with_binary_format()
2108        } else {
2109            req
2110        };
2111        req.value(self.kind.clone());
2112    }
2113}
2114
2115/// Returned by [`adhoc`] or [`adhoc_mut`].
2116pub struct Adhoc<F>(F);
2117
2118impl<F> InspectMut for Adhoc<F>
2119where
2120    F: FnMut(Request<'_>),
2121{
2122    fn inspect_mut(&mut self, req: Request<'_>) {
2123        (self.0)(req)
2124    }
2125}
2126
2127impl<F> Inspect for Adhoc<F>
2128where
2129    F: Fn(Request<'_>),
2130{
2131    fn inspect(&self, req: Request<'_>) {
2132        (self.0)(req)
2133    }
2134}
2135
2136/// Returns an object that implements `Inspect` by calling `f` with the
2137/// inspection request.
2138pub fn adhoc<F>(f: F) -> Adhoc<F>
2139where
2140    F: Fn(Request<'_>),
2141{
2142    Adhoc(f)
2143}
2144
2145/// Returns an object that implements `InspectMut` by calling `f` with the
2146/// inspection request.
2147pub fn adhoc_mut<F>(f: F) -> Adhoc<F>
2148where
2149    F: FnMut(Request<'_>),
2150{
2151    Adhoc(f)
2152}
2153
2154#[cfg(all(test, feature = "derive", feature = "initiate"))]
2155mod tests {
2156    use crate::AsBytes;
2157    use crate::AtomicMut;
2158    use crate::Error;
2159    use crate::Inspect;
2160    use crate::InspectMut;
2161    use crate::InspectionBuilder;
2162    use crate::Node;
2163    use crate::Request;
2164    use crate::SensitivityLevel;
2165    use crate::ValueKind;
2166    use crate::adhoc;
2167    use crate::adhoc_mut;
2168    use crate::inspect;
2169    use crate::update;
2170    use alloc::boxed::Box;
2171    use alloc::string::String;
2172    use alloc::string::ToString;
2173    use alloc::vec;
2174    use alloc::vec::Vec;
2175    use core::time::Duration;
2176    use expect_test::Expect;
2177    use expect_test::expect;
2178    use futures::FutureExt;
2179    use pal_async::DefaultDriver;
2180    use pal_async::async_test;
2181    use pal_async::timer::Instant;
2182    use pal_async::timer::PolledTimer;
2183
2184    fn expected_node(node: Node, expect: Expect) -> Node {
2185        expect.assert_eq(&std::format!("{node:#}"));
2186        node
2187    }
2188
2189    async fn inspect_async(
2190        driver: &DefaultDriver,
2191        path: &str,
2192        depth: Option<usize>,
2193        timeout: Duration,
2194        obj: impl InspectMut,
2195    ) -> Node {
2196        let deadline = Instant::now() + timeout;
2197        let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2198        let mut timer = PolledTimer::new(driver);
2199        futures::select! { // race semantics
2200            _ = result.resolve().fuse() => {}
2201            _ = timer.sleep_until(deadline).fuse() => {}
2202        };
2203        result.results()
2204    }
2205
2206    async fn inspect_async_expect(
2207        driver: &DefaultDriver,
2208        path: &str,
2209        depth: Option<usize>,
2210        timeout: Duration,
2211        obj: impl InspectMut,
2212        expect: Expect,
2213    ) -> Node {
2214        expected_node(
2215            inspect_async(driver, path, depth, timeout, obj).await,
2216            expect,
2217        )
2218    }
2219
2220    fn inspect_sync(path: &str, depth: Option<usize>, obj: impl InspectMut) -> Node {
2221        let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2222        result.resolve().now_or_never();
2223        result.results()
2224    }
2225
2226    fn inspect_sync_expect(
2227        path: &str,
2228        depth: Option<usize>,
2229        obj: impl InspectMut,
2230        expect: Expect,
2231    ) -> Node {
2232        expected_node(inspect_sync(path, depth, obj), expect)
2233    }
2234
2235    #[derive(Default)]
2236    struct Foo {
2237        xx: u32,
2238        xy: bool,
2239        xz: Vec<Foo>,
2240    }
2241
2242    impl Inspect for Foo {
2243        fn inspect(&self, req: Request<'_>) {
2244            let mut resp = req.respond();
2245            resp.field("xx", self.xx)
2246                .field("xy", self.xy)
2247                .fields("", self.xz.iter().enumerate());
2248        }
2249    }
2250
2251    #[test]
2252    fn test() {
2253        let f = Foo {
2254            xx: 1,
2255            xy: true,
2256            xz: vec![
2257                Foo {
2258                    xx: 3,
2259                    xy: false,
2260                    xz: vec![],
2261                },
2262                Foo {
2263                    xx: 5,
2264                    xy: true,
2265                    xz: vec![],
2266                },
2267            ],
2268        };
2269        let node = inspect_sync_expect(
2270            "",
2271            None,
2272            &f,
2273            expect!([r#"
2274                {
2275                    0: {
2276                        xx: 3,
2277                        xy: false,
2278                    },
2279                    1: {
2280                        xx: 5,
2281                        xy: true,
2282                    },
2283                    xx: 1,
2284                    xy: true,
2285                }"#]),
2286        );
2287        let expected_json =
2288            expect!([r#"{"0":{"xx":3,"xy":false},"1":{"xx":5,"xy":true},"xx":1,"xy":true}"#]);
2289        expected_json.assert_eq(&node.json().to_string());
2290    }
2291
2292    #[async_test]
2293    async fn test_deferred(driver: DefaultDriver) {
2294        inspect_async_expect(
2295            &driver,
2296            "",
2297            None,
2298            Duration::from_secs(1),
2299            adhoc(|req| {
2300                let foo = req.defer();
2301                std::thread::spawn(|| foo.inspect(&Foo::default()));
2302            }),
2303            expect!([r#"
2304                {
2305                    xx: 0,
2306                    xy: false,
2307                }"#]),
2308        )
2309        .await;
2310    }
2311
2312    #[async_test]
2313    async fn test_dropped(driver: DefaultDriver) {
2314        inspect_async_expect(
2315            &driver,
2316            "",
2317            None,
2318            Duration::from_secs(86400),
2319            adhoc(|req| {
2320                drop(req.defer());
2321            }),
2322            expect!("error (unresolved)"),
2323        )
2324        .await;
2325    }
2326
2327    #[test]
2328    fn test_path() {
2329        let mut obj = adhoc(|req| {
2330            req.respond().field("a", 1).child("b", |req| {
2331                req.respond().field("c", 2).field("d", 2).child("e", |req| {
2332                    req.respond();
2333                });
2334            });
2335        });
2336        inspect_sync_expect("a", None, &mut obj, expect!("1"));
2337        inspect_sync_expect("///a", None, &mut obj, expect!("1"));
2338        inspect_sync_expect(
2339            "b",
2340            None,
2341            &mut obj,
2342            expect!([r#"
2343            {
2344                c: 2,
2345                d: 2,
2346                e: {},
2347            }"#]),
2348        );
2349        inspect_sync_expect("b/c", None, &mut obj, expect!("2"));
2350        inspect_sync_expect("b////c", None, &mut obj, expect!("2"));
2351        inspect_sync_expect("b/c/", None, &mut obj, expect!("error (not a directory)"));
2352        inspect_sync_expect("b/c/x", None, &mut obj, expect!("error (not a directory)"));
2353        inspect_sync_expect("b/e", None, &mut obj, expect!("{}"));
2354        inspect_sync_expect("b/e/", None, &mut obj, expect!("{}"));
2355        inspect_sync_expect("b/e///", None, &mut obj, expect!("{}"));
2356        inspect_sync_expect("b/f", None, &mut obj, expect!("error (not found)"));
2357    }
2358
2359    #[async_test]
2360    async fn test_timeout(driver: DefaultDriver) {
2361        inspect_async_expect(
2362            &driver,
2363            "",
2364            None,
2365            Duration::from_millis(10),
2366            adhoc(|req| {
2367                let foo = req.defer();
2368                std::thread::spawn(|| {
2369                    std::thread::sleep(Duration::from_millis(250));
2370                    foo.inspect(&Foo::default())
2371                });
2372            }),
2373            expect!("error (unresolved)"),
2374        )
2375        .await;
2376    }
2377
2378    #[test]
2379    fn test_merge() {
2380        let mut obj = adhoc(|req| {
2381            req.respond().field("a", 1).merge(adhoc(|req| {
2382                req.respond().field("b", 2);
2383            }));
2384        });
2385
2386        inspect_sync_expect(
2387            "",
2388            None,
2389            &mut obj,
2390            expect!([r#"
2391            {
2392                a: 1,
2393                b: 2,
2394            }"#]),
2395        );
2396        inspect_sync_expect("a", None, &mut obj, expect!("1"));
2397        inspect_sync_expect("b", None, &mut obj, expect!("2"));
2398        inspect_sync_expect("c", None, &mut obj, expect!("error (not found)"));
2399    }
2400
2401    #[test]
2402    fn test_named_merge() {
2403        let mut obj = adhoc(|req| {
2404            req.respond()
2405                .field("a", 1)
2406                .field("a", 2)
2407                .child("x", |req| {
2408                    req.respond().field("b", 3).child("c", |req| {
2409                        req.respond().field("y", 4);
2410                    });
2411                })
2412                .child("x", |req| {
2413                    req.respond().field("b", 4).child("d", |req| {
2414                        req.respond().field("y", 5);
2415                    });
2416                });
2417        });
2418
2419        inspect_sync_expect(
2420            "",
2421            None,
2422            &mut obj,
2423            expect!([r#"
2424                {
2425                    a: 2,
2426                    x: {
2427                        b: 4,
2428                        c: {
2429                            y: 4,
2430                        },
2431                        d: {
2432                            y: 5,
2433                        },
2434                    },
2435                }"#]),
2436        );
2437        inspect_sync_expect(
2438            "x",
2439            None,
2440            &mut obj,
2441            expect!([r#"
2442            {
2443                b: 4,
2444                c: {
2445                    y: 4,
2446                },
2447                d: {
2448                    y: 5,
2449                },
2450            }"#]),
2451        );
2452    }
2453
2454    #[test]
2455    fn test_update() {
2456        struct Foo {
2457            immut: u32,
2458            mut_: u32,
2459            child: Option<Box<Foo>>,
2460        }
2461
2462        impl InspectMut for Foo {
2463            fn inspect_mut(&mut self, req: Request<'_>) {
2464                let mut resp = req.respond();
2465                resp.field("immut", self.immut)
2466                    .field_mut("mut", &mut self.mut_)
2467                    .field_mut("child", &mut self.child);
2468            }
2469        }
2470
2471        let mut foo = Foo {
2472            immut: 1,
2473            mut_: 2,
2474            child: Some(Box::new(Foo {
2475                immut: 101,
2476                mut_: 102,
2477                child: None,
2478            })),
2479        };
2480        assert_eq!(
2481            update("immut", "12", &mut foo)
2482                .now_or_never()
2483                .unwrap()
2484                .unwrap_err(),
2485            Error::Immutable
2486        );
2487        assert_eq!(
2488            update("mut/", "4", &mut foo)
2489                .now_or_never()
2490                .unwrap()
2491                .unwrap_err(),
2492            Error::NotADirectory
2493        );
2494        assert_eq!(
2495            update("mut", "3", &mut foo)
2496                .now_or_never()
2497                .unwrap()
2498                .unwrap()
2499                .kind,
2500            ValueKind::Unsigned(3)
2501        );
2502        assert_eq!(
2503            update("//child/mut", "103", &mut foo)
2504                .now_or_never()
2505                .unwrap()
2506                .unwrap()
2507                .kind,
2508            ValueKind::Unsigned(103)
2509        );
2510        assert_eq!(foo.mut_, 3);
2511        assert_eq!(foo.child.as_ref().unwrap().mut_, 103);
2512    }
2513
2514    #[test]
2515    fn test_nest() {
2516        let mut obj = adhoc(|req| {
2517            req.respond().field("x/a/b", 1).field("x/a/c", 2);
2518        });
2519
2520        inspect_sync_expect(
2521            "",
2522            None,
2523            &mut obj,
2524            expect!([r#"
2525            {
2526                x: {
2527                    a: {
2528                        b: 1,
2529                        c: 2,
2530                    },
2531                },
2532            }"#]),
2533        );
2534        inspect_sync_expect(
2535            "x/a",
2536            None,
2537            &mut obj,
2538            expect!([r#"
2539            {
2540                b: 1,
2541                c: 2,
2542            }"#]),
2543        );
2544        inspect_sync_expect(
2545            "x",
2546            Some(0),
2547            &mut obj,
2548            expect!([r#"
2549            {
2550                a: _,
2551            }"#]),
2552        );
2553        inspect_sync_expect(
2554            "x",
2555            Some(2),
2556            &mut obj,
2557            expect!([r#"
2558            {
2559                a: {
2560                    b: 1,
2561                    c: 2,
2562                },
2563            }"#]),
2564        );
2565    }
2566
2567    #[test]
2568    fn test_depth() {
2569        let mut obj = adhoc(|req| {
2570            req.respond()
2571                .field("1a", 0)
2572                .field("1b", 0)
2573                .field("1c", 0)
2574                .child("1d", |req| {
2575                    req.respond().field("2a", 0).child("2b", |req| {
2576                        req.respond().child("3a", |req| {
2577                            req.respond().field_with("xxx", || -> u32 { panic!() });
2578                        });
2579                    });
2580                })
2581                .field("1d/2b/3b", 0);
2582        });
2583
2584        inspect_sync_expect(
2585            "1d",
2586            Some(0),
2587            &mut obj,
2588            expect!([r#"
2589            {
2590                2a: 0,
2591                2b: _,
2592            }"#]),
2593        );
2594        inspect_sync_expect(
2595            "",
2596            Some(0),
2597            &mut obj,
2598            expect!([r#"
2599                {
2600                    1a: 0,
2601                    1b: 0,
2602                    1c: 0,
2603                    1d: _,
2604                }"#]),
2605        );
2606        inspect_sync_expect(
2607            "",
2608            Some(1),
2609            &mut obj,
2610            expect!([r#"
2611                {
2612                    1a: 0,
2613                    1b: 0,
2614                    1c: 0,
2615                    1d: {
2616                        2a: 0,
2617                        2b: _,
2618                    },
2619                }"#]),
2620        );
2621    }
2622
2623    #[test]
2624    fn test_hex() {
2625        let mut obj = adhoc(|req| {
2626            req.respond().hex("a", 0x1234);
2627        });
2628        inspect_sync_expect(
2629            "",
2630            Some(0),
2631            &mut obj,
2632            expect!([r#"
2633            {
2634                a: 0x1234,
2635            }"#]),
2636        );
2637    }
2638
2639    #[test]
2640    fn test_binary() {
2641        let mut obj = adhoc(|req| {
2642            req.respond().binary("a", 0b1001000110100);
2643        });
2644        inspect_sync_expect(
2645            "",
2646            Some(0),
2647            &mut obj,
2648            expect!([r#"
2649            {
2650                a: 0b1001000110100,
2651            }"#]),
2652        );
2653    }
2654
2655    #[test]
2656    fn test_since() {
2657        let mut n = 500_u32;
2658        let mut b = false;
2659        let mut obj = adhoc_mut(|req| {
2660            req.respond()
2661                .counter("c", n)
2662                .field("f", n)
2663                .child("d", |req| {
2664                    let mut resp = req.respond();
2665                    if !b {
2666                        resp.field("1_a", true).field("1_b", true);
2667                    } else {
2668                        resp.field("1_c", true);
2669                    }
2670                    resp.field("2", true).counter("3", n);
2671                    if !b {
2672                        resp.field("4_a", true);
2673                    } else {
2674                        resp.field("4_b", true).field("4_c", true);
2675                    }
2676                });
2677            n += 100;
2678            b = true;
2679        });
2680        let old = inspect_sync("", Some(1), &mut obj);
2681        let new = inspect_sync("", Some(1), &mut obj);
2682
2683        let diff = new.since(&old, Duration::from_secs(2));
2684
2685        expected_node(
2686            diff,
2687            expect!([r#"
2688                {
2689                    c: 50,
2690                    d: {
2691                        1_c: true,
2692                        2: true,
2693                        3: 50,
2694                        4_b: true,
2695                        4_c: true,
2696                    },
2697                    f: 600,
2698                }"#]),
2699        );
2700    }
2701
2702    #[test]
2703    fn test_bytes() {
2704        inspect_sync_expect(
2705            "",
2706            Some(1),
2707            &AsBytes([0xab, 0xcd, 0xef]),
2708            expect!("<abcdef>"),
2709        );
2710    }
2711
2712    #[test]
2713    fn test_sensitivity() {
2714        let mut obj = adhoc(|req| {
2715            req.respond()
2716                .sensitivity_field("1a", SensitivityLevel::Safe, 0)
2717                .sensitivity_field("1b", SensitivityLevel::Unspecified, 0)
2718                .sensitivity_field("1c", SensitivityLevel::Sensitive, 0)
2719                .sensitivity_child("1d", SensitivityLevel::Safe, |req| {
2720                    req.respond()
2721                        .sensitivity_field("2a", SensitivityLevel::Sensitive, 0)
2722                        .sensitivity_child("2b", SensitivityLevel::Safe, |req| {
2723                            req.respond().sensitivity_child(
2724                                "3a",
2725                                SensitivityLevel::Sensitive,
2726                                |req| {
2727                                    req.respond().sensitivity_field(
2728                                        "4a",
2729                                        SensitivityLevel::Safe,
2730                                        0,
2731                                    );
2732                                },
2733                            );
2734                        });
2735                })
2736                .sensitivity_field("1d/2b/3b", SensitivityLevel::Unspecified, 0)
2737                .sensitivity_child("", SensitivityLevel::Sensitive, |req| {
2738                    req.respond()
2739                        .sensitivity_field("1e", SensitivityLevel::Safe, 0);
2740                });
2741        });
2742
2743        fn inspect_sync(
2744            path: &str,
2745            sensitivity: Option<SensitivityLevel>,
2746            obj: impl InspectMut,
2747        ) -> Node {
2748            let mut result = InspectionBuilder::new(path)
2749                .sensitivity(sensitivity)
2750                .inspect(obj);
2751            result.resolve().now_or_never();
2752            result.results()
2753        }
2754
2755        expected_node(
2756            inspect_sync("", Some(SensitivityLevel::Safe), &mut obj),
2757            expect!([r#"
2758                {
2759                    1a: 0,
2760                    1d: {
2761                        2b: {},
2762                    },
2763                }"#]),
2764        );
2765        expected_node(
2766            inspect_sync("", Some(SensitivityLevel::Unspecified), &mut obj),
2767            expect!([r#"
2768                {
2769                    1a: 0,
2770                    1b: 0,
2771                    1d: {
2772                        2b: {
2773                            3b: 0,
2774                        },
2775                    },
2776                }"#]),
2777        );
2778        expected_node(
2779            inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2780            expect!([r#"
2781                {
2782                    1a: 0,
2783                    1b: 0,
2784                    1c: 0,
2785                    1d: {
2786                        2a: 0,
2787                        2b: {
2788                            3a: {
2789                                4a: 0,
2790                            },
2791                            3b: 0,
2792                        },
2793                    },
2794                    1e: 0,
2795                }"#]),
2796        );
2797        expected_node(
2798            inspect_sync("", None, &mut obj),
2799            expect!([r#"
2800                {
2801                    1a: 0,
2802                    1b: 0,
2803                    1c: 0,
2804                    1d: {
2805                        2a: 0,
2806                        2b: {
2807                            3a: {
2808                                4a: 0,
2809                            },
2810                            3b: 0,
2811                        },
2812                    },
2813                    1e: 0,
2814                }"#]),
2815        );
2816        expected_node(
2817            inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2818            expect!([r#"
2819                {
2820                    1a: 0,
2821                    1b: 0,
2822                    1c: 0,
2823                    1d: {
2824                        2a: 0,
2825                        2b: {
2826                            3a: {
2827                                4a: 0,
2828                            },
2829                            3b: 0,
2830                        },
2831                    },
2832                    1e: 0,
2833                }"#]),
2834        );
2835    }
2836
2837    #[test]
2838    fn test_derive() {
2839        use std::marker::PhantomData;
2840
2841        #[derive(InspectMut)]
2842        struct Derived {
2843            dec: u32,
2844            #[inspect(hex, rename = "hex")]
2845            val2: u64,
2846            #[inspect(binary)]
2847            bin: u8,
2848            inner: Inner,
2849            #[inspect(mut)]
2850            inner_mut: InnerMut,
2851            #[inspect(flatten)]
2852            flattened: Inner,
2853            #[inspect(skip)]
2854            _skip: bool,
2855            t: Transparent,
2856            t2: Newtype,
2857            #[inspect(format = "{:02x}")]
2858            minute: u8,
2859            #[inspect(debug)]
2860            debug: (),
2861            #[inspect(display)]
2862            display: u8,
2863            var: Enum,
2864            ignored: Ignored,
2865            tr1: Tr1,
2866            tr2: Tr2,
2867            #[inspect(iter_by_index, hex)]
2868            hex_array: [u8; 4],
2869            hex_inner: HexInner,
2870            #[inspect(hex)]
2871            inner_as_hex: Inner,
2872        }
2873
2874        #[derive(Clone, Inspect)]
2875        struct Inner {
2876            val: u32,
2877        }
2878
2879        #[derive(InspectMut)]
2880        struct InnerMut {
2881            val: String,
2882        }
2883
2884        #[derive(Inspect)]
2885        #[inspect(hex)]
2886        struct HexInner {
2887            val: u32,
2888        }
2889
2890        #[derive(Inspect)]
2891        #[inspect(transparent)]
2892        struct Transparent {
2893            inner: Inner,
2894        }
2895
2896        #[derive(Inspect)]
2897        #[inspect(transparent)]
2898        struct Newtype(Inner, PhantomData<()>);
2899
2900        #[derive(Inspect)]
2901        #[inspect(transparent(hex))]
2902        struct Tr1(u32, PhantomData<()>);
2903
2904        #[derive(Inspect)]
2905        #[inspect(transparent)]
2906        struct Tr2(#[inspect(debug)] ());
2907
2908        #[derive(Inspect)]
2909        #[expect(dead_code)]
2910        enum Enum {
2911            Foo,
2912            BarBaz,
2913            #[inspect(rename = "brother")]
2914            Other,
2915        }
2916
2917        #[derive(Inspect)]
2918        #[inspect(skip)]
2919        struct Ignored {
2920            _x: fn(),
2921        }
2922
2923        let mut obj = Derived {
2924            dec: 5,
2925            val2: 4,
2926            bin: 3,
2927            inner: Inner { val: 3 },
2928            inner_mut: InnerMut {
2929                val: "hi".to_string(),
2930            },
2931            _skip: true,
2932            flattened: Inner { val: 8 },
2933            t: Transparent {
2934                inner: Inner { val: 1 },
2935            },
2936            t2: Newtype(Inner { val: 2 }, PhantomData),
2937            debug: (),
2938            display: 10,
2939            minute: 7,
2940            var: Enum::BarBaz,
2941            ignored: Ignored { _x: || () },
2942            tr1: Tr1(10, PhantomData),
2943            tr2: Tr2(()),
2944            hex_array: [100, 101, 102, 103],
2945            hex_inner: HexInner { val: 100 },
2946            inner_as_hex: Inner { val: 100 },
2947        };
2948
2949        inspect_sync_expect(
2950            "",
2951            None,
2952            &mut obj,
2953            expect!([r#"
2954                {
2955                    bin: 0b11,
2956                    debug: "()",
2957                    dec: 5,
2958                    display: "10",
2959                    hex: 0x4,
2960                    hex_array: {
2961                        0: 0x64,
2962                        1: 0x65,
2963                        2: 0x66,
2964                        3: 0x67,
2965                    },
2966                    hex_inner: {
2967                        val: 0x64,
2968                    },
2969                    inner: {
2970                        val: 3,
2971                    },
2972                    inner_as_hex: {
2973                        val: 0x64,
2974                    },
2975                    inner_mut: {
2976                        val: "hi",
2977                    },
2978                    minute: "07",
2979                    t: {
2980                        val: 1,
2981                    },
2982                    t2: {
2983                        val: 2,
2984                    },
2985                    tr1: 0xa,
2986                    tr2: "()",
2987                    val: 8,
2988                    var: "bar_baz",
2989                }"#]),
2990        );
2991    }
2992
2993    #[test]
2994    fn test_derive_enum() {
2995        #[expect(dead_code)]
2996        #[derive(Inspect)]
2997        enum EmptyUnitEmum {}
2998
2999        #[expect(dead_code)]
3000        #[derive(Inspect)]
3001        #[inspect(untagged)]
3002        enum EmptyUntaggedEmum {}
3003
3004        #[expect(dead_code)]
3005        #[derive(Inspect)]
3006        enum UnitEnum {
3007            A,
3008            B,
3009            C,
3010        }
3011
3012        inspect_sync_expect("", None, &UnitEnum::B, expect!([r#""b""#]));
3013
3014        #[expect(dead_code)]
3015        #[derive(Inspect)]
3016        #[inspect(tag = "tag")]
3017        enum TaggedEnum {
3018            A { x: u32 },
3019            B(#[inspect(rename = "y")] bool),
3020        }
3021
3022        inspect_sync_expect(
3023            "",
3024            None,
3025            &TaggedEnum::B(true),
3026            expect!([r#"
3027                {
3028                    tag: "b",
3029                    y: true,
3030                }"#]),
3031        );
3032
3033        #[expect(dead_code)]
3034        #[derive(Inspect)]
3035        #[inspect(external_tag)]
3036        enum ExternallyTaggedEnum {
3037            A {
3038                x: u32,
3039            },
3040            B(#[inspect(rename = "y")] bool),
3041            #[inspect(transparent)]
3042            C(u32),
3043        }
3044
3045        inspect_sync_expect(
3046            "",
3047            None,
3048            &ExternallyTaggedEnum::B(true),
3049            expect!([r#"
3050                {
3051                    b: {
3052                        y: true,
3053                    },
3054                }"#]),
3055        );
3056
3057        inspect_sync_expect(
3058            "",
3059            None,
3060            &ExternallyTaggedEnum::C(5),
3061            expect!([r#"
3062            {
3063                c: 5,
3064            }"#]),
3065        );
3066
3067        #[expect(dead_code)]
3068        #[derive(Inspect)]
3069        #[inspect(untagged)]
3070        enum UntaggedEnum {
3071            A { x: u32 },
3072            B(#[inspect(rename = "y")] bool),
3073        }
3074
3075        inspect_sync_expect(
3076            "",
3077            None,
3078            &UntaggedEnum::B(true),
3079            expect!([r#"
3080            {
3081                y: true,
3082            }"#]),
3083        );
3084    }
3085
3086    #[test]
3087    fn test_derive_extra() {
3088        #[derive(Inspect)]
3089        #[inspect(extra = "Foo::inspect_extra")]
3090        struct Foo {
3091            x: u32,
3092            y: u32,
3093        }
3094
3095        impl Foo {
3096            fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
3097                resp.field("sum", self.x + self.y);
3098            }
3099        }
3100
3101        inspect_sync_expect(
3102            "",
3103            None,
3104            &Foo { x: 2, y: 5 },
3105            expect!([r#"
3106                {
3107                    sum: 7,
3108                    x: 2,
3109                    y: 5,
3110                }"#]),
3111        );
3112    }
3113
3114    #[test]
3115    fn test_derive_sensitivity() {
3116        #[derive(Inspect)]
3117        struct Foo {
3118            #[inspect(safe)]
3119            a: u32,
3120            b: u32,
3121            #[inspect(sensitive)]
3122            c: u32,
3123            #[inspect(safe)]
3124            d: Bar,
3125        }
3126        #[derive(Inspect)]
3127        struct Bar {
3128            #[inspect(sensitive)]
3129            a: u32,
3130            #[inspect(safe)]
3131            b: Baz,
3132        }
3133        #[derive(Inspect)]
3134        struct Baz {
3135            #[inspect(sensitive)]
3136            a: Qux,
3137            b: u32,
3138        }
3139        #[derive(Inspect)]
3140        struct Qux {
3141            #[inspect(safe)]
3142            a: u32,
3143        }
3144
3145        fn inspect_sync(
3146            path: &str,
3147            sensitivity: Option<SensitivityLevel>,
3148            obj: impl Inspect,
3149        ) -> Node {
3150            let mut result = InspectionBuilder::new(path)
3151                .sensitivity(sensitivity)
3152                .inspect(&obj);
3153            result.resolve().now_or_never();
3154            result.results()
3155        }
3156
3157        let obj = Foo {
3158            a: 0,
3159            b: 0,
3160            c: 0,
3161            d: Bar {
3162                a: 0,
3163                b: Baz {
3164                    a: Qux { a: 0 },
3165                    b: 0,
3166                },
3167            },
3168        };
3169
3170        expected_node(
3171            inspect_sync("", Some(SensitivityLevel::Safe), &obj),
3172            expect!([r#"
3173                {
3174                    a: 0,
3175                    d: {
3176                        b: {},
3177                    },
3178                }"#]),
3179        );
3180        expected_node(
3181            inspect_sync("", Some(SensitivityLevel::Unspecified), &obj),
3182            expect!([r#"
3183                {
3184                    a: 0,
3185                    b: 0,
3186                    d: {
3187                        b: {
3188                            b: 0,
3189                        },
3190                    },
3191                }"#]),
3192        );
3193        let node = expected_node(
3194            inspect_sync("", Some(SensitivityLevel::Sensitive), &obj),
3195            expect!([r#"
3196                {
3197                    a: 0,
3198                    b: 0,
3199                    c: 0,
3200                    d: {
3201                        a: 0,
3202                        b: {
3203                            a: {
3204                                a: 0,
3205                            },
3206                            b: 0,
3207                        },
3208                    },
3209                }"#]),
3210        );
3211        assert_eq!(
3212            node,
3213            inspect_sync("", Some(SensitivityLevel::Sensitive), &obj)
3214        );
3215    }
3216
3217    /// Test that you can update via AtomicMut.
3218    #[test]
3219    fn test_atomic_mut() {
3220        let mut v = core::sync::atomic::AtomicBool::new(false);
3221        let obj = AtomicMut(&v);
3222        update("", "true", &obj).now_or_never().unwrap().unwrap();
3223        assert!(*v.get_mut());
3224    }
3225}