Skip to main content

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