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