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