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