1#![no_std]
17
18extern crate alloc;
19
20#[cfg(any(feature = "std", feature = "initiate", feature = "defer",))]
26extern crate std;
27
28#[cfg(feature = "defer")]
29mod defer;
30#[cfg(feature = "initiate")]
31mod initiate;
32
33#[cfg(all(test, feature = "derive", feature = "initiate"))]
34extern crate self as inspect;
35
36#[cfg(feature = "defer")]
37pub use defer::*;
38#[cfg(feature = "initiate")]
39pub use initiate::*;
40
41#[cfg(feature = "derive")]
441pub use inspect_derive::Inspect;
442#[cfg(feature = "derive")]
446pub use inspect_derive::InspectMut;
447
448use alloc::borrow::Cow;
449use alloc::borrow::ToOwned;
450use alloc::boxed::Box;
451use alloc::format;
452use alloc::rc::Rc;
453use alloc::string::String;
454use alloc::string::ToString;
455use alloc::sync::Arc;
456use alloc::vec::Vec;
457use core::fmt;
458use core::fmt::Arguments;
459use core::fmt::Debug;
460use core::fmt::Display;
461use core::num::Wrapping;
462
463pub struct Request<'a> {
465 path: &'a str,
466 depth: usize,
467 node: &'a mut InternalNode,
468 value: Option<&'a str>,
469 sensitivity: SensitivityLevel,
470}
471
472#[cfg(any(feature = "defer", feature = "initiate"))]
473struct RequestRoot<'a> {
474 path: &'a str,
475 node: InternalNode,
476 depth: usize,
477 value: Option<&'a str>,
478 sensitivity: SensitivityLevel,
479}
480
481#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Default)]
486#[cfg_attr(
487 any(feature = "defer", feature = "initiate"),
488 derive(mesh::MeshPayload)
489)]
490#[cfg_attr(
491 any(feature = "defer", feature = "initiate"),
492 mesh(package = "inspect")
493)]
494#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
495pub enum SensitivityLevel {
496 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(1))]
498 Safe,
499 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(2))]
502 #[default]
503 Unspecified,
504 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(3))]
507 Sensitive,
508}
509
510#[cfg(any(feature = "defer", feature = "initiate"))]
511impl<'a> RequestRoot<'a> {
512 fn new(
513 path: &'a str,
514 depth: usize,
515 value: Option<&'a str>,
516 sensitivity: SensitivityLevel,
517 ) -> Self {
518 Self {
519 path,
520 node: InternalNode::Unevaluated,
521 depth,
522 value,
523 sensitivity,
524 }
525 }
526
527 fn request(&mut self) -> Request<'_> {
528 Request::new(
529 self.path,
530 self.depth,
531 &mut self.node,
532 self.value,
533 self.sensitivity,
534 )
535 }
536}
537
538pub struct Response<'a> {
540 path: &'a str,
542 path_without_slashes: Option<&'a str>,
544 depth: usize,
545 cell: &'a mut InternalNode,
546 value: Option<&'a str>,
547 sensitivity: SensitivityLevel,
548}
549
550#[derive(Debug)]
551enum Action<'a, 'b> {
552 Process {
553 name: &'a str,
554 sensitivity: SensitivityLevel,
555 new_path: &'b str,
556 new_depth: usize,
557 },
558 Skip,
559 DepthExhausted {
560 name: &'a str,
561 sensitivity: SensitivityLevel,
562 },
563}
564
565impl<'a, 'b> Action<'a, 'b> {
566 fn eval(child: Child<'a>, resp: &Response<'b>) -> Self {
569 let path = resp.path_without_slashes.unwrap();
570 if resp.depth == 0 {
571 return Self::Skip;
574 }
575 if resp.sensitivity < child.sensitivity {
576 return Self::Skip;
578 }
579 if let Some(rest) = path.strip_prefix(child.name) {
580 if rest.is_empty() || rest.as_bytes()[0] == b'/' {
581 Self::Process {
584 name: child.name,
585 sensitivity: child.sensitivity,
586 new_path: rest,
587 new_depth: resp.depth,
588 }
589 } else {
590 Self::Skip
593 }
594 } else if child.name.starts_with(path) {
595 let remaining_name = if path.is_empty() {
596 child.name
598 } else {
599 if child.name.as_bytes()[path.len()] != b'/' {
600 return Self::Skip;
602 }
603 &child.name[path.len() + 1..]
605 };
606 match remaining_name.match_indices('/').nth(resp.depth - 1) {
608 None => Self::Process {
609 name: child.name,
610 sensitivity: child.sensitivity,
611 new_path: "",
612 new_depth: resp.depth - 1,
613 },
614 Some((n, _)) => Self::DepthExhausted {
615 name: &child.name[..child.name.len() - remaining_name.len() + n],
616 sensitivity: child.sensitivity,
617 },
618 }
619 } else {
620 Self::Skip
621 }
622 }
623}
624
625struct Child<'a> {
626 name: &'a str,
627 sensitivity: SensitivityLevel,
628}
629
630impl Response<'_> {
631 pub fn field<T>(&mut self, name: &str, value: T) -> &mut Self
646 where
647 T: Inspect,
648 {
649 self.inspect_field(name, &value)
650 }
651
652 pub fn sensitivity_field<T>(
654 &mut self,
655 name: &str,
656 sensitivity: SensitivityLevel,
657 value: T,
658 ) -> &mut Self
659 where
660 T: Inspect,
661 {
662 self.sensitivity_inspect_field(name, sensitivity, &value)
663 }
664
665 pub fn hex<T>(&mut self, name: &str, value: T) -> &mut Self
669 where
670 T: Into<Value>,
671 {
672 self.field_with(name, || value.into().into_hex())
673 }
674
675 pub fn counter<T>(&mut self, name: &str, value: T) -> &mut Self
679 where
680 T: Into<Value>,
681 {
682 self.field_with(name, || value.into().into_counter())
683 }
684
685 pub fn sensitivity_counter<T>(
689 &mut self,
690 name: &str,
691 sensitivity: SensitivityLevel,
692 value: T,
693 ) -> &mut Self
694 where
695 T: Into<Value>,
696 {
697 self.sensitivity_field_with(name, sensitivity, || value.into().into_counter())
698 }
699
700 pub fn binary<T>(&mut self, name: &str, value: T) -> &mut Self
704 where
705 T: Into<Value>,
706 {
707 self.field_with(name, || value.into().into_binary())
708 }
709
710 pub fn display(&mut self, name: &str, value: &impl Display) -> &mut Self {
725 self.field_with(name, || value.to_string())
726 }
727
728 pub fn display_debug(&mut self, name: &str, value: &impl Debug) -> &mut Self {
738 self.field(name, format_args!("{value:?}"))
739 }
740
741 pub fn field_with<F, V>(&mut self, name: &str, f: F) -> &mut Self
743 where
744 F: FnOnce() -> V,
745 V: Inspect,
746 {
747 self.sensitivity_field_with(name, SensitivityLevel::Unspecified, f)
748 }
749
750 pub fn sensitivity_field_with<F, V>(
752 &mut self,
753 name: &str,
754 sensitivity: SensitivityLevel,
755 f: F,
756 ) -> &mut Self
757 where
758 F: FnOnce() -> V,
759 V: Inspect,
760 {
761 if let Some(req) = self.child_request(Child { name, sensitivity }) {
762 (f)().inspect(req)
763 }
764 self
765 }
766
767 pub fn field_mut<T>(&mut self, name: &str, value: &mut T) -> &mut Self
769 where
770 T: InspectMut + ?Sized,
771 {
772 self.inspect_field(name, value)
773 }
774
775 pub fn sensitivity_field_mut<T>(
777 &mut self,
778 name: &str,
779 sensitivity: SensitivityLevel,
780 value: &mut T,
781 ) -> &mut Self
782 where
783 T: InspectMut + ?Sized,
784 {
785 self.sensitivity_inspect_field(name, sensitivity, value)
786 }
787
788 pub fn field_mut_with<F, V, E>(&mut self, name: &str, f: F) -> &mut Self
790 where
791 F: FnOnce(Option<&str>) -> Result<V, E>,
792 V: Into<Value>,
793 E: Into<Box<dyn core::error::Error + Send + Sync>>,
794 {
795 self.child(name, |req| match req.update() {
796 Ok(req) => match (f)(Some(req.new_value())) {
797 Ok(v) => req.succeed(v.into()),
798 Err(err) => req.fail(err),
799 },
800 Err(req) => req.value((f)(None).ok().unwrap().into()),
801 })
802 }
803
804 fn child_request(&mut self, child: Child<'_>) -> Option<Request<'_>> {
805 if self.path_without_slashes.is_none() {
806 self.path_without_slashes = Some(self.path.trim_start_matches('/'));
807 }
808
809 match Action::eval(child, self) {
810 Action::Process {
811 name,
812 sensitivity,
813 new_path,
814 new_depth,
815 } => {
816 let children = self.cell.as_dir();
817 children.push(InternalEntry {
818 name: name.to_owned(),
819 node: InternalNode::Unevaluated,
820 sensitivity,
821 });
822 let entry = children.last_mut().unwrap();
823 Some(Request::new(
824 new_path,
825 new_depth,
826 &mut entry.node,
827 self.value,
828 self.sensitivity,
829 ))
830 }
831 Action::Skip => None,
832 Action::DepthExhausted { name, sensitivity } => {
833 self.cell.as_dir().push(InternalEntry {
834 name: name.to_owned(),
835 node: InternalNode::DepthExhausted,
836 sensitivity,
837 });
838 None
839 }
840 }
841 }
842
843 fn inspect_field(&mut self, name: &str, child: impl InspectMut) -> &mut Self {
845 self.sensitivity_inspect_field(name, SensitivityLevel::Unspecified, child)
846 }
847
848 #[inline(never)] fn sensitivity_inspect_field(
851 &mut self,
852 name: &str,
853 sensitivity: SensitivityLevel,
854 mut child: impl InspectMut,
855 ) -> &mut Self {
856 if let Some(req) = self.child_request(Child { name, sensitivity }) {
857 child.inspect_mut(req);
858 }
859 self
860 }
861
862 #[cfg_attr(
867 feature = "initiate",
868 doc = r##"
869```rust
870# use inspect::{inspect, Inspect, Request};
871# use core::time::Duration;
872
873struct Child(u32);
874impl Inspect for Child {
875 fn inspect(&self, req: Request) {
876 req.respond().field("x", self.0);
877 }
878}
879
880struct Parent(Vec<Child>);
881impl Inspect for Parent {
882 fn inspect(&self, req: Request) {
883 req.respond().fields("children", self.0.iter().enumerate());
884 }
885}
886
887assert_eq!(
888 inspect(
889 "",
890 &Parent(vec![Child(5), Child(12)]),
891 )
892 .results()
893 .to_string(),
894 r#"{children: {0: {x: 5}, 1: {x: 12}}}"#
895);
896```
897"##
898 )]
899 pub fn fields<I, N, C>(&mut self, name: &str, children: I) -> &mut Self
900 where
901 I: Iterator<Item = (N, C)>,
902 N: ToString,
903 C: Inspect,
904 {
905 self.child(name, |req| {
906 let mut resp = req.respond();
907 for (name, child) in children {
908 resp.inspect_field(&name.to_string(), &child);
909 }
910 })
911 }
912
913 #[cfg_attr(
918 feature = "initiate",
919 doc = r##"
920```rust
921# use inspect::{inspect, InspectMut, Request};
922# use std::time::Duration;
923struct Child(u32);
924impl InspectMut for Child {
925 fn inspect_mut(&mut self, req: Request) {
926 req.respond().field("x", self.0);
927 }
928}
929
930struct Parent(Vec<Child>);
931impl InspectMut for Parent {
932 fn inspect_mut(&mut self, req: Request) {
933 req.respond().fields_mut("children", self.0.iter_mut().enumerate());
934 }
935}
936
937assert_eq!(
938 inspect(
939 "",
940 &mut Parent(vec![Child(5), Child(12)]),
941 )
942 .results()
943 .to_string(),
944 r#"{children: {0: {x: 5}, 1: {x: 12}}}"#
945);
946```
947"##
948 )]
949 pub fn fields_mut<I, N, C>(&mut self, name: &str, children: I) -> &mut Self
950 where
951 I: Iterator<Item = (N, C)>,
952 N: ToString,
953 C: InspectMut,
954 {
955 self.child(name, |req| {
956 let mut resp = req.respond();
957 for (name, child) in children {
958 resp.inspect_field(&name.to_string(), child);
959 }
960 })
961 }
962
963 pub fn child<F: FnOnce(Request<'_>)>(&mut self, name: &str, f: F) -> &mut Self {
968 self.sensitivity_child(name, SensitivityLevel::Unspecified, f)
969 }
970
971 pub fn sensitivity_child<F: FnOnce(Request<'_>)>(
976 &mut self,
977 name: &str,
978 sensitivity: SensitivityLevel,
979 f: F,
980 ) -> &mut Self {
981 if let Some(req) = self.child_request(Child { name, sensitivity }) {
982 f(req);
983 }
984 self
985 }
986
987 pub fn merge(&mut self, mut child: impl InspectMut) -> &mut Self {
990 child.inspect_mut(self.request());
991 self
992 }
993
994 pub fn request(&mut self) -> Request<'_> {
997 let children = self.cell.as_dir();
998 children.push(InternalEntry {
999 name: String::new(),
1000 node: InternalNode::Unevaluated,
1001 sensitivity: SensitivityLevel::Unspecified,
1002 });
1003 let entry = children.last_mut().unwrap();
1004 Request::new(
1005 self.path,
1006 self.depth,
1007 &mut entry.node,
1008 self.value,
1009 self.sensitivity,
1010 )
1011 }
1012}
1013
1014impl Drop for Response<'_> {
1015 fn drop(&mut self) {
1016 if self.depth > 0 {
1017 let _ = self.cell.as_dir();
1019 } else {
1020 *self.cell = InternalNode::DepthExhausted;
1023 }
1024 }
1025}
1026
1027impl<'a> Request<'a> {
1028 fn new(
1029 path: &'a str,
1030 depth: usize,
1031 cell: &'a mut InternalNode,
1032 value: Option<&'a str>,
1033 sensitivity: SensitivityLevel,
1034 ) -> Self {
1035 Self {
1036 path,
1037 depth,
1038 node: cell,
1039 value,
1040 sensitivity,
1041 }
1042 }
1043
1044 pub fn value(self, value: Value) {
1046 let node = if self.path.is_empty() {
1047 if self.value.is_none() {
1048 InternalNode::Value(value)
1049 } else {
1050 InternalNode::Failed(InternalError::Immutable)
1051 }
1052 } else {
1053 InternalNode::Failed(InternalError::NotADirectory)
1054 };
1055 *self.node = node;
1056 }
1057
1058 pub fn update(self) -> Result<UpdateRequest<'a>, Self> {
1062 if let Some(value) = self.value {
1063 if !self.path.is_empty() {
1064 return Err(self);
1065 }
1066 Ok(UpdateRequest {
1067 node: self.node,
1068 value,
1069 })
1070 } else {
1071 Err(self)
1072 }
1073 }
1074
1075 pub fn respond(self) -> Response<'a> {
1079 Response {
1080 path: self.path,
1081 path_without_slashes: None,
1082 depth: self.depth,
1083 cell: self.node,
1084 value: self.value,
1085 sensitivity: self.sensitivity,
1086 }
1087 }
1088
1089 pub fn ignore(self) {
1091 *self.node = InternalNode::Ignored;
1092 }
1093
1094 pub fn is_update(&self) -> bool {
1096 self.value.is_some()
1097 }
1098
1099 pub fn sensitivity(&self) -> SensitivityLevel {
1101 self.sensitivity
1102 }
1103}
1104
1105pub struct UpdateRequest<'a> {
1107 node: &'a mut InternalNode,
1108 value: &'a str,
1109}
1110
1111impl UpdateRequest<'_> {
1112 pub fn new_value(&self) -> &str {
1114 self.value
1115 }
1116
1117 pub fn succeed(self, value: Value) {
1119 *self.node = InternalNode::Value(value);
1120 }
1121
1122 pub fn fail<E: Into<Box<dyn core::error::Error + Send + Sync>>>(self, err: E) {
1124 *self.node = InternalNode::failed(err.into());
1125 }
1126}
1127
1128#[derive(Debug, Clone, PartialEq)]
1131#[cfg_attr(
1132 any(feature = "defer", feature = "initiate"),
1133 derive(mesh::MeshPayload),
1134 mesh(package = "inspect")
1135)]
1136#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1137pub struct Value {
1138 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(1))]
1140 pub kind: ValueKind,
1141 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(2))]
1143 pub flags: ValueFlags,
1144}
1145
1146impl Value {
1147 pub fn new(kind: impl Into<ValueKind>) -> Self {
1149 Self {
1150 kind: kind.into(),
1151 flags: Default::default(),
1152 }
1153 }
1154
1155 pub fn hex(kind: impl Into<ValueKind>) -> Self {
1157 Self::new(kind).into_hex()
1158 }
1159
1160 pub fn counter(kind: impl Into<ValueKind>) -> Self {
1162 Self::new(kind).into_counter()
1163 }
1164
1165 pub fn binary(kind: impl Into<ValueKind>) -> Self {
1167 Self::new(kind).into_binary()
1168 }
1169
1170 pub fn into_hex(self) -> Self {
1172 Self {
1173 kind: self.kind,
1174 flags: self.flags.with_hex(true),
1175 }
1176 }
1177
1178 pub fn into_counter(self) -> Self {
1180 Self {
1181 kind: self.kind,
1182 flags: self.flags.with_count(true),
1183 }
1184 }
1185
1186 pub fn into_binary(self) -> Self {
1188 Self {
1189 kind: self.kind,
1190 flags: self.flags.with_binary(true),
1191 }
1192 }
1193}
1194
1195#[derive(Debug, Clone, PartialEq)]
1197#[cfg_attr(
1198 any(feature = "defer", feature = "initiate"),
1199 derive(mesh::MeshPayload),
1200 mesh(package = "inspect")
1201)]
1202#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1203pub enum ValueKind {
1204 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(1))]
1206 Signed(i64),
1207 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(2))]
1209 Unsigned(u64),
1210 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(3))]
1212 Float(f32),
1213 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(4))]
1215 Double(f64),
1216 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(5))]
1218 Bool(bool),
1219 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(6))]
1221 String(String),
1222 #[cfg_attr(any(feature = "defer", feature = "initiate"), mesh(7))]
1224 Bytes(Vec<u8>),
1225}
1226
1227#[bitfield_struct::bitfield(u64)]
1229#[derive(PartialEq)]
1230#[cfg_attr(
1231 any(feature = "defer", feature = "initiate"),
1232 derive(mesh::MeshPayload),
1233 mesh(package = "inspect")
1234)]
1235#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1236pub struct ValueFlags {
1237 pub hex: bool,
1239 pub count: bool,
1241 pub binary: bool,
1243
1244 #[bits(61)]
1245 _reserved: u64,
1246}
1247
1248impl Display for Value {
1249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1250 match &self.kind {
1251 ValueKind::Signed(n) => {
1252 if self.flags.hex() {
1253 write!(f, "{:#x}", &n)
1254 } else if self.flags.binary() {
1255 write!(f, "{:#b}", &n)
1256 } else {
1257 Display::fmt(&n, f)
1258 }
1259 }
1260 ValueKind::Unsigned(n) => {
1261 if self.flags.hex() {
1262 write!(f, "{:#x}", &n)
1263 } else if self.flags.binary() {
1264 write!(f, "{:#b}", &n)
1265 } else {
1266 Display::fmt(&n, f)
1267 }
1268 }
1269 ValueKind::Float(n) => Display::fmt(&n, f),
1270 ValueKind::Double(n) => Display::fmt(&n, f),
1271 ValueKind::Bool(b) => Display::fmt(&b, f),
1272 ValueKind::String(s) => Debug::fmt(&s, f),
1273 ValueKind::Bytes(b) => {
1274 f.write_str("<")?;
1275 for &b in b {
1276 write!(f, "{:02x}", b)?;
1277 }
1278 f.write_str(">")
1279 }
1280 }
1281 }
1282}
1283
1284impl<T> From<T> for Value
1285where
1286 ValueKind: From<T>,
1287{
1288 fn from(v: T) -> Self {
1289 Value {
1290 kind: v.into(),
1291 flags: Default::default(),
1292 }
1293 }
1294}
1295
1296macro_rules! from_as {
1297 ($x:ident, $to:ty, $($ty:ty),* $(,)?) => {
1298 $(
1299 impl From<$ty> for ValueKind {
1300 fn from(v: $ty) -> Self {
1301 Self::$x(v as $to)
1302 }
1303 }
1304 )*
1305 };
1306}
1307
1308from_as!(Unsigned, u64, u8, u16, u32, u64, usize);
1309from_as!(Signed, i64, i8, i16, i32, i64, isize);
1310
1311macro_rules! from_get {
1312 ($x:ident, $to:ty, $($ty:ty),* $(,)?) => {
1313 $(
1314 impl From<$ty> for ValueKind {
1315 fn from(v: $ty) -> Self {
1316 Self::$x(v.get() as $to)
1317 }
1318 }
1319 )*
1320 };
1321}
1322
1323from_get!(
1324 Unsigned,
1325 u64,
1326 core::num::NonZeroU8,
1327 core::num::NonZeroU16,
1328 core::num::NonZeroU32,
1329 core::num::NonZeroU64,
1330 core::num::NonZeroUsize
1331);
1332from_get!(
1333 Signed,
1334 i64,
1335 core::num::NonZeroI8,
1336 core::num::NonZeroI16,
1337 core::num::NonZeroI32,
1338 core::num::NonZeroI64,
1339 core::num::NonZeroIsize
1340);
1341
1342impl From<f32> for ValueKind {
1343 fn from(v: f32) -> Self {
1344 Self::Float(v)
1345 }
1346}
1347
1348impl From<f64> for ValueKind {
1349 fn from(v: f64) -> Self {
1350 Self::Double(v)
1351 }
1352}
1353
1354impl From<bool> for ValueKind {
1355 fn from(v: bool) -> Self {
1356 Self::Bool(v)
1357 }
1358}
1359
1360impl From<&'_ str> for ValueKind {
1361 fn from(v: &str) -> Self {
1362 Self::String(v.to_owned())
1363 }
1364}
1365
1366impl From<String> for ValueKind {
1367 fn from(v: String) -> Self {
1368 Self::String(v)
1369 }
1370}
1371
1372#[cfg(feature = "std")]
1373impl From<&'_ std::ffi::CStr> for ValueKind {
1374 fn from(v: &std::ffi::CStr) -> Self {
1375 Self::String(v.to_string_lossy().to_string())
1376 }
1377}
1378
1379#[cfg(feature = "std")]
1380impl From<std::ffi::CString> for ValueKind {
1381 fn from(v: std::ffi::CString) -> Self {
1382 Self::String(v.to_string_lossy().to_string())
1383 }
1384}
1385
1386impl From<&'_ [u8]> for ValueKind {
1387 fn from(v: &[u8]) -> Self {
1388 Self::Bytes(v.to_vec())
1389 }
1390}
1391
1392impl<const N: usize> From<[u8; N]> for ValueKind {
1393 fn from(v: [u8; N]) -> Self {
1394 Self::Bytes(v.to_vec())
1395 }
1396}
1397
1398impl From<Vec<u8>> for ValueKind {
1399 fn from(v: Vec<u8>) -> Self {
1400 Self::Bytes(v)
1401 }
1402}
1403
1404impl From<Arguments<'_>> for ValueKind {
1405 fn from(v: Arguments<'_>) -> Self {
1406 Self::String(v.to_string())
1407 }
1408}
1409
1410impl<T: Into<ValueKind> + Clone> From<&'_ T> for ValueKind {
1411 fn from(v: &T) -> Self {
1412 v.clone().into()
1413 }
1414}
1415
1416impl Inspect for () {
1417 fn inspect(&self, req: Request<'_>) {
1418 req.respond();
1419 }
1420}
1421
1422impl InspectMut for () {
1423 fn inspect_mut(&mut self, req: Request<'_>) {
1424 req.respond();
1425 }
1426}
1427
1428macro_rules! inspect_value_immut {
1429 ($($(#[$attr:meta])* $ty:ty),* $(,)?) => {
1430 $(
1431 $(#[$attr])*
1432 impl Inspect for $ty {
1433 fn inspect(&self, req: Request<'_>) {
1434 req.value(self.into())
1435 }
1436 }
1437 )*
1438 };
1439}
1440
1441macro_rules! inspect_value {
1442 ($($(#[$attr:meta])* $ty:ty),* $(,)?) => {
1443 inspect_value_immut!($($ty,)*);
1444 $(
1445 $(#[$attr])*
1446 impl InspectMut for $ty {
1447 fn inspect_mut(&mut self, req: Request<'_>) {
1448 match req.update() {
1449 Ok(req) => match req.new_value().parse::<Self>() {
1450 Ok(v) => {
1451 *self = v.clone();
1452 req.succeed(v.into());
1453 }
1454 Err(err) => req.fail(err),
1455 }
1456 Err(req) => req.value((&*self).into()),
1457 }
1458 }
1459 }
1460 )*
1461 };
1462}
1463
1464inspect_value_immut! {
1465 str,
1466 #[cfg(feature = "std")]
1467 std::ffi::CStr,
1468 #[cfg(feature = "std")]
1469 std::ffi::CString,
1470 [u8],
1471 Vec<u8>,
1472 Arguments<'_>,
1473}
1474
1475inspect_value! {
1476 u8,
1477 u16,
1478 u32,
1479 u64,
1480 usize,
1481 i8,
1482 i16,
1483 i32,
1484 i64,
1485 isize,
1486 core::num::NonZeroU8,
1487 core::num::NonZeroU16,
1488 core::num::NonZeroU32,
1489 core::num::NonZeroU64,
1490 core::num::NonZeroUsize,
1491 core::num::NonZeroI8,
1492 core::num::NonZeroI16,
1493 core::num::NonZeroI32,
1494 core::num::NonZeroI64,
1495 core::num::NonZeroIsize,
1496 f32,
1497 f64,
1498 bool,
1499 String,
1500}
1501
1502impl<const N: usize> Inspect for [u8; N] {
1503 fn inspect(&self, req: Request<'_>) {
1504 self.as_slice().inspect(req)
1505 }
1506}
1507
1508pub struct AtomicMut<T>(pub T);
1511
1512macro_rules! inspect_atomic_value {
1513 ($(($ty:ident, $backing:ty)),* $(,)?) => {
1514 $(
1515
1516 impl Inspect for core::sync::atomic::$ty {
1517 fn inspect(&self, req: Request<'_>) {
1518 req.value(self.load(core::sync::atomic::Ordering::Relaxed).into())
1519 }
1520 }
1521
1522 impl Inspect for AtomicMut<&core::sync::atomic::$ty> {
1527 fn inspect(&self, req: Request<'_>) {
1528 let mut value = self.0.load(core::sync::atomic::Ordering::Relaxed);
1529 let is_update = req.is_update();
1530 value.inspect_mut(req);
1531 if is_update {
1532 self.0.store(value, core::sync::atomic::Ordering::Relaxed);
1533 }
1534 }
1535 }
1536
1537 )*
1538 };
1539}
1540
1541inspect_atomic_value! {
1542 (AtomicBool, bool),
1543 (AtomicU8, u8),
1544 (AtomicU16, u16),
1545 (AtomicU32, u32),
1546 (AtomicU64, u64),
1547 (AtomicUsize, usize),
1548 (AtomicI8, i8),
1549 (AtomicI16, i16),
1550 (AtomicI32, i32),
1551 (AtomicI64, i64),
1552 (AtomicIsize, isize),
1553}
1554
1555impl<T: Inspect> Inspect for Wrapping<T> {
1556 fn inspect(&self, req: Request<'_>) {
1557 self.0.inspect(req)
1558 }
1559}
1560
1561impl<T: InspectMut> InspectMut for Wrapping<T> {
1562 fn inspect_mut(&mut self, req: Request<'_>) {
1563 self.0.inspect_mut(req)
1564 }
1565}
1566
1567#[cfg(feature = "filepath")]
1568impl Inspect for std::fs::File {
1569 fn inspect(&self, req: Request<'_>) {
1570 use filepath::FilePath;
1571 if let Ok(path) = self.path() {
1572 req.value(path.display().to_string().into());
1573 } else {
1574 req.ignore();
1575 }
1576 }
1577}
1578
1579pub struct AsDisplay<T>(pub T);
1582
1583impl<T: Display> Inspect for AsDisplay<T> {
1584 fn inspect(&self, req: Request<'_>) {
1585 req.value(self.0.to_string().into())
1586 }
1587}
1588
1589pub struct AsDebug<T>(pub T);
1592
1593impl<T: Debug> InspectMut for AsDebug<T> {
1594 fn inspect_mut(&mut self, req: Request<'_>) {
1595 req.value(format!("{:?}", self.0).into())
1596 }
1597}
1598
1599impl<T: Debug> Inspect for AsDebug<T> {
1600 fn inspect(&self, req: Request<'_>) {
1601 req.value(format!("{:?}", self.0).into())
1602 }
1603}
1604
1605macro_rules! hexbincount {
1606 ($tr:ident, $method:ident, $($ty:ty),* $(,)?) => {
1607 $(
1608 impl Inspect for $tr<$ty> {
1609 fn inspect(&self, req: Request<'_>) {
1610 req.value(Value::from(self.0).$method());
1611 }
1612 }
1613 )*
1614 };
1615}
1616
1617#[derive(Clone, Copy)]
1620pub struct AsHex<T>(pub T);
1621
1622hexbincount!(AsHex, into_hex, u8, u16, u32, u64, usize);
1623
1624impl<T> Inspect for AsHex<Wrapping<T>>
1625where
1626 for<'a> AsHex<&'a T>: Inspect,
1627{
1628 fn inspect(&self, req: Request<'_>) {
1629 Inspect::inspect(&AsHex(&self.0.0), req)
1630 }
1631}
1632
1633impl<T: Clone> Inspect for AsHex<&'_ T>
1634where
1635 AsHex<T>: Inspect,
1636{
1637 fn inspect(&self, req: Request<'_>) {
1638 Inspect::inspect(&AsHex(self.0.clone()), req)
1639 }
1640}
1641
1642impl<T> Inspect for AsHex<Option<T>>
1643where
1644 for<'a> AsHex<&'a T>: Inspect,
1645{
1646 fn inspect(&self, req: Request<'_>) {
1647 Inspect::inspect(&self.0.as_ref().map(AsHex), req);
1648 }
1649}
1650
1651pub struct AsBinary<T>(pub T);
1654
1655hexbincount!(AsBinary, into_binary, u8, u16, u32, u64, usize);
1656
1657impl<T: Clone> Inspect for AsBinary<&'_ T>
1658where
1659 AsBinary<T>: Inspect,
1660{
1661 fn inspect(&self, req: Request<'_>) {
1662 Inspect::inspect(&AsBinary(self.0.clone()), req)
1663 }
1664}
1665
1666impl<T> Inspect for AsBinary<Option<T>>
1667where
1668 for<'a> AsBinary<&'a T>: Inspect,
1669{
1670 fn inspect(&self, req: Request<'_>) {
1671 Inspect::inspect(&self.0.as_ref().map(AsBinary), req);
1672 }
1673}
1674
1675pub struct AsCounter<T>(pub T);
1678
1679hexbincount!(AsCounter, into_counter, u8, u16, u32, u64, usize);
1680
1681impl<T: Clone> Inspect for AsCounter<&'_ T>
1682where
1683 AsCounter<T>: Inspect,
1684{
1685 fn inspect(&self, req: Request<'_>) {
1686 Inspect::inspect(&AsCounter(self.0.clone()), req)
1687 }
1688}
1689
1690pub struct AsBytes<T>(pub T);
1695
1696impl<T> Inspect for AsBytes<T>
1697where
1698 T: Clone + IntoIterator,
1699 Vec<u8>: Extend<T::Item>,
1700{
1701 fn inspect(&self, req: Request<'_>) {
1702 let mut v = Vec::new();
1703 v.extend(self.0.clone());
1704 req.value(ValueKind::Bytes(v).into())
1705 }
1706}
1707
1708#[doc(hidden)]
1709pub mod derive_helpers {
1710 pub fn call<T, F, R>(t: T, f: F) -> R
1712 where
1713 F: Fn(T) -> R,
1714 {
1715 f(t)
1716 }
1717}
1718
1719#[derive(Default)]
1727pub struct Iterated<I>(I);
1728
1729pub fn iter_by_key<I, K, V>(iter: impl IntoIterator<IntoIter = I>) -> Iterated<I>
1742where
1743 I: Clone + Iterator<Item = (K, V)>,
1744{
1745 Iterated(iter.into_iter())
1746}
1747
1748pub fn iter_by_index<I, V>(
1761 iter: impl IntoIterator<IntoIter = I>,
1762) -> Iterated<core::iter::Enumerate<I>>
1763where
1764 I: Clone + Iterator<Item = V>,
1765{
1766 iter_by_key(iter.into_iter().enumerate())
1767}
1768
1769impl<I, K, V> Iterated<I>
1770where
1771 I: Clone + Iterator<Item = (K, V)>,
1772{
1773 pub fn map_key<F, K2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K2, V)>>
1785 where
1786 F: Clone + FnMut(K) -> K2,
1787 {
1788 iter_by_key(self.0.map(move |(k, v)| (f(k), v)))
1789 }
1790
1791 pub fn map_value<F, V2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K, V2)>>
1803 where
1804 F: Clone + FnMut(V) -> V2,
1805 {
1806 iter_by_key(self.0.map(move |(k, v)| (k, f(v))))
1807 }
1808
1809 pub fn prefix<'a>(
1821 self,
1822 prefix: &'a str,
1823 ) -> Iterated<impl 'a + Clone + Iterator<Item = (String, V)>>
1824 where
1825 K: Display,
1826 I: 'a,
1827 K: 'a,
1828 V: 'a,
1829 {
1830 self.map_key(move |k| format!("{}{}", prefix, k))
1831 }
1832}
1833
1834impl<I, K, V> Inspect for Iterated<I>
1835where
1836 I: Clone + Iterator<Item = (K, V)>,
1837 K: ToString,
1838 V: Inspect,
1839{
1840 fn inspect(&self, req: Request<'_>) {
1841 let mut resp = req.respond();
1842 for (name, value) in self.0.clone() {
1843 resp.field(&name.to_string(), value);
1844 }
1845 }
1846}
1847
1848#[derive(Debug)]
1849#[cfg_attr(
1850 any(feature = "defer", feature = "initiate"),
1851 derive(mesh::MeshPayload)
1852)]
1853#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1854enum InternalNode {
1855 Unevaluated,
1856 Failed(InternalError),
1857 DepthExhausted,
1858 Value(Value),
1859 Dir(Vec<InternalEntry>),
1860 Ignored,
1861 #[cfg(any(feature = "defer", feature = "initiate"))]
1862 Deferred(mesh::OneshotReceiver<InternalNode>),
1863 #[cfg(any(feature = "defer", feature = "initiate"))]
1864 DirResolved(Vec<InternalEntry>),
1865}
1866
1867#[derive(Debug)]
1868#[cfg_attr(
1869 any(feature = "defer", feature = "initiate"),
1870 derive(mesh::MeshPayload)
1871)]
1872#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1875struct InternalEntry {
1876 name: String,
1877 node: InternalNode,
1878 sensitivity: SensitivityLevel,
1879}
1880
1881impl InternalNode {
1882 fn as_dir(&mut self) -> &mut Vec<InternalEntry> {
1883 match self {
1884 Self::Dir(children) => children,
1885 _ => {
1886 *self = Self::Dir(Vec::new());
1887 let Self::Dir(children) = self else {
1888 unreachable!()
1889 };
1890 children
1891 }
1892 }
1893 }
1894}
1895
1896#[derive(Debug)]
1897#[cfg_attr(
1898 any(feature = "defer", feature = "initiate"),
1899 derive(mesh::MeshPayload)
1900)]
1901#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1902enum InternalError {
1903 Immutable,
1904 Update(String),
1905 NotADirectory,
1906 Unresolved,
1907 Mesh(String),
1908}
1909
1910impl InternalNode {
1911 fn failed(err: Box<dyn core::error::Error + Send + Sync>) -> Self {
1912 use core::fmt::Write;
1913
1914 let mut s = err.to_string();
1915 let mut src = err.source();
1916 while let Some(err) = src {
1917 src = err.source();
1918 let _ = write!(&mut s, ": {err}");
1919 }
1920 InternalNode::Failed(InternalError::Update(s))
1921 }
1922}
1923
1924pub trait InspectMut {
1929 fn inspect_mut(&mut self, req: Request<'_>);
1931}
1932
1933impl<T: Inspect + ?Sized> InspectMut for &'_ T {
1934 fn inspect_mut(&mut self, req: Request<'_>) {
1935 self.inspect(req);
1936 }
1937}
1938
1939impl<T: InspectMut + ?Sized> InspectMut for &'_ mut T {
1940 fn inspect_mut(&mut self, req: Request<'_>) {
1941 T::inspect_mut(*self, req)
1942 }
1943}
1944
1945impl<T: InspectMut + ?Sized> InspectMut for Box<T> {
1946 fn inspect_mut(&mut self, req: Request<'_>) {
1947 T::inspect_mut(self.as_mut(), req)
1948 }
1949}
1950
1951impl<T: InspectMut> InspectMut for Option<T> {
1952 fn inspect_mut(&mut self, req: Request<'_>) {
1953 if let Some(val) = self {
1954 val.inspect_mut(req);
1955 } else {
1956 req.ignore();
1957 }
1958 }
1959}
1960
1961pub trait Inspect {
2032 fn inspect(&self, req: Request<'_>);
2034}
2035
2036impl<T: Inspect + ?Sized> Inspect for &'_ T {
2037 fn inspect(&self, req: Request<'_>) {
2038 T::inspect(*self, req)
2039 }
2040}
2041
2042impl<T: Inspect + ?Sized> Inspect for &'_ mut T {
2043 fn inspect(&self, req: Request<'_>) {
2044 T::inspect(*self, req)
2045 }
2046}
2047
2048impl<T: Inspect + ?Sized> Inspect for Box<T> {
2049 fn inspect(&self, req: Request<'_>) {
2050 T::inspect(self.as_ref(), req)
2051 }
2052}
2053
2054impl<T: Inspect + ?Sized> Inspect for Rc<T> {
2055 fn inspect(&self, req: Request<'_>) {
2056 T::inspect(self.as_ref(), req)
2057 }
2058}
2059
2060impl<T: Inspect + ?Sized> Inspect for Arc<T> {
2061 fn inspect(&self, req: Request<'_>) {
2062 T::inspect(self.as_ref(), req)
2063 }
2064}
2065
2066impl<T: Inspect + ?Sized> Inspect for parking_lot::Mutex<T> {
2067 fn inspect(&self, req: Request<'_>) {
2068 T::inspect(&*self.lock(), req)
2069 }
2070}
2071
2072impl<T: Inspect + ?Sized> Inspect for parking_lot::RwLock<T> {
2073 fn inspect(&self, req: Request<'_>) {
2074 T::inspect(&*self.read(), req)
2075 }
2076}
2077
2078#[cfg(feature = "std")]
2079impl<T: Inspect> Inspect for std::sync::OnceLock<T> {
2080 fn inspect(&self, req: Request<'_>) {
2081 <_ as Inspect>::inspect(&self.get(), req)
2082 }
2083}
2084
2085impl<T: Inspect> Inspect for Option<T> {
2086 fn inspect(&self, req: Request<'_>) {
2087 if let Some(val) = self {
2088 val.inspect(req);
2089 } else {
2090 req.ignore();
2091 }
2092 }
2093}
2094
2095impl<T: ?Sized + Inspect + ToOwned> Inspect for Cow<'_, T> {
2096 fn inspect(&self, req: Request<'_>) {
2097 self.as_ref().inspect(req)
2098 }
2099}
2100
2101impl<T> Inspect for *mut T {
2102 fn inspect(&self, req: Request<'_>) {
2103 req.value(Value::hex(*self as usize))
2104 }
2105}
2106
2107impl<T> Inspect for *const T {
2108 fn inspect(&self, req: Request<'_>) {
2109 req.value(Value::hex(*self as usize))
2110 }
2111}
2112
2113impl Inspect for Value {
2114 fn inspect(&self, req: Request<'_>) {
2115 req.value(self.clone());
2116 }
2117}
2118
2119pub struct Adhoc<F>(F);
2121
2122impl<F> InspectMut for Adhoc<F>
2123where
2124 F: FnMut(Request<'_>),
2125{
2126 fn inspect_mut(&mut self, req: Request<'_>) {
2127 (self.0)(req)
2128 }
2129}
2130
2131impl<F> Inspect for Adhoc<F>
2132where
2133 F: Fn(Request<'_>),
2134{
2135 fn inspect(&self, req: Request<'_>) {
2136 (self.0)(req)
2137 }
2138}
2139
2140pub fn adhoc<F>(f: F) -> Adhoc<F>
2143where
2144 F: Fn(Request<'_>),
2145{
2146 Adhoc(f)
2147}
2148
2149pub fn adhoc_mut<F>(f: F) -> Adhoc<F>
2152where
2153 F: FnMut(Request<'_>),
2154{
2155 Adhoc(f)
2156}
2157
2158#[cfg(all(test, feature = "derive", feature = "initiate"))]
2159mod tests {
2160 use crate::AsBytes;
2161 use crate::AtomicMut;
2162 use crate::Error;
2163 use crate::Inspect;
2164 use crate::InspectMut;
2165 use crate::InspectionBuilder;
2166 use crate::Node;
2167 use crate::Request;
2168 use crate::SensitivityLevel;
2169 use crate::ValueKind;
2170 use crate::adhoc;
2171 use crate::adhoc_mut;
2172 use crate::inspect;
2173 use crate::update;
2174 use alloc::boxed::Box;
2175 use alloc::string::String;
2176 use alloc::string::ToString;
2177 use alloc::vec;
2178 use alloc::vec::Vec;
2179 use core::time::Duration;
2180 use expect_test::Expect;
2181 use expect_test::expect;
2182 use futures::FutureExt;
2183 use pal_async::DefaultDriver;
2184 use pal_async::async_test;
2185 use pal_async::timer::Instant;
2186 use pal_async::timer::PolledTimer;
2187
2188 fn expected_node(node: Node, expect: Expect) -> Node {
2189 expect.assert_eq(&node.to_string());
2190 node
2191 }
2192
2193 async fn inspect_async(
2194 driver: &DefaultDriver,
2195 path: &str,
2196 depth: Option<usize>,
2197 timeout: Duration,
2198 obj: impl InspectMut,
2199 ) -> Node {
2200 let deadline = Instant::now() + timeout;
2201 let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2202 let mut timer = PolledTimer::new(driver);
2203 futures::select! { _ = result.resolve().fuse() => {}
2205 _ = timer.sleep_until(deadline).fuse() => {}
2206 };
2207 result.results()
2208 }
2209
2210 async fn inspect_async_expect(
2211 driver: &DefaultDriver,
2212 path: &str,
2213 depth: Option<usize>,
2214 timeout: Duration,
2215 obj: impl InspectMut,
2216 expect: Expect,
2217 ) -> Node {
2218 expected_node(
2219 inspect_async(driver, path, depth, timeout, obj).await,
2220 expect,
2221 )
2222 }
2223
2224 fn inspect_sync(path: &str, depth: Option<usize>, obj: impl InspectMut) -> Node {
2225 let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2226 result.resolve().now_or_never();
2227 result.results()
2228 }
2229
2230 fn inspect_sync_expect(
2231 path: &str,
2232 depth: Option<usize>,
2233 obj: impl InspectMut,
2234 expect: Expect,
2235 ) -> Node {
2236 expected_node(inspect_sync(path, depth, obj), expect)
2237 }
2238
2239 #[derive(Default)]
2240 struct Foo {
2241 xx: u32,
2242 xy: bool,
2243 xz: Vec<Foo>,
2244 }
2245
2246 impl Inspect for Foo {
2247 fn inspect(&self, req: Request<'_>) {
2248 let mut resp = req.respond();
2249 resp.field("xx", self.xx)
2250 .field("xy", self.xy)
2251 .fields("", self.xz.iter().enumerate());
2252 }
2253 }
2254
2255 #[test]
2256 fn test() {
2257 let f = Foo {
2258 xx: 1,
2259 xy: true,
2260 xz: vec![
2261 Foo {
2262 xx: 3,
2263 xy: false,
2264 xz: vec![],
2265 },
2266 Foo {
2267 xx: 5,
2268 xy: true,
2269 xz: vec![],
2270 },
2271 ],
2272 };
2273 let node = inspect_sync_expect(
2274 "",
2275 None,
2276 &f,
2277 expect!("{0: {xx: 3, xy: false}, 1: {xx: 5, xy: true}, xx: 1, xy: true}"),
2278 );
2279 let expected_json =
2280 expect!([r#"{"0":{"xx":3,"xy":false},"1":{"xx":5,"xy":true},"xx":1,"xy":true}"#]);
2281 expected_json.assert_eq(&node.json().to_string());
2282 }
2283
2284 #[async_test]
2285 async fn test_deferred(driver: DefaultDriver) {
2286 inspect_async_expect(
2287 &driver,
2288 "",
2289 None,
2290 Duration::from_secs(1),
2291 adhoc(|req| {
2292 let foo = req.defer();
2293 std::thread::spawn(|| foo.inspect(&Foo::default()));
2294 }),
2295 expect!("{xx: 0, xy: false}"),
2296 )
2297 .await;
2298 }
2299
2300 #[async_test]
2301 async fn test_dropped(driver: DefaultDriver) {
2302 inspect_async_expect(
2303 &driver,
2304 "",
2305 None,
2306 Duration::from_secs(86400),
2307 adhoc(|req| {
2308 drop(req.defer());
2309 }),
2310 expect!("error (unresolved)"),
2311 )
2312 .await;
2313 }
2314
2315 #[test]
2316 fn test_path() {
2317 let mut obj = adhoc(|req| {
2318 req.respond().field("a", 1).child("b", |req| {
2319 req.respond().field("c", 2).field("d", 2).child("e", |req| {
2320 req.respond();
2321 });
2322 });
2323 });
2324 inspect_sync_expect("a", None, &mut obj, expect!("1"));
2325 inspect_sync_expect("///a", None, &mut obj, expect!("1"));
2326 inspect_sync_expect("b", None, &mut obj, expect!("{c: 2, d: 2, e: {}}"));
2327 inspect_sync_expect("b/c", None, &mut obj, expect!("2"));
2328 inspect_sync_expect("b////c", None, &mut obj, expect!("2"));
2329 inspect_sync_expect("b/c/", None, &mut obj, expect!("error (not a directory)"));
2330 inspect_sync_expect("b/c/x", None, &mut obj, expect!("error (not a directory)"));
2331 inspect_sync_expect("b/e", None, &mut obj, expect!("{}"));
2332 inspect_sync_expect("b/e/", None, &mut obj, expect!("{}"));
2333 inspect_sync_expect("b/e///", None, &mut obj, expect!("{}"));
2334 inspect_sync_expect("b/f", None, &mut obj, expect!("error (not found)"));
2335 }
2336
2337 #[async_test]
2338 async fn test_timeout(driver: DefaultDriver) {
2339 inspect_async_expect(
2340 &driver,
2341 "",
2342 None,
2343 Duration::from_millis(10),
2344 adhoc(|req| {
2345 let foo = req.defer();
2346 std::thread::spawn(|| {
2347 std::thread::sleep(Duration::from_millis(250));
2348 foo.inspect(&Foo::default())
2349 });
2350 }),
2351 expect!("error (unresolved)"),
2352 )
2353 .await;
2354 }
2355
2356 #[test]
2357 fn test_merge() {
2358 let mut obj = adhoc(|req| {
2359 req.respond()
2360 .field("a", 1)
2361 .request()
2362 .respond()
2363 .field("b", 2);
2364 });
2365
2366 inspect_sync_expect("", None, &mut obj, expect!("{a: 1, b: 2}"));
2367 inspect_sync_expect("a", None, &mut obj, expect!("1"));
2368 inspect_sync_expect("b", None, &mut obj, expect!("2"));
2369 inspect_sync_expect("c", None, &mut obj, expect!("error (not found)"));
2370 }
2371
2372 #[test]
2373 fn test_named_merge() {
2374 let mut obj = adhoc(|req| {
2375 req.respond()
2376 .field("a", 1)
2377 .field("a", 2)
2378 .child("x", |req| {
2379 req.respond().field("b", 3).child("c", |req| {
2380 req.respond().field("y", 4);
2381 });
2382 })
2383 .child("x", |req| {
2384 req.respond().field("b", 4).child("d", |req| {
2385 req.respond().field("y", 5);
2386 });
2387 });
2388 });
2389
2390 inspect_sync_expect(
2391 "",
2392 None,
2393 &mut obj,
2394 expect!("{a: 2, x: {b: 4, c: {y: 4}, d: {y: 5}}}"),
2395 );
2396 inspect_sync_expect("x", None, &mut obj, expect!("{b: 4, c: {y: 4}, d: {y: 5}}"));
2397 }
2398
2399 #[test]
2400 fn test_update() {
2401 struct Foo {
2402 immut: u32,
2403 mut_: u32,
2404 child: Option<Box<Foo>>,
2405 }
2406
2407 impl InspectMut for Foo {
2408 fn inspect_mut(&mut self, req: Request<'_>) {
2409 let mut resp = req.respond();
2410 resp.field("immut", self.immut)
2411 .field_mut("mut", &mut self.mut_)
2412 .field_mut("child", &mut self.child);
2413 }
2414 }
2415
2416 let mut foo = Foo {
2417 immut: 1,
2418 mut_: 2,
2419 child: Some(Box::new(Foo {
2420 immut: 101,
2421 mut_: 102,
2422 child: None,
2423 })),
2424 };
2425 assert_eq!(
2426 update("immut", "12", &mut foo)
2427 .now_or_never()
2428 .unwrap()
2429 .unwrap_err(),
2430 Error::Immutable
2431 );
2432 assert_eq!(
2433 update("mut/", "4", &mut foo)
2434 .now_or_never()
2435 .unwrap()
2436 .unwrap_err(),
2437 Error::NotADirectory
2438 );
2439 assert_eq!(
2440 update("mut", "3", &mut foo)
2441 .now_or_never()
2442 .unwrap()
2443 .unwrap()
2444 .kind,
2445 ValueKind::Unsigned(3)
2446 );
2447 assert_eq!(
2448 update("//child/mut", "103", &mut foo)
2449 .now_or_never()
2450 .unwrap()
2451 .unwrap()
2452 .kind,
2453 ValueKind::Unsigned(103)
2454 );
2455 assert_eq!(foo.mut_, 3);
2456 assert_eq!(foo.child.as_ref().unwrap().mut_, 103);
2457 }
2458
2459 #[test]
2460 fn test_nest() {
2461 let mut obj = adhoc(|req| {
2462 req.respond().field("x/a/b", 1).field("x/a/c", 2);
2463 });
2464
2465 inspect_sync_expect("", None, &mut obj, expect!("{x: {a: {b: 1, c: 2}}}"));
2466 inspect_sync_expect("x/a", None, &mut obj, expect!("{b: 1, c: 2}"));
2467 inspect_sync_expect("x", Some(0), &mut obj, expect!("{a: _}"));
2468 inspect_sync_expect("x", Some(2), &mut obj, expect!("{a: {b: 1, c: 2}}"));
2469 }
2470
2471 #[test]
2472 fn test_depth() {
2473 let mut obj = adhoc(|req| {
2474 req.respond()
2475 .field("1a", 0)
2476 .field("1b", 0)
2477 .field("1c", 0)
2478 .child("1d", |req| {
2479 req.respond().field("2a", 0).child("2b", |req| {
2480 req.respond().child("3a", |req| {
2481 req.respond().field_with("xxx", || -> u32 { panic!() });
2482 });
2483 });
2484 })
2485 .field("1d/2b/3b", 0);
2486 });
2487
2488 inspect_sync_expect("1d", Some(0), &mut obj, expect!("{2a: 0, 2b: _}"));
2489 inspect_sync_expect(
2490 "",
2491 Some(0),
2492 &mut obj,
2493 expect!("{1a: 0, 1b: 0, 1c: 0, 1d: _}"),
2494 );
2495 inspect_sync_expect(
2496 "",
2497 Some(1),
2498 &mut obj,
2499 expect!("{1a: 0, 1b: 0, 1c: 0, 1d: {2a: 0, 2b: _}}"),
2500 );
2501 }
2502
2503 #[test]
2504 fn test_hex() {
2505 let mut obj = adhoc(|req| {
2506 req.respond().hex("a", 0x1234);
2507 });
2508 inspect_sync_expect("", Some(0), &mut obj, expect!("{a: 0x1234}"));
2509 }
2510
2511 #[test]
2512 fn test_binary() {
2513 let mut obj = adhoc(|req| {
2514 req.respond().binary("a", 0b1001000110100);
2515 });
2516 inspect_sync_expect("", Some(0), &mut obj, expect!("{a: 0b1001000110100}"));
2517 }
2518
2519 #[test]
2520 fn test_since() {
2521 let mut n = 500_u32;
2522 let mut b = false;
2523 let mut obj = adhoc_mut(|req| {
2524 req.respond()
2525 .counter("c", n)
2526 .field("f", n)
2527 .child("d", |req| {
2528 let mut resp = req.respond();
2529 if !b {
2530 resp.field("1_a", true).field("1_b", true);
2531 } else {
2532 resp.field("1_c", true);
2533 }
2534 resp.field("2", true).counter("3", n);
2535 if !b {
2536 resp.field("4_a", true);
2537 } else {
2538 resp.field("4_b", true).field("4_c", true);
2539 }
2540 });
2541 n += 100;
2542 b = true;
2543 });
2544 let old = inspect_sync("", Some(1), &mut obj);
2545 let new = inspect_sync("", Some(1), &mut obj);
2546
2547 let diff = new.since(&old, Duration::from_secs(2));
2548
2549 expected_node(
2550 diff,
2551 expect!("{c: 50, d: {1_c: true, 2: true, 3: 50, 4_b: true, 4_c: true}, f: 600}"),
2552 );
2553 }
2554
2555 #[test]
2556 fn test_bytes() {
2557 inspect_sync_expect(
2558 "",
2559 Some(1),
2560 &AsBytes([0xab, 0xcd, 0xef]),
2561 expect!("<abcdef>"),
2562 );
2563 }
2564
2565 #[test]
2566 fn test_sensitivity() {
2567 let mut obj = adhoc(|req| {
2568 req.respond()
2569 .sensitivity_field("1a", SensitivityLevel::Safe, 0)
2570 .sensitivity_field("1b", SensitivityLevel::Unspecified, 0)
2571 .sensitivity_field("1c", SensitivityLevel::Sensitive, 0)
2572 .sensitivity_child("1d", SensitivityLevel::Safe, |req| {
2573 req.respond()
2574 .sensitivity_field("2a", SensitivityLevel::Sensitive, 0)
2575 .sensitivity_child("2b", SensitivityLevel::Safe, |req| {
2576 req.respond().sensitivity_child(
2577 "3a",
2578 SensitivityLevel::Sensitive,
2579 |req| {
2580 req.respond().sensitivity_field(
2581 "4a",
2582 SensitivityLevel::Safe,
2583 0,
2584 );
2585 },
2586 );
2587 });
2588 })
2589 .sensitivity_field("1d/2b/3b", SensitivityLevel::Unspecified, 0)
2590 .sensitivity_child("", SensitivityLevel::Sensitive, |req| {
2591 req.respond()
2592 .sensitivity_field("1e", SensitivityLevel::Safe, 0);
2593 });
2594 });
2595
2596 fn inspect_sync(
2597 path: &str,
2598 sensitivity: Option<SensitivityLevel>,
2599 obj: impl InspectMut,
2600 ) -> Node {
2601 let mut result = InspectionBuilder::new(path)
2602 .sensitivity(sensitivity)
2603 .inspect(obj);
2604 result.resolve().now_or_never();
2605 result.results()
2606 }
2607
2608 expected_node(
2609 inspect_sync("", Some(SensitivityLevel::Safe), &mut obj),
2610 expect!("{1a: 0, 1d: {2b: {}}}"),
2611 );
2612 expected_node(
2613 inspect_sync("", Some(SensitivityLevel::Unspecified), &mut obj),
2614 expect!("{1a: 0, 1b: 0, 1d: {2b: {3b: 0}}}"),
2615 );
2616 expected_node(
2617 inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2618 expect!("{1a: 0, 1b: 0, 1c: 0, 1d: {2a: 0, 2b: {3a: {4a: 0}, 3b: 0}}, 1e: 0}"),
2619 );
2620 expected_node(
2621 inspect_sync("", None, &mut obj),
2622 expect!("{1a: 0, 1b: 0, 1c: 0, 1d: {2a: 0, 2b: {3a: {4a: 0}, 3b: 0}}, 1e: 0}"),
2623 );
2624 expected_node(
2625 inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2626 expect!("{1a: 0, 1b: 0, 1c: 0, 1d: {2a: 0, 2b: {3a: {4a: 0}, 3b: 0}}, 1e: 0}"),
2627 );
2628 }
2629
2630 #[test]
2631 fn test_derive() {
2632 use std::marker::PhantomData;
2633
2634 #[derive(InspectMut)]
2635 struct Derived {
2636 dec: u32,
2637 #[inspect(hex, rename = "hex")]
2638 val2: u64,
2639 #[inspect(binary)]
2640 bin: u8,
2641 inner: Inner,
2642 #[inspect(mut)]
2643 inner_mut: InnerMut,
2644 #[inspect(flatten)]
2645 flattened: Inner,
2646 #[inspect(skip)]
2647 _skip: bool,
2648 t: Transparent,
2649 t2: Newtype,
2650 #[inspect(format = "{:02x}")]
2651 minute: u8,
2652 #[inspect(debug)]
2653 debug: (),
2654 #[inspect(display)]
2655 display: u8,
2656 var: Enum,
2657 ignored: Ignored,
2658 tr1: Tr1,
2659 tr2: Tr2,
2660 }
2661
2662 #[derive(Clone, Inspect)]
2663 struct Inner {
2664 val: u32,
2665 }
2666
2667 #[derive(InspectMut)]
2668 struct InnerMut {
2669 val: String,
2670 }
2671
2672 #[derive(Inspect)]
2673 #[inspect(transparent)]
2674 struct Transparent {
2675 inner: Inner,
2676 }
2677
2678 #[derive(Inspect)]
2679 #[inspect(transparent)]
2680 struct Newtype(Inner, PhantomData<()>);
2681
2682 #[derive(Inspect)]
2683 #[inspect(transparent(hex))]
2684 struct Tr1(u32, PhantomData<()>);
2685
2686 #[derive(Inspect)]
2687 #[inspect(transparent)]
2688 struct Tr2(#[inspect(debug)] ());
2689
2690 #[derive(Inspect)]
2691 #[expect(dead_code)]
2692 enum Enum {
2693 Foo,
2694 BarBaz,
2695 #[inspect(rename = "brother")]
2696 Other,
2697 }
2698
2699 #[derive(Inspect)]
2700 #[inspect(skip)]
2701 struct Ignored {
2702 _x: fn(),
2703 }
2704
2705 let mut obj = Derived {
2706 dec: 5,
2707 val2: 4,
2708 bin: 3,
2709 inner: Inner { val: 3 },
2710 inner_mut: InnerMut {
2711 val: "hi".to_string(),
2712 },
2713 _skip: true,
2714 flattened: Inner { val: 8 },
2715 t: Transparent {
2716 inner: Inner { val: 1 },
2717 },
2718 t2: Newtype(Inner { val: 2 }, PhantomData),
2719 debug: (),
2720 display: 10,
2721 minute: 7,
2722 var: Enum::BarBaz,
2723 ignored: Ignored { _x: || () },
2724 tr1: Tr1(10, PhantomData),
2725 tr2: Tr2(()),
2726 };
2727
2728 inspect_sync_expect(
2729 "",
2730 None,
2731 &mut obj,
2732 expect!([
2733 r#"{bin: 0b11, debug: "()", dec: 5, display: "10", hex: 0x4, inner: {val: 3}, inner_mut: {val: "hi"}, minute: "07", t: {val: 1}, t2: {val: 2}, tr1: 0xa, tr2: "()", val: 8, var: "bar_baz"}"#
2734 ]),
2735 );
2736 }
2737
2738 #[test]
2739 fn test_derive_enum() {
2740 #[expect(dead_code)]
2741 #[derive(Inspect)]
2742 enum EmptyUnitEmum {}
2743
2744 #[expect(dead_code)]
2745 #[derive(Inspect)]
2746 #[inspect(untagged)]
2747 enum EmptyUntaggedEmum {}
2748
2749 #[expect(dead_code)]
2750 #[derive(Inspect)]
2751 enum UnitEnum {
2752 A,
2753 B,
2754 C,
2755 }
2756
2757 inspect_sync_expect("", None, &UnitEnum::B, expect!([r#""b""#]));
2758
2759 #[expect(dead_code)]
2760 #[derive(Inspect)]
2761 #[inspect(tag = "tag")]
2762 enum TaggedEnum {
2763 A { x: u32 },
2764 B(#[inspect(rename = "y")] bool),
2765 }
2766
2767 inspect_sync_expect(
2768 "",
2769 None,
2770 &TaggedEnum::B(true),
2771 expect!([r#"{tag: "b", y: true}"#]),
2772 );
2773
2774 #[expect(dead_code)]
2775 #[derive(Inspect)]
2776 #[inspect(external_tag)]
2777 enum ExternallyTaggedEnum {
2778 A {
2779 x: u32,
2780 },
2781 B(#[inspect(rename = "y")] bool),
2782 #[inspect(transparent)]
2783 C(u32),
2784 }
2785
2786 inspect_sync_expect(
2787 "",
2788 None,
2789 &ExternallyTaggedEnum::B(true),
2790 expect!("{b: {y: true}}"),
2791 );
2792
2793 inspect_sync_expect("", None, &ExternallyTaggedEnum::C(5), expect!("{c: 5}"));
2794
2795 #[expect(dead_code)]
2796 #[derive(Inspect)]
2797 #[inspect(untagged)]
2798 enum UntaggedEnum {
2799 A { x: u32 },
2800 B(#[inspect(rename = "y")] bool),
2801 }
2802
2803 inspect_sync_expect("", None, &UntaggedEnum::B(true), expect!("{y: true}"));
2804 }
2805
2806 #[test]
2807 fn test_derive_extra() {
2808 #[derive(Inspect)]
2809 #[inspect(extra = "Foo::inspect_extra")]
2810 struct Foo {
2811 x: u32,
2812 y: u32,
2813 }
2814
2815 impl Foo {
2816 fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
2817 resp.field("sum", self.x + self.y);
2818 }
2819 }
2820
2821 inspect_sync_expect(
2822 "",
2823 None,
2824 &Foo { x: 2, y: 5 },
2825 expect!("{sum: 7, x: 2, y: 5}"),
2826 );
2827 }
2828
2829 #[test]
2830 fn test_derive_sensitivity() {
2831 #[derive(Inspect)]
2832 struct Foo {
2833 #[inspect(safe)]
2834 a: u32,
2835 b: u32,
2836 #[inspect(sensitive)]
2837 c: u32,
2838 #[inspect(safe)]
2839 d: Bar,
2840 }
2841 #[derive(Inspect)]
2842 struct Bar {
2843 #[inspect(sensitive)]
2844 a: u32,
2845 #[inspect(safe)]
2846 b: Baz,
2847 }
2848 #[derive(Inspect)]
2849 struct Baz {
2850 #[inspect(sensitive)]
2851 a: Qux,
2852 b: u32,
2853 }
2854 #[derive(Inspect)]
2855 struct Qux {
2856 #[inspect(safe)]
2857 a: u32,
2858 }
2859
2860 fn inspect_sync(
2861 path: &str,
2862 sensitivity: Option<SensitivityLevel>,
2863 obj: impl Inspect,
2864 ) -> Node {
2865 let mut result = InspectionBuilder::new(path)
2866 .sensitivity(sensitivity)
2867 .inspect(&obj);
2868 result.resolve().now_or_never();
2869 result.results()
2870 }
2871
2872 let obj = Foo {
2873 a: 0,
2874 b: 0,
2875 c: 0,
2876 d: Bar {
2877 a: 0,
2878 b: Baz {
2879 a: Qux { a: 0 },
2880 b: 0,
2881 },
2882 },
2883 };
2884
2885 expected_node(
2886 inspect_sync("", Some(SensitivityLevel::Safe), &obj),
2887 expect!("{a: 0, d: {b: {}}}"),
2888 );
2889 expected_node(
2890 inspect_sync("", Some(SensitivityLevel::Unspecified), &obj),
2891 expect!("{a: 0, b: 0, d: {b: {b: 0}}}"),
2892 );
2893 let node = expected_node(
2894 inspect_sync("", Some(SensitivityLevel::Sensitive), &obj),
2895 expect!("{a: 0, b: 0, c: 0, d: {a: 0, b: {a: {a: 0}, b: 0}}}"),
2896 );
2897 assert_eq!(
2898 node,
2899 inspect_sync("", Some(SensitivityLevel::Sensitive), &obj)
2900 );
2901 }
2902
2903 #[test]
2905 fn test_atomic_mut() {
2906 let mut v = core::sync::atomic::AtomicBool::new(false);
2907 let obj = AtomicMut(&v);
2908 update("", "true", &obj).now_or_never().unwrap().unwrap();
2909 assert!(*v.get_mut());
2910 }
2911}