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