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
2075#[cfg(feature = "std")]
2076impl<T: Inspect + ?Sized> Inspect for parking_lot::Mutex<T> {
2077 fn inspect(&self, req: Request<'_>) {
2078 T::inspect(&*self.lock(), req)
2079 }
2080}
2081
2082#[cfg(feature = "std")]
2083impl<T: Inspect + ?Sized> Inspect for parking_lot::RwLock<T> {
2084 fn inspect(&self, req: Request<'_>) {
2085 T::inspect(&*self.read(), req)
2086 }
2087}
2088
2089#[cfg(feature = "std")]
2090impl<T: Inspect> Inspect for std::sync::OnceLock<T> {
2091 fn inspect(&self, req: Request<'_>) {
2092 <_ as Inspect>::inspect(&self.get(), req)
2093 }
2094}
2095
2096impl<T: Inspect> Inspect for Option<T> {
2097 fn inspect(&self, req: Request<'_>) {
2098 if let Some(val) = self {
2099 val.inspect(req);
2100 } else {
2101 req.ignore();
2102 }
2103 }
2104}
2105
2106impl<T: ?Sized + Inspect + ToOwned> Inspect for Cow<'_, T> {
2107 fn inspect(&self, req: Request<'_>) {
2108 self.as_ref().inspect(req)
2109 }
2110}
2111
2112impl<T> Inspect for *mut T {
2113 fn inspect(&self, req: Request<'_>) {
2114 req.with_hex_format().value(*self as usize)
2115 }
2116}
2117
2118impl<T> Inspect for *const T {
2119 fn inspect(&self, req: Request<'_>) {
2120 req.with_hex_format().value(*self as usize)
2121 }
2122}
2123
2124impl Inspect for ValueKind {
2125 fn inspect(&self, req: Request<'_>) {
2126 req.value(self.clone());
2127 }
2128}
2129
2130impl Inspect for Value {
2131 fn inspect(&self, req: Request<'_>) {
2132 let req = if self.flags.count() {
2133 req.with_counter_format()
2134 } else if self.flags.hex() {
2135 req.with_hex_format()
2136 } else if self.flags.binary() {
2137 req.with_binary_format()
2138 } else {
2139 req
2140 };
2141 req.value(self.kind.clone());
2142 }
2143}
2144impl<T: Inspect + ?Sized> Inspect for ManuallyDrop<T> {
2145 fn inspect(&self, req: Request<'_>) {
2146 self.deref().inspect(req);
2147 }
2148}
2149
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}