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