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
1623impl Inspect for core::time::Duration {
1624 fn inspect(&self, req: Request<'_>) {
1625 req.value(format!("{}.{:09}s", self.as_secs(), self.subsec_nanos()));
1626 }
1627}
1628
1629pub struct AsDisplay<T>(pub T);
1632
1633impl<T: Display> Inspect for AsDisplay<T> {
1634 fn inspect(&self, req: Request<'_>) {
1635 req.value(self.0.to_string())
1636 }
1637}
1638
1639pub struct AsDebug<T>(pub T);
1642
1643impl<T: Debug> InspectMut for AsDebug<T> {
1644 fn inspect_mut(&mut self, req: Request<'_>) {
1645 req.value(format!("{:?}", self.0))
1646 }
1647}
1648
1649impl<T: Debug> Inspect for AsDebug<T> {
1650 fn inspect(&self, req: Request<'_>) {
1651 req.value(format!("{:?}", self.0))
1652 }
1653}
1654
1655macro_rules! hexbincount {
1656 ($tr:ident, $fmt:expr) => {
1657 impl<T: Inspect> Inspect for $tr<T> {
1658 fn inspect(&self, mut req: Request<'_>) {
1659 req.params.number_format = $fmt;
1660 self.0.inspect(req);
1661 }
1662 }
1663
1664 impl<T: InspectMut> InspectMut for $tr<T> {
1665 fn inspect_mut(&mut self, mut req: Request<'_>) {
1666 req.params.number_format = $fmt;
1667 self.0.inspect_mut(req);
1668 }
1669 }
1670 };
1671}
1672
1673#[derive(Clone, Copy)]
1676pub struct AsHex<T>(pub T);
1677
1678hexbincount!(AsHex, NumberFormat::Hex);
1679
1680pub struct AsBinary<T>(pub T);
1683
1684hexbincount!(AsBinary, NumberFormat::Binary);
1685
1686pub struct AsCounter<T>(pub T);
1689
1690hexbincount!(AsCounter, NumberFormat::Counter);
1691
1692pub struct AsBytes<T>(pub T);
1697
1698impl<T> Inspect for AsBytes<T>
1699where
1700 T: Clone + IntoIterator,
1701 Vec<u8>: Extend<T::Item>,
1702{
1703 fn inspect(&self, req: Request<'_>) {
1704 let mut v = Vec::new();
1705 v.extend(self.0.clone());
1706 req.value(ValueKind::Bytes(v))
1707 }
1708}
1709
1710#[doc(hidden)]
1711pub mod derive_helpers {
1712 pub fn call<T, F, R>(t: T, f: F) -> R
1714 where
1715 F: Fn(T) -> R,
1716 {
1717 f(t)
1718 }
1719}
1720
1721#[derive(Default)]
1729pub struct Iterated<I>(I);
1730
1731pub fn iter_by_key<I, K, V>(iter: impl IntoIterator<IntoIter = I>) -> Iterated<I>
1744where
1745 I: Clone + Iterator<Item = (K, V)>,
1746{
1747 Iterated(iter.into_iter())
1748}
1749
1750pub fn iter_by_index<I, V>(
1763 iter: impl IntoIterator<IntoIter = I>,
1764) -> Iterated<core::iter::Enumerate<I>>
1765where
1766 I: Clone + Iterator<Item = V>,
1767{
1768 iter_by_key(iter.into_iter().enumerate())
1769}
1770
1771impl<I, K, V> Iterated<I>
1772where
1773 I: Clone + Iterator<Item = (K, V)>,
1774{
1775 pub fn map_key<F, K2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K2, V)>>
1787 where
1788 F: Clone + FnMut(K) -> K2,
1789 {
1790 iter_by_key(self.0.map(move |(k, v)| (f(k), v)))
1791 }
1792
1793 pub fn map_value<F, V2>(self, mut f: F) -> Iterated<impl Clone + Iterator<Item = (K, V2)>>
1805 where
1806 F: Clone + FnMut(V) -> V2,
1807 {
1808 iter_by_key(self.0.map(move |(k, v)| (k, f(v))))
1809 }
1810
1811 pub fn prefix<'a>(
1823 self,
1824 prefix: &'a str,
1825 ) -> Iterated<impl 'a + Clone + Iterator<Item = (String, V)>>
1826 where
1827 K: Display,
1828 I: 'a,
1829 K: 'a,
1830 V: 'a,
1831 {
1832 self.map_key(move |k| format!("{}{}", prefix, k))
1833 }
1834}
1835
1836impl<I, K, V> Inspect for Iterated<I>
1837where
1838 I: Clone + Iterator<Item = (K, V)>,
1839 K: ToString,
1840 V: Inspect,
1841{
1842 fn inspect(&self, req: Request<'_>) {
1843 let mut resp = req.respond();
1844 for (name, value) in self.0.clone() {
1845 resp.field(&name.to_string(), value);
1846 }
1847 }
1848}
1849
1850#[derive(Debug)]
1851#[cfg_attr(
1852 any(feature = "defer", feature = "initiate"),
1853 derive(mesh::MeshPayload)
1854)]
1855#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1856enum InternalNode {
1857 Unevaluated,
1858 Failed(InternalError),
1859 DepthExhausted,
1860 Value(Value),
1861 Dir(Vec<InternalEntry>),
1862 Ignored,
1863 #[cfg(any(feature = "defer", feature = "initiate"))]
1864 Deferred(mesh::OneshotReceiver<InternalNode>),
1865 #[cfg(any(feature = "defer", feature = "initiate"))]
1866 DirResolved(Vec<InternalEntry>),
1867}
1868
1869#[derive(Debug)]
1870#[cfg_attr(
1871 any(feature = "defer", feature = "initiate"),
1872 derive(mesh::MeshPayload)
1873)]
1874#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1877struct InternalEntry {
1878 name: String,
1879 node: InternalNode,
1880 sensitivity: SensitivityLevel,
1881}
1882
1883#[derive(Debug)]
1884#[cfg_attr(
1885 any(feature = "defer", feature = "initiate"),
1886 derive(mesh::MeshPayload)
1887)]
1888#[cfg_attr(not(any(feature = "defer", feature = "initiate")), expect(dead_code))]
1889enum InternalError {
1890 Immutable,
1891 Update(String),
1892 NotADirectory,
1893 Unresolved,
1894 Mesh(String),
1895}
1896
1897impl InternalNode {
1898 fn failed(err: Box<dyn core::error::Error + Send + Sync>) -> Self {
1899 use core::fmt::Write;
1900
1901 let mut s = err.to_string();
1902 let mut src = err.source();
1903 while let Some(err) = src {
1904 src = err.source();
1905 let _ = write!(&mut s, ": {err}");
1906 }
1907 InternalNode::Failed(InternalError::Update(s))
1908 }
1909}
1910
1911pub trait InspectMut {
1916 fn inspect_mut(&mut self, req: Request<'_>);
1918}
1919
1920impl<T: Inspect + ?Sized> InspectMut for &'_ T {
1921 fn inspect_mut(&mut self, req: Request<'_>) {
1922 self.inspect(req);
1923 }
1924}
1925
1926impl<T: InspectMut + ?Sized> InspectMut for &'_ mut T {
1927 fn inspect_mut(&mut self, req: Request<'_>) {
1928 T::inspect_mut(*self, req)
1929 }
1930}
1931
1932impl<T: InspectMut + ?Sized> InspectMut for Box<T> {
1933 fn inspect_mut(&mut self, req: Request<'_>) {
1934 T::inspect_mut(self.as_mut(), req)
1935 }
1936}
1937
1938impl<T: InspectMut> InspectMut for Option<T> {
1939 fn inspect_mut(&mut self, req: Request<'_>) {
1940 if let Some(val) = self {
1941 val.inspect_mut(req);
1942 } else {
1943 req.ignore();
1944 }
1945 }
1946}
1947
1948pub trait Inspect {
2019 fn inspect(&self, req: Request<'_>);
2021}
2022
2023impl<T: Inspect + ?Sized> Inspect for &'_ T {
2024 fn inspect(&self, req: Request<'_>) {
2025 T::inspect(*self, req)
2026 }
2027}
2028
2029impl<T: Inspect + ?Sized> Inspect for &'_ mut T {
2030 fn inspect(&self, req: Request<'_>) {
2031 T::inspect(*self, req)
2032 }
2033}
2034
2035impl<T: Inspect + ?Sized> Inspect for Box<T> {
2036 fn inspect(&self, req: Request<'_>) {
2037 T::inspect(self.as_ref(), req)
2038 }
2039}
2040
2041impl<T: Inspect + ?Sized> Inspect for Rc<T> {
2042 fn inspect(&self, req: Request<'_>) {
2043 T::inspect(self.as_ref(), req)
2044 }
2045}
2046
2047impl<T: Inspect + ?Sized> Inspect for Arc<T> {
2048 fn inspect(&self, req: Request<'_>) {
2049 T::inspect(self.as_ref(), req)
2050 }
2051}
2052
2053impl<T: Inspect + ?Sized> Inspect for parking_lot::Mutex<T> {
2054 fn inspect(&self, req: Request<'_>) {
2055 T::inspect(&*self.lock(), req)
2056 }
2057}
2058
2059impl<T: Inspect + ?Sized> Inspect for parking_lot::RwLock<T> {
2060 fn inspect(&self, req: Request<'_>) {
2061 T::inspect(&*self.read(), req)
2062 }
2063}
2064
2065#[cfg(feature = "std")]
2066impl<T: Inspect> Inspect for std::sync::OnceLock<T> {
2067 fn inspect(&self, req: Request<'_>) {
2068 <_ as Inspect>::inspect(&self.get(), req)
2069 }
2070}
2071
2072impl<T: Inspect> Inspect for Option<T> {
2073 fn inspect(&self, req: Request<'_>) {
2074 if let Some(val) = self {
2075 val.inspect(req);
2076 } else {
2077 req.ignore();
2078 }
2079 }
2080}
2081
2082impl<T: ?Sized + Inspect + ToOwned> Inspect for Cow<'_, T> {
2083 fn inspect(&self, req: Request<'_>) {
2084 self.as_ref().inspect(req)
2085 }
2086}
2087
2088impl<T> Inspect for *mut T {
2089 fn inspect(&self, req: Request<'_>) {
2090 req.with_hex_format().value(*self as usize)
2091 }
2092}
2093
2094impl<T> Inspect for *const T {
2095 fn inspect(&self, req: Request<'_>) {
2096 req.with_hex_format().value(*self as usize)
2097 }
2098}
2099
2100impl Inspect for ValueKind {
2101 fn inspect(&self, req: Request<'_>) {
2102 req.value(self.clone());
2103 }
2104}
2105
2106impl Inspect for Value {
2107 fn inspect(&self, req: Request<'_>) {
2108 let req = if self.flags.count() {
2109 req.with_counter_format()
2110 } else if self.flags.hex() {
2111 req.with_hex_format()
2112 } else if self.flags.binary() {
2113 req.with_binary_format()
2114 } else {
2115 req
2116 };
2117 req.value(self.kind.clone());
2118 }
2119}
2120
2121pub struct Adhoc<F>(F);
2123
2124impl<F> InspectMut for Adhoc<F>
2125where
2126 F: FnMut(Request<'_>),
2127{
2128 fn inspect_mut(&mut self, req: Request<'_>) {
2129 (self.0)(req)
2130 }
2131}
2132
2133impl<F> Inspect for Adhoc<F>
2134where
2135 F: Fn(Request<'_>),
2136{
2137 fn inspect(&self, req: Request<'_>) {
2138 (self.0)(req)
2139 }
2140}
2141
2142pub fn adhoc<F>(f: F) -> Adhoc<F>
2145where
2146 F: Fn(Request<'_>),
2147{
2148 Adhoc(f)
2149}
2150
2151pub fn adhoc_mut<F>(f: F) -> Adhoc<F>
2154where
2155 F: FnMut(Request<'_>),
2156{
2157 Adhoc(f)
2158}
2159
2160#[cfg(all(test, feature = "derive", feature = "initiate"))]
2161mod tests {
2162 use crate::AsBytes;
2163 use crate::AtomicMut;
2164 use crate::Error;
2165 use crate::Inspect;
2166 use crate::InspectMut;
2167 use crate::InspectionBuilder;
2168 use crate::Node;
2169 use crate::Request;
2170 use crate::SensitivityLevel;
2171 use crate::ValueKind;
2172 use crate::adhoc;
2173 use crate::adhoc_mut;
2174 use crate::inspect;
2175 use crate::update;
2176 use alloc::boxed::Box;
2177 use alloc::string::String;
2178 use alloc::string::ToString;
2179 use alloc::vec;
2180 use alloc::vec::Vec;
2181 use core::time::Duration;
2182 use expect_test::Expect;
2183 use expect_test::expect;
2184 use futures::FutureExt;
2185 use pal_async::DefaultDriver;
2186 use pal_async::async_test;
2187 use pal_async::timer::Instant;
2188 use pal_async::timer::PolledTimer;
2189
2190 fn expected_node(node: Node, expect: Expect) -> Node {
2191 expect.assert_eq(&std::format!("{node:#}"));
2192 node
2193 }
2194
2195 async fn inspect_async(
2196 driver: &DefaultDriver,
2197 path: &str,
2198 depth: Option<usize>,
2199 timeout: Duration,
2200 obj: impl InspectMut,
2201 ) -> Node {
2202 let deadline = Instant::now() + timeout;
2203 let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2204 let mut timer = PolledTimer::new(driver);
2205 futures::select! { _ = result.resolve().fuse() => {}
2207 _ = timer.sleep_until(deadline).fuse() => {}
2208 };
2209 result.results()
2210 }
2211
2212 async fn inspect_async_expect(
2213 driver: &DefaultDriver,
2214 path: &str,
2215 depth: Option<usize>,
2216 timeout: Duration,
2217 obj: impl InspectMut,
2218 expect: Expect,
2219 ) -> Node {
2220 expected_node(
2221 inspect_async(driver, path, depth, timeout, obj).await,
2222 expect,
2223 )
2224 }
2225
2226 fn inspect_sync(path: &str, depth: Option<usize>, obj: impl InspectMut) -> Node {
2227 let mut result = InspectionBuilder::new(path).depth(depth).inspect(obj);
2228 result.resolve().now_or_never();
2229 result.results()
2230 }
2231
2232 fn inspect_sync_expect(
2233 path: &str,
2234 depth: Option<usize>,
2235 obj: impl InspectMut,
2236 expect: Expect,
2237 ) -> Node {
2238 expected_node(inspect_sync(path, depth, obj), expect)
2239 }
2240
2241 #[derive(Default)]
2242 struct Foo {
2243 xx: u32,
2244 xy: bool,
2245 xz: Vec<Foo>,
2246 }
2247
2248 impl Inspect for Foo {
2249 fn inspect(&self, req: Request<'_>) {
2250 let mut resp = req.respond();
2251 resp.field("xx", self.xx)
2252 .field("xy", self.xy)
2253 .fields("", self.xz.iter().enumerate());
2254 }
2255 }
2256
2257 #[test]
2258 fn test() {
2259 let f = Foo {
2260 xx: 1,
2261 xy: true,
2262 xz: vec![
2263 Foo {
2264 xx: 3,
2265 xy: false,
2266 xz: vec![],
2267 },
2268 Foo {
2269 xx: 5,
2270 xy: true,
2271 xz: vec![],
2272 },
2273 ],
2274 };
2275 let node = inspect_sync_expect(
2276 "",
2277 None,
2278 &f,
2279 expect!([r#"
2280 {
2281 0: {
2282 xx: 3,
2283 xy: false,
2284 },
2285 1: {
2286 xx: 5,
2287 xy: true,
2288 },
2289 xx: 1,
2290 xy: true,
2291 }"#]),
2292 );
2293 let expected_json =
2294 expect!([r#"{"0":{"xx":3,"xy":false},"1":{"xx":5,"xy":true},"xx":1,"xy":true}"#]);
2295 expected_json.assert_eq(&node.json().to_string());
2296 }
2297
2298 #[async_test]
2299 async fn test_deferred(driver: DefaultDriver) {
2300 inspect_async_expect(
2301 &driver,
2302 "",
2303 None,
2304 Duration::from_secs(1),
2305 adhoc(|req| {
2306 let foo = req.defer();
2307 std::thread::spawn(|| foo.inspect(&Foo::default()));
2308 }),
2309 expect!([r#"
2310 {
2311 xx: 0,
2312 xy: false,
2313 }"#]),
2314 )
2315 .await;
2316 }
2317
2318 #[async_test]
2319 async fn test_dropped(driver: DefaultDriver) {
2320 inspect_async_expect(
2321 &driver,
2322 "",
2323 None,
2324 Duration::from_secs(86400),
2325 adhoc(|req| {
2326 drop(req.defer());
2327 }),
2328 expect!("error (unresolved)"),
2329 )
2330 .await;
2331 }
2332
2333 #[test]
2334 fn test_path() {
2335 let mut obj = adhoc(|req| {
2336 req.respond().field("a", 1).child("b", |req| {
2337 req.respond().field("c", 2).field("d", 2).child("e", |req| {
2338 req.respond();
2339 });
2340 });
2341 });
2342 inspect_sync_expect("a", None, &mut obj, expect!("1"));
2343 inspect_sync_expect("///a", None, &mut obj, expect!("1"));
2344 inspect_sync_expect(
2345 "b",
2346 None,
2347 &mut obj,
2348 expect!([r#"
2349 {
2350 c: 2,
2351 d: 2,
2352 e: {},
2353 }"#]),
2354 );
2355 inspect_sync_expect("b/c", None, &mut obj, expect!("2"));
2356 inspect_sync_expect("b////c", None, &mut obj, expect!("2"));
2357 inspect_sync_expect("b/c/", None, &mut obj, expect!("error (not a directory)"));
2358 inspect_sync_expect("b/c/x", None, &mut obj, expect!("error (not a directory)"));
2359 inspect_sync_expect("b/e", None, &mut obj, expect!("{}"));
2360 inspect_sync_expect("b/e/", None, &mut obj, expect!("{}"));
2361 inspect_sync_expect("b/e///", None, &mut obj, expect!("{}"));
2362 inspect_sync_expect("b/f", None, &mut obj, expect!("error (not found)"));
2363 }
2364
2365 #[async_test]
2366 async fn test_timeout(driver: DefaultDriver) {
2367 inspect_async_expect(
2368 &driver,
2369 "",
2370 None,
2371 Duration::from_millis(10),
2372 adhoc(|req| {
2373 let foo = req.defer();
2374 std::thread::spawn(|| {
2375 std::thread::sleep(Duration::from_millis(250));
2376 foo.inspect(&Foo::default())
2377 });
2378 }),
2379 expect!("error (unresolved)"),
2380 )
2381 .await;
2382 }
2383
2384 #[test]
2385 fn test_merge() {
2386 let mut obj = adhoc(|req| {
2387 req.respond().field("a", 1).merge(adhoc(|req| {
2388 req.respond().field("b", 2);
2389 }));
2390 });
2391
2392 inspect_sync_expect(
2393 "",
2394 None,
2395 &mut obj,
2396 expect!([r#"
2397 {
2398 a: 1,
2399 b: 2,
2400 }"#]),
2401 );
2402 inspect_sync_expect("a", None, &mut obj, expect!("1"));
2403 inspect_sync_expect("b", None, &mut obj, expect!("2"));
2404 inspect_sync_expect("c", None, &mut obj, expect!("error (not found)"));
2405 }
2406
2407 #[test]
2408 fn test_named_merge() {
2409 let mut obj = adhoc(|req| {
2410 req.respond()
2411 .field("a", 1)
2412 .field("a", 2)
2413 .child("x", |req| {
2414 req.respond().field("b", 3).child("c", |req| {
2415 req.respond().field("y", 4);
2416 });
2417 })
2418 .child("x", |req| {
2419 req.respond().field("b", 4).child("d", |req| {
2420 req.respond().field("y", 5);
2421 });
2422 });
2423 });
2424
2425 inspect_sync_expect(
2426 "",
2427 None,
2428 &mut obj,
2429 expect!([r#"
2430 {
2431 a: 2,
2432 x: {
2433 b: 4,
2434 c: {
2435 y: 4,
2436 },
2437 d: {
2438 y: 5,
2439 },
2440 },
2441 }"#]),
2442 );
2443 inspect_sync_expect(
2444 "x",
2445 None,
2446 &mut obj,
2447 expect!([r#"
2448 {
2449 b: 4,
2450 c: {
2451 y: 4,
2452 },
2453 d: {
2454 y: 5,
2455 },
2456 }"#]),
2457 );
2458 }
2459
2460 #[test]
2461 fn test_update() {
2462 struct Foo {
2463 immut: u32,
2464 mut_: u32,
2465 child: Option<Box<Foo>>,
2466 }
2467
2468 impl InspectMut for Foo {
2469 fn inspect_mut(&mut self, req: Request<'_>) {
2470 let mut resp = req.respond();
2471 resp.field("immut", self.immut)
2472 .field_mut("mut", &mut self.mut_)
2473 .field_mut("child", &mut self.child);
2474 }
2475 }
2476
2477 let mut foo = Foo {
2478 immut: 1,
2479 mut_: 2,
2480 child: Some(Box::new(Foo {
2481 immut: 101,
2482 mut_: 102,
2483 child: None,
2484 })),
2485 };
2486 assert_eq!(
2487 update("immut", "12", &mut foo)
2488 .now_or_never()
2489 .unwrap()
2490 .unwrap_err(),
2491 Error::Immutable
2492 );
2493 assert_eq!(
2494 update("mut/", "4", &mut foo)
2495 .now_or_never()
2496 .unwrap()
2497 .unwrap_err(),
2498 Error::NotADirectory
2499 );
2500 assert_eq!(
2501 update("mut", "3", &mut foo)
2502 .now_or_never()
2503 .unwrap()
2504 .unwrap()
2505 .kind,
2506 ValueKind::Unsigned(3)
2507 );
2508 assert_eq!(
2509 update("//child/mut", "103", &mut foo)
2510 .now_or_never()
2511 .unwrap()
2512 .unwrap()
2513 .kind,
2514 ValueKind::Unsigned(103)
2515 );
2516 assert_eq!(foo.mut_, 3);
2517 assert_eq!(foo.child.as_ref().unwrap().mut_, 103);
2518 }
2519
2520 #[test]
2521 fn test_nest() {
2522 let mut obj = adhoc(|req| {
2523 req.respond().field("x/a/b", 1).field("x/a/c", 2);
2524 });
2525
2526 inspect_sync_expect(
2527 "",
2528 None,
2529 &mut obj,
2530 expect!([r#"
2531 {
2532 x: {
2533 a: {
2534 b: 1,
2535 c: 2,
2536 },
2537 },
2538 }"#]),
2539 );
2540 inspect_sync_expect(
2541 "x/a",
2542 None,
2543 &mut obj,
2544 expect!([r#"
2545 {
2546 b: 1,
2547 c: 2,
2548 }"#]),
2549 );
2550 inspect_sync_expect(
2551 "x",
2552 Some(0),
2553 &mut obj,
2554 expect!([r#"
2555 {
2556 a: _,
2557 }"#]),
2558 );
2559 inspect_sync_expect(
2560 "x",
2561 Some(2),
2562 &mut obj,
2563 expect!([r#"
2564 {
2565 a: {
2566 b: 1,
2567 c: 2,
2568 },
2569 }"#]),
2570 );
2571 }
2572
2573 #[test]
2574 fn test_depth() {
2575 let mut obj = adhoc(|req| {
2576 req.respond()
2577 .field("1a", 0)
2578 .field("1b", 0)
2579 .field("1c", 0)
2580 .child("1d", |req| {
2581 req.respond().field("2a", 0).child("2b", |req| {
2582 req.respond().child("3a", |req| {
2583 req.respond().field_with("xxx", || -> u32 { panic!() });
2584 });
2585 });
2586 })
2587 .field("1d/2b/3b", 0);
2588 });
2589
2590 inspect_sync_expect(
2591 "1d",
2592 Some(0),
2593 &mut obj,
2594 expect!([r#"
2595 {
2596 2a: 0,
2597 2b: _,
2598 }"#]),
2599 );
2600 inspect_sync_expect(
2601 "",
2602 Some(0),
2603 &mut obj,
2604 expect!([r#"
2605 {
2606 1a: 0,
2607 1b: 0,
2608 1c: 0,
2609 1d: _,
2610 }"#]),
2611 );
2612 inspect_sync_expect(
2613 "",
2614 Some(1),
2615 &mut obj,
2616 expect!([r#"
2617 {
2618 1a: 0,
2619 1b: 0,
2620 1c: 0,
2621 1d: {
2622 2a: 0,
2623 2b: _,
2624 },
2625 }"#]),
2626 );
2627 }
2628
2629 #[test]
2630 fn test_hex() {
2631 let mut obj = adhoc(|req| {
2632 req.respond().hex("a", 0x1234);
2633 });
2634 inspect_sync_expect(
2635 "",
2636 Some(0),
2637 &mut obj,
2638 expect!([r#"
2639 {
2640 a: 0x1234,
2641 }"#]),
2642 );
2643 }
2644
2645 #[test]
2646 fn test_binary() {
2647 let mut obj = adhoc(|req| {
2648 req.respond().binary("a", 0b1001000110100);
2649 });
2650 inspect_sync_expect(
2651 "",
2652 Some(0),
2653 &mut obj,
2654 expect!([r#"
2655 {
2656 a: 0b1001000110100,
2657 }"#]),
2658 );
2659 }
2660
2661 #[test]
2662 fn test_since() {
2663 let mut n = 500_u32;
2664 let mut b = false;
2665 let mut obj = adhoc_mut(|req| {
2666 req.respond()
2667 .counter("c", n)
2668 .field("f", n)
2669 .child("d", |req| {
2670 let mut resp = req.respond();
2671 if !b {
2672 resp.field("1_a", true).field("1_b", true);
2673 } else {
2674 resp.field("1_c", true);
2675 }
2676 resp.field("2", true).counter("3", n);
2677 if !b {
2678 resp.field("4_a", true);
2679 } else {
2680 resp.field("4_b", true).field("4_c", true);
2681 }
2682 });
2683 n += 100;
2684 b = true;
2685 });
2686 let old = inspect_sync("", Some(1), &mut obj);
2687 let new = inspect_sync("", Some(1), &mut obj);
2688
2689 let diff = new.since(&old, Duration::from_secs(2));
2690
2691 expected_node(
2692 diff,
2693 expect!([r#"
2694 {
2695 c: 50,
2696 d: {
2697 1_c: true,
2698 2: true,
2699 3: 50,
2700 4_b: true,
2701 4_c: true,
2702 },
2703 f: 600,
2704 }"#]),
2705 );
2706 }
2707
2708 #[test]
2709 fn test_bytes() {
2710 inspect_sync_expect(
2711 "",
2712 Some(1),
2713 &AsBytes([0xab, 0xcd, 0xef]),
2714 expect!("<abcdef>"),
2715 );
2716 }
2717
2718 #[test]
2719 fn test_sensitivity() {
2720 let mut obj = adhoc(|req| {
2721 req.respond()
2722 .sensitivity_field("1a", SensitivityLevel::Safe, 0)
2723 .sensitivity_field("1b", SensitivityLevel::Unspecified, 0)
2724 .sensitivity_field("1c", SensitivityLevel::Sensitive, 0)
2725 .sensitivity_child("1d", SensitivityLevel::Safe, |req| {
2726 req.respond()
2727 .sensitivity_field("2a", SensitivityLevel::Sensitive, 0)
2728 .sensitivity_child("2b", SensitivityLevel::Safe, |req| {
2729 req.respond().sensitivity_child(
2730 "3a",
2731 SensitivityLevel::Sensitive,
2732 |req| {
2733 req.respond().sensitivity_field(
2734 "4a",
2735 SensitivityLevel::Safe,
2736 0,
2737 );
2738 },
2739 );
2740 });
2741 })
2742 .sensitivity_field("1d/2b/3b", SensitivityLevel::Unspecified, 0)
2743 .sensitivity_child("", SensitivityLevel::Sensitive, |req| {
2744 req.respond()
2745 .sensitivity_field("1e", SensitivityLevel::Safe, 0);
2746 });
2747 });
2748
2749 fn inspect_sync(
2750 path: &str,
2751 sensitivity: Option<SensitivityLevel>,
2752 obj: impl InspectMut,
2753 ) -> Node {
2754 let mut result = InspectionBuilder::new(path)
2755 .sensitivity(sensitivity)
2756 .inspect(obj);
2757 result.resolve().now_or_never();
2758 result.results()
2759 }
2760
2761 expected_node(
2762 inspect_sync("", Some(SensitivityLevel::Safe), &mut obj),
2763 expect!([r#"
2764 {
2765 1a: 0,
2766 1d: {
2767 2b: {},
2768 },
2769 }"#]),
2770 );
2771 expected_node(
2772 inspect_sync("", Some(SensitivityLevel::Unspecified), &mut obj),
2773 expect!([r#"
2774 {
2775 1a: 0,
2776 1b: 0,
2777 1d: {
2778 2b: {
2779 3b: 0,
2780 },
2781 },
2782 }"#]),
2783 );
2784 expected_node(
2785 inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2786 expect!([r#"
2787 {
2788 1a: 0,
2789 1b: 0,
2790 1c: 0,
2791 1d: {
2792 2a: 0,
2793 2b: {
2794 3a: {
2795 4a: 0,
2796 },
2797 3b: 0,
2798 },
2799 },
2800 1e: 0,
2801 }"#]),
2802 );
2803 expected_node(
2804 inspect_sync("", None, &mut obj),
2805 expect!([r#"
2806 {
2807 1a: 0,
2808 1b: 0,
2809 1c: 0,
2810 1d: {
2811 2a: 0,
2812 2b: {
2813 3a: {
2814 4a: 0,
2815 },
2816 3b: 0,
2817 },
2818 },
2819 1e: 0,
2820 }"#]),
2821 );
2822 expected_node(
2823 inspect_sync("", Some(SensitivityLevel::Sensitive), &mut obj),
2824 expect!([r#"
2825 {
2826 1a: 0,
2827 1b: 0,
2828 1c: 0,
2829 1d: {
2830 2a: 0,
2831 2b: {
2832 3a: {
2833 4a: 0,
2834 },
2835 3b: 0,
2836 },
2837 },
2838 1e: 0,
2839 }"#]),
2840 );
2841 }
2842
2843 #[test]
2844 fn test_derive() {
2845 use std::marker::PhantomData;
2846
2847 #[derive(InspectMut)]
2848 struct Derived {
2849 dec: u32,
2850 #[inspect(hex, rename = "hex")]
2851 val2: u64,
2852 #[inspect(binary)]
2853 bin: u8,
2854 inner: Inner,
2855 #[inspect(mut)]
2856 inner_mut: InnerMut,
2857 #[inspect(flatten)]
2858 flattened: Inner,
2859 #[inspect(skip)]
2860 _skip: bool,
2861 t: Transparent,
2862 t2: Newtype,
2863 #[inspect(format = "{:02x}")]
2864 minute: u8,
2865 #[inspect(debug)]
2866 debug: (),
2867 #[inspect(display)]
2868 display: u8,
2869 var: Enum,
2870 ignored: Ignored,
2871 tr1: Tr1,
2872 tr2: Tr2,
2873 unnamed: Unnamed,
2874 #[inspect(iter_by_index, hex)]
2875 hex_array: [u8; 4],
2876 hex_inner: HexInner,
2877 #[inspect(hex)]
2878 inner_as_hex: Inner,
2879 }
2880
2881 #[derive(Clone, Inspect)]
2882 struct Inner {
2883 val: u32,
2884 }
2885
2886 #[derive(InspectMut)]
2887 struct InnerMut {
2888 val: String,
2889 }
2890
2891 #[derive(Inspect)]
2892 #[inspect(hex)]
2893 struct HexInner {
2894 val: u32,
2895 }
2896
2897 #[derive(Inspect)]
2898 #[inspect(transparent)]
2899 struct Transparent {
2900 inner: Inner,
2901 }
2902
2903 #[derive(Inspect)]
2904 struct Unnamed(u8, i32);
2905
2906 #[derive(Inspect)]
2907 #[inspect(transparent)]
2908 struct Newtype(Inner, PhantomData<()>);
2909
2910 #[derive(Inspect)]
2911 #[inspect(transparent(hex))]
2912 struct Tr1(u32, PhantomData<()>);
2913
2914 #[derive(Inspect)]
2915 #[inspect(transparent)]
2916 struct Tr2(#[inspect(debug)] ());
2917
2918 #[derive(Inspect)]
2919 #[expect(dead_code)]
2920 enum Enum {
2921 Foo,
2922 BarBaz,
2923 #[inspect(rename = "brother")]
2924 Other,
2925 }
2926
2927 #[derive(Inspect)]
2928 #[inspect(skip)]
2929 struct Ignored {
2930 _x: fn(),
2931 }
2932
2933 let mut obj = Derived {
2934 dec: 5,
2935 val2: 4,
2936 bin: 3,
2937 inner: Inner { val: 3 },
2938 inner_mut: InnerMut {
2939 val: "hi".to_string(),
2940 },
2941 _skip: true,
2942 flattened: Inner { val: 8 },
2943 t: Transparent {
2944 inner: Inner { val: 1 },
2945 },
2946 t2: Newtype(Inner { val: 2 }, PhantomData),
2947 debug: (),
2948 display: 10,
2949 minute: 7,
2950 var: Enum::BarBaz,
2951 ignored: Ignored { _x: || () },
2952 tr1: Tr1(10, PhantomData),
2953 tr2: Tr2(()),
2954 unnamed: Unnamed(5, -83),
2955 hex_array: [100, 101, 102, 103],
2956 hex_inner: HexInner { val: 100 },
2957 inner_as_hex: Inner { val: 100 },
2958 };
2959
2960 inspect_sync_expect(
2961 "",
2962 None,
2963 &mut obj,
2964 expect!([r#"
2965 {
2966 bin: 0b11,
2967 debug: "()",
2968 dec: 5,
2969 display: "10",
2970 hex: 0x4,
2971 hex_array: {
2972 0: 0x64,
2973 1: 0x65,
2974 2: 0x66,
2975 3: 0x67,
2976 },
2977 hex_inner: {
2978 val: 0x64,
2979 },
2980 inner: {
2981 val: 3,
2982 },
2983 inner_as_hex: {
2984 val: 0x64,
2985 },
2986 inner_mut: {
2987 val: "hi",
2988 },
2989 minute: "07",
2990 t: {
2991 val: 1,
2992 },
2993 t2: {
2994 val: 2,
2995 },
2996 tr1: 0xa,
2997 tr2: "()",
2998 unnamed: {
2999 0: 5,
3000 1: -83,
3001 },
3002 val: 8,
3003 var: "bar_baz",
3004 }"#]),
3005 );
3006 }
3007
3008 #[test]
3009 fn test_derive_enum() {
3010 #[expect(dead_code)]
3011 #[derive(Inspect)]
3012 enum EmptyUnitEmum {}
3013
3014 #[expect(dead_code)]
3015 #[derive(Inspect)]
3016 #[inspect(untagged)]
3017 enum EmptyUntaggedEmum {}
3018
3019 #[expect(dead_code)]
3020 #[derive(Inspect)]
3021 enum UnitEnum {
3022 A,
3023 B,
3024 C,
3025 }
3026
3027 inspect_sync_expect("", None, &UnitEnum::B, expect!([r#""b""#]));
3028
3029 #[expect(dead_code)]
3030 #[derive(Inspect)]
3031 #[inspect(tag = "tag")]
3032 enum TaggedEnum {
3033 A { x: u32 },
3034 B(#[inspect(rename = "y")] bool),
3035 }
3036
3037 inspect_sync_expect(
3038 "",
3039 None,
3040 &TaggedEnum::B(true),
3041 expect!([r#"
3042 {
3043 tag: "b",
3044 y: true,
3045 }"#]),
3046 );
3047
3048 #[expect(dead_code)]
3049 #[derive(Inspect)]
3050 #[inspect(external_tag)]
3051 enum ExternallyTaggedEnum {
3052 A {
3053 x: u32,
3054 },
3055 B(#[inspect(rename = "y")] bool),
3056 #[inspect(transparent)]
3057 C(u32),
3058 }
3059
3060 inspect_sync_expect(
3061 "",
3062 None,
3063 &ExternallyTaggedEnum::B(true),
3064 expect!([r#"
3065 {
3066 b: {
3067 y: true,
3068 },
3069 }"#]),
3070 );
3071
3072 inspect_sync_expect(
3073 "",
3074 None,
3075 &ExternallyTaggedEnum::C(5),
3076 expect!([r#"
3077 {
3078 c: 5,
3079 }"#]),
3080 );
3081
3082 #[expect(dead_code)]
3083 #[derive(Inspect)]
3084 #[inspect(untagged)]
3085 enum UntaggedEnum {
3086 A { x: u32 },
3087 B(#[inspect(rename = "y")] bool),
3088 }
3089
3090 inspect_sync_expect(
3091 "",
3092 None,
3093 &UntaggedEnum::B(true),
3094 expect!([r#"
3095 {
3096 y: true,
3097 }"#]),
3098 );
3099 }
3100
3101 #[test]
3102 fn test_derive_extra() {
3103 #[derive(Inspect)]
3104 #[inspect(extra = "Foo::inspect_extra")]
3105 struct Foo {
3106 x: u32,
3107 y: u32,
3108 }
3109
3110 impl Foo {
3111 fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
3112 resp.field("sum", self.x + self.y);
3113 }
3114 }
3115
3116 inspect_sync_expect(
3117 "",
3118 None,
3119 &Foo { x: 2, y: 5 },
3120 expect!([r#"
3121 {
3122 sum: 7,
3123 x: 2,
3124 y: 5,
3125 }"#]),
3126 );
3127 }
3128
3129 #[test]
3130 fn test_derive_sensitivity() {
3131 #[derive(Inspect)]
3132 struct Foo {
3133 #[inspect(safe)]
3134 a: u32,
3135 b: u32,
3136 #[inspect(sensitive)]
3137 c: u32,
3138 #[inspect(safe)]
3139 d: Bar,
3140 }
3141 #[derive(Inspect)]
3142 struct Bar {
3143 #[inspect(sensitive)]
3144 a: u32,
3145 #[inspect(safe)]
3146 b: Baz,
3147 }
3148 #[derive(Inspect)]
3149 struct Baz {
3150 #[inspect(sensitive)]
3151 a: Qux,
3152 b: u32,
3153 }
3154 #[derive(Inspect)]
3155 struct Qux {
3156 #[inspect(safe)]
3157 a: u32,
3158 }
3159
3160 fn inspect_sync(
3161 path: &str,
3162 sensitivity: Option<SensitivityLevel>,
3163 obj: impl Inspect,
3164 ) -> Node {
3165 let mut result = InspectionBuilder::new(path)
3166 .sensitivity(sensitivity)
3167 .inspect(&obj);
3168 result.resolve().now_or_never();
3169 result.results()
3170 }
3171
3172 let obj = Foo {
3173 a: 0,
3174 b: 0,
3175 c: 0,
3176 d: Bar {
3177 a: 0,
3178 b: Baz {
3179 a: Qux { a: 0 },
3180 b: 0,
3181 },
3182 },
3183 };
3184
3185 expected_node(
3186 inspect_sync("", Some(SensitivityLevel::Safe), &obj),
3187 expect!([r#"
3188 {
3189 a: 0,
3190 d: {
3191 b: {},
3192 },
3193 }"#]),
3194 );
3195 expected_node(
3196 inspect_sync("", Some(SensitivityLevel::Unspecified), &obj),
3197 expect!([r#"
3198 {
3199 a: 0,
3200 b: 0,
3201 d: {
3202 b: {
3203 b: 0,
3204 },
3205 },
3206 }"#]),
3207 );
3208 let node = expected_node(
3209 inspect_sync("", Some(SensitivityLevel::Sensitive), &obj),
3210 expect!([r#"
3211 {
3212 a: 0,
3213 b: 0,
3214 c: 0,
3215 d: {
3216 a: 0,
3217 b: {
3218 a: {
3219 a: 0,
3220 },
3221 b: 0,
3222 },
3223 },
3224 }"#]),
3225 );
3226 assert_eq!(
3227 node,
3228 inspect_sync("", Some(SensitivityLevel::Sensitive), &obj)
3229 );
3230 }
3231
3232 #[test]
3234 fn test_atomic_mut() {
3235 let mut v = core::sync::atomic::AtomicBool::new(false);
3236 let obj = AtomicMut(&v);
3237 update("", "true", &obj).now_or_never().unwrap().unwrap();
3238 assert!(*v.get_mut());
3239 }
3240}