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 };
430 (params, path_node_count(root.full_path))
431 }
432}
433
434pub fn inspect(path: &str, obj: impl InspectMut) -> Inspection {
452 InspectionBuilder::new(path).inspect(obj)
453}
454
455#[derive(Debug)]
457pub struct Inspection {
458 node: InternalNode,
459 skip: usize,
460}
461
462impl Inspection {
463 pub async fn resolve(&mut self) {
470 self.node.resolve().await
471 }
472
473 pub fn results(self) -> Node {
478 self.node.into_node().skip(self.skip)
479 }
480}
481
482pub fn update(path: &str, value: &str, obj: impl InspectMut) -> Update {
484 InspectionBuilder::new(path).update(value, obj)
485}
486
487pub struct Update {
489 node: InternalNode,
490 skip: usize,
491}
492
493impl Future for Update {
494 type Output = Result<Value, Error>;
495
496 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
497 let this = self.get_mut();
498 core::task::ready!(this.node.poll_resolve(cx));
499 Poll::Ready(
500 match std::mem::replace(&mut this.node, InternalNode::Unevaluated)
501 .into_node()
502 .skip(this.skip)
503 {
504 Node::Unevaluated => Err(Error::Unresolved),
505 Node::Failed(err) => Err(err),
506 Node::Value(v) => Ok(v),
507 Node::Dir(_) => Err(Error::Unresolved),
508 },
509 )
510 }
511}
512
513impl InternalNode {
514 fn poll_resolve(&mut self, cx: &mut Context<'_>) -> Poll<()> {
515 loop {
516 match self {
517 InternalNode::Dir(children) => {
518 if !children
522 .iter_mut()
523 .all(|entry| entry.node.poll_resolve(cx).is_ready())
524 {
525 break Poll::Pending;
526 }
527 *self = InternalNode::DirResolved(core::mem::take(children));
530 }
531 InternalNode::Deferred(recv) => match Pin::new(recv).poll(cx) {
532 Poll::Ready(node) => {
533 *self = match node {
534 Ok(node) => {
535 node
538 }
539 Err(err) => InternalNode::Failed(match err {
540 mesh::RecvError::Closed => InternalError::Unresolved,
541 mesh::RecvError::Error(err) => InternalError::Mesh(err.to_string()),
542 }),
543 };
544 }
545 _ => break Poll::Pending,
546 },
547 _ => break Poll::Ready(()),
548 }
549 }
550 }
551
552 async fn resolve(&mut self) {
553 poll_fn(|cx| self.poll_resolve(cx)).await
554 }
555
556 fn into_node(self) -> Node {
557 match self {
558 InternalNode::Dir(children) | InternalNode::DirResolved(children) => {
559 let mut child_nodes = Vec::new();
561 for entry in children {
562 if matches!(entry.node, InternalNode::Ignored) {
563 continue;
564 }
565 let mut child_node = entry.node.into_node();
566
567 if entry.name.is_empty() {
568 if let Node::Dir(grandchildren) = child_node {
569 child_nodes.extend(grandchildren);
571 }
572 } else {
573 let mut name = entry.name;
574 let root_len = {
575 let mut names = name.split('/');
577 let root_name = names.next().unwrap();
578 for interior_name in names.rev() {
579 child_node = Node::Dir(vec![Entry {
580 name: interior_name.to_owned(),
581 node: child_node,
582 sensitivity: entry.sensitivity,
583 }]);
584 }
585 root_name.len()
586 };
587 name.truncate(root_len);
588 child_nodes.push(Entry {
589 name,
590 node: child_node,
591 sensitivity: entry.sensitivity,
592 });
593 }
594 }
595
596 Node::merge_list(&mut child_nodes);
597 Node::Dir(child_nodes)
598 }
599 InternalNode::Value(v) => Node::Value(v),
600 InternalNode::Failed(err) => Node::Failed(err.into()),
601 InternalNode::Deferred(_) => Node::Failed(Error::Unresolved),
602 InternalNode::DepthExhausted | InternalNode::Unevaluated | InternalNode::Ignored => {
603 Node::Unevaluated
604 }
605 }
606 }
607}