1mod natural_sort;
7
8use super::InspectMut;
9use super::InternalError;
10use super::InternalNode;
11use super::SensitivityLevel;
12use super::Value;
13use super::ValueKind;
14use crate::NumberFormat;
15use crate::RequestParams;
16use crate::RootParams;
17use alloc::borrow::ToOwned;
18use alloc::string::String;
19use alloc::string::ToString;
20use alloc::vec;
21use alloc::vec::Vec;
22use base64::display::Base64Display;
23use core::cmp::Ordering;
24use core::fmt;
25use core::fmt::Write;
26use core::future::Future;
27use core::future::poll_fn;
28use core::pin::Pin;
29use core::task::Context;
30use core::task::Poll;
31use core::time::Duration;
32use mesh::MeshPayload;
33use thiserror::Error;
34
35#[derive(Debug, Clone, PartialEq, MeshPayload)]
37#[mesh(package = "inspect")]
38#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
39pub enum Node {
40 #[mesh(1)]
42 Unevaluated,
43 #[mesh(2)]
45 Failed(Error),
46 #[mesh(3)]
48 Value(Value),
49 #[mesh(4)]
51 Dir(Vec<Entry>),
52}
53
54#[derive(Debug, Clone, PartialEq, MeshPayload)]
55#[mesh(package = "inspect")]
56#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
57pub struct Entry {
59 #[mesh(1)]
61 pub name: String,
62 #[mesh(2)]
64 pub node: Node,
65 #[mesh(3)]
67 pub sensitivity: SensitivityLevel,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Error, MeshPayload)]
72#[mesh(package = "inspect")]
73#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
74pub enum Error {
75 #[error("unresolved")]
77 #[mesh(1)]
78 Unresolved,
79 #[error("channel error: {0}")]
81 #[mesh(2)]
82 Mesh(String),
83 #[error("immutable node")]
85 #[mesh(3)]
86 Immutable,
87 #[error("update error: {0}")]
89 #[mesh(4)]
90 Update(String),
91 #[error("not a directory")]
93 #[mesh(5)]
94 NotADirectory,
95 #[error("not found")]
97 #[mesh(6)]
98 NotFound,
99 #[error("internal error")]
101 #[mesh(7)]
102 Internal,
103}
104
105impl From<InternalError> for Error {
106 fn from(value: InternalError) -> Self {
107 match value {
108 InternalError::Immutable => Self::Immutable,
109 InternalError::Update(v) => Self::Update(v),
110 InternalError::NotADirectory => Self::NotADirectory,
111 InternalError::Unresolved => Self::Unresolved,
112 InternalError::Mesh(v) => Self::Mesh(v),
113 }
114 }
115}
116
117struct DebugFromDisplay<T>(T);
119
120impl<T: fmt::Display> fmt::Debug for DebugFromDisplay<T> {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 self.0.fmt(f)
123 }
124}
125
126impl fmt::Display for Node {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 match self {
129 Node::Unevaluated => f.pad("_"),
130 Node::Failed(err) => write!(f, "error ({err})"),
131 Node::Value(v) => fmt::Display::fmt(v, f),
132 Node::Dir(children) => {
133 let mut map = f.debug_map();
134 for entry in children {
135 map.entry(
136 &DebugFromDisplay(&entry.name),
137 &DebugFromDisplay(&entry.node),
138 );
139 }
140 map.finish()
141 }
142 }
143 }
144}
145
146impl Node {
147 fn merge_list(children: &mut Vec<Entry>) {
148 children.sort_by(|a, b| natural_sort::compare(&a.name, &b.name));
150
151 {
153 let mut last: Option<&mut Entry> = None;
154 for entry in children.iter_mut() {
155 if entry.name.is_empty() {
156 continue;
157 }
158 match &mut last {
159 Some(last_entry) if *last_entry.name == entry.name => {
160 last_entry
161 .node
162 .merge(core::mem::replace(&mut entry.node, Node::Unevaluated));
163 entry.name.clear();
164 }
165 _ => {
166 last = Some(entry);
167 }
168 }
169 }
170 }
171
172 children.retain(|entry| !entry.name.is_empty());
174 }
175
176 fn merge(&mut self, other: Node) {
177 if matches!(other, Node::Unevaluated) {
178 return;
179 }
180 match self {
181 Node::Unevaluated | Node::Failed(_) | Node::Value(_) => {
182 *self = other;
184 }
185
186 Node::Dir(children) => match other {
187 Node::Unevaluated | Node::Failed(_) | Node::Value(_) => {
188 }
190 Node::Dir(mut other_children) => {
191 children.append(&mut other_children);
192 Self::merge_list(children);
193 }
194 },
195 }
196 }
197
198 fn skip(mut self, mut n: usize) -> Node {
199 while n > 0 {
200 self = match self {
201 Node::Dir(d) => {
202 if d.len() == 1 {
203 d.into_iter().next().unwrap().node
204 } else if d.is_empty() {
205 return Node::Failed(Error::NotFound);
206 } else {
207 return Node::Failed(Error::Internal);
210 }
211 }
212 Node::Failed(_) | Node::Unevaluated => return self,
213 Node::Value(_) => {
214 return Node::Failed(Error::Internal);
216 }
217 };
218 n -= 1;
219 }
220 self
221 }
222
223 fn compute_since(&self, last: &Node, t: f64) -> Node {
224 match (self, last) {
225 (Node::Value(value), Node::Value(last)) if value.flags.count() => {
226 let kind = match (&value.kind, &last.kind) {
227 (ValueKind::Unsigned(x), ValueKind::Unsigned(y)) => {
228 ValueKind::Double((x - y) as f64 / t)
229 }
230 (ValueKind::Signed(x), ValueKind::Signed(y)) => {
231 ValueKind::Double((x - y) as f64 / t)
232 }
233 (ValueKind::Float(x), ValueKind::Float(y)) => {
234 ValueKind::Double((x - y) as f64 / t)
235 }
236 (ValueKind::Double(x), ValueKind::Double(y)) => ValueKind::Double((x - y) / t),
237 (kind, _) => kind.clone(),
238 };
239 Node::Value(Value {
240 kind,
241 flags: value.flags,
242 })
243 }
244 (Node::Dir(this), Node::Dir(last)) => {
245 let mut children = Vec::new();
246 let mut this = this.iter().peekable();
247 let mut last = last.iter().peekable();
248 while let (Some(&this_entry), Some(&last_entry)) = (this.peek(), last.peek()) {
249 match this_entry.name.cmp(&last_entry.name) {
250 Ordering::Less => {
251 children.push(this_entry.clone());
252 this.next();
253 }
254 Ordering::Equal => {
255 children.push(Entry {
256 node: this_entry.node.compute_since(&last_entry.node, t),
257 ..this_entry.clone()
258 });
259 this.next();
260 last.next();
261 }
262 Ordering::Greater => {
263 last.next();
264 }
265 }
266 }
267 children.extend(this.cloned());
268 Node::Dir(children)
269 }
270 (node, _) => node.clone(),
271 }
272 }
273
274 pub fn since(&self, last: &Node, duration: Duration) -> Self {
284 self.compute_since(last, duration.as_secs_f64())
285 }
286
287 pub fn json(&self) -> impl '_ + fmt::Display {
289 JsonDisplay(self)
290 }
291}
292
293struct JsonDisplay<'a>(&'a Node);
294
295impl fmt::Display for JsonDisplay<'_> {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 match self.0 {
298 Node::Unevaluated => f.write_str("null"),
299 Node::Failed(error) => write!(f, r#"{{"$error":{:?}}}"#, error.to_string()),
302 Node::Value(value) => match &value.kind {
303 ValueKind::Signed(v) => {
304 if value.flags.hex() {
307 write!(f, r#""{v:#x}""#)
308 } else if value.flags.binary() {
309 write!(f, r#""{v:#b}""#)
310 } else {
311 write!(f, "{v}")
312 }
313 }
314 ValueKind::Unsigned(v) => {
315 if value.flags.hex() {
316 write!(f, r#""{v:#x}""#)
317 } else if value.flags.binary() {
318 write!(f, r#""{v:#b}""#)
319 } else {
320 write!(f, "{v}")
321 }
322 }
323 ValueKind::Float(v) => write!(f, "{v}"),
324 ValueKind::Double(v) => write!(f, "{v}"),
325 ValueKind::Bool(v) => write!(f, "{v}"),
326 ValueKind::String(v) => write!(f, "{v:?}"),
327 ValueKind::Bytes(b) => {
328 write!(
330 f,
331 r#""{}""#,
332 Base64Display::new(b, &base64::engine::general_purpose::STANDARD_NO_PAD)
333 )
334 }
335 },
336 Node::Dir(children) => {
337 f.write_char('{')?;
338 let mut comma = "";
339 for entry in children {
340 let child = JsonDisplay(&entry.node);
341 let name = &entry.name;
342 write!(f, "{comma}{name:?}:{child}")?;
343 comma = ",";
344 }
345 f.write_char('}')?;
346 Ok(())
347 }
348 }
349 }
350}
351
352fn path_node_count(path: &str) -> usize {
353 path.split('/').filter(|x| !x.is_empty()).count()
354}
355
356pub struct InspectionBuilder<'a> {
358 path: &'a str,
359 depth: Option<usize>,
360 sensitivity: Option<SensitivityLevel>,
361}
362
363impl<'a> InspectionBuilder<'a> {
364 pub fn new(path: &'a str) -> Self {
366 Self {
367 path,
368 depth: None,
369 sensitivity: None,
370 }
371 }
372
373 pub fn depth(mut self, depth: Option<usize>) -> Self {
375 self.depth = depth;
376 self
377 }
378
379 pub fn sensitivity(mut self, sensitivity: Option<SensitivityLevel>) -> Self {
381 self.sensitivity = sensitivity;
382 self
383 }
384
385 pub fn inspect(self, obj: impl InspectMut) -> Inspection {
387 let root = self.root();
388 let (params, skip) = self.build(&root);
389 Inspection {
390 node: params.inspect(obj),
391 skip,
392 }
393 }
394
395 pub fn update(self, value: &'a str, obj: impl InspectMut) -> Update {
397 let mut root = self.root();
398 root.value = Some(value);
399 let (params, skip) = self.build(&root);
400 Update {
401 node: params.inspect(obj),
402 skip,
403 }
404 }
405
406 fn root(&self) -> RootParams<'_> {
407 RootParams {
408 full_path: self.path,
409 value: None,
410 sensitivity: self.sensitivity.unwrap_or(SensitivityLevel::Sensitive),
411 }
412 }
413
414 fn build<'b>(&self, root: &'b RootParams<'_>) -> (RequestParams<'b>, usize) {
415 const MAX_INSPECT_DEPTH: usize = 4096;
419 let depth_with_root = if let Some(depth) = self.depth {
420 depth.saturating_add(1).min(MAX_INSPECT_DEPTH)
421 } else {
422 MAX_INSPECT_DEPTH
423 };
424 let params = RequestParams {
425 root,
426 path_start: 0,
427 depth: depth_with_root,
428 number_format: NumberFormat::default(),
429 parent_sensitivity: SensitivityLevel::Unspecified,
430 };
431 (params, path_node_count(root.full_path))
432 }
433}
434
435pub fn inspect(path: &str, obj: impl InspectMut) -> Inspection {
453 InspectionBuilder::new(path).inspect(obj)
454}
455
456#[derive(Debug)]
458pub struct Inspection {
459 node: InternalNode,
460 skip: usize,
461}
462
463impl Inspection {
464 pub async fn resolve(&mut self) {
471 self.node.resolve().await
472 }
473
474 pub fn results(self) -> Node {
479 self.node.into_node().skip(self.skip)
480 }
481}
482
483pub fn update(path: &str, value: &str, obj: impl InspectMut) -> Update {
485 InspectionBuilder::new(path).update(value, obj)
486}
487
488pub struct Update {
490 node: InternalNode,
491 skip: usize,
492}
493
494impl Future for Update {
495 type Output = Result<Value, Error>;
496
497 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
498 let this = self.get_mut();
499 core::task::ready!(this.node.poll_resolve(cx));
500 Poll::Ready(
501 match std::mem::replace(&mut this.node, InternalNode::Unevaluated)
502 .into_node()
503 .skip(this.skip)
504 {
505 Node::Unevaluated => Err(Error::Unresolved),
506 Node::Failed(err) => Err(err),
507 Node::Value(v) => Ok(v),
508 Node::Dir(_) => Err(Error::Unresolved),
509 },
510 )
511 }
512}
513
514impl InternalNode {
515 fn poll_resolve(&mut self, cx: &mut Context<'_>) -> Poll<()> {
516 loop {
517 match self {
518 InternalNode::Dir(children) => {
519 if !children
523 .iter_mut()
524 .all(|entry| entry.node.poll_resolve(cx).is_ready())
525 {
526 break Poll::Pending;
527 }
528 *self = InternalNode::DirResolved(core::mem::take(children));
531 }
532 InternalNode::Deferred(recv) => match Pin::new(recv).poll(cx) {
533 Poll::Ready(node) => {
534 *self = match node {
535 Ok(node) => {
536 node
539 }
540 Err(err) => InternalNode::Failed(match err {
541 mesh::RecvError::Closed => InternalError::Unresolved,
542 mesh::RecvError::Error(err) => InternalError::Mesh(err.to_string()),
543 }),
544 };
545 }
546 _ => break Poll::Pending,
547 },
548 _ => break Poll::Ready(()),
549 }
550 }
551 }
552
553 async fn resolve(&mut self) {
554 poll_fn(|cx| self.poll_resolve(cx)).await
555 }
556
557 fn into_node(self) -> Node {
558 match self {
559 InternalNode::Dir(children) | InternalNode::DirResolved(children) => {
560 let mut child_nodes = Vec::new();
562 for entry in children {
563 if matches!(entry.node, InternalNode::Ignored) {
564 continue;
565 }
566 let mut child_node = entry.node.into_node();
567
568 if entry.name.is_empty() {
569 if let Node::Dir(grandchildren) = child_node {
570 child_nodes.extend(grandchildren);
572 }
573 } else {
574 let mut name = entry.name;
575 let root_len = {
576 let mut names = name.split('/');
578 let root_name = names.next().unwrap();
579 for interior_name in names.rev() {
580 child_node = Node::Dir(vec![Entry {
581 name: interior_name.to_owned(),
582 node: child_node,
583 sensitivity: entry.sensitivity,
584 }]);
585 }
586 root_name.len()
587 };
588 name.truncate(root_len);
589 child_nodes.push(Entry {
590 name,
591 node: child_node,
592 sensitivity: entry.sensitivity,
593 });
594 }
595 }
596
597 Node::merge_list(&mut child_nodes);
598 Node::Dir(child_nodes)
599 }
600 InternalNode::Value(v) => Node::Value(v),
601 InternalNode::Failed(err) => Node::Failed(err.into()),
602 InternalNode::Deferred(_) => Node::Failed(Error::Unresolved),
603 InternalNode::DepthExhausted | InternalNode::Unevaluated | InternalNode::Ignored => {
604 Node::Unevaluated
605 }
606 }
607 }
608}