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