1mod natural_sort;
7
8use super::InspectMut;
9use super::InternalError;
10use super::InternalNode;
11use super::RequestRoot;
12use super::SensitivityLevel;
13use super::Value;
14use super::ValueKind;
15use alloc::borrow::ToOwned;
16use alloc::string::String;
17use alloc::string::ToString;
18use alloc::vec;
19use alloc::vec::Vec;
20use base64::display::Base64Display;
21use core::cmp::Ordering;
22use core::fmt;
23use core::fmt::Write;
24use core::future::Future;
25use core::future::poll_fn;
26use core::pin::Pin;
27use core::task::Context;
28use core::task::Poll;
29use core::time::Duration;
30use mesh::MeshPayload;
31use thiserror::Error;
32
33#[derive(Debug, Clone, PartialEq, MeshPayload)]
35#[mesh(package = "inspect")]
36#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
37pub enum Node {
38 #[mesh(1)]
40 Unevaluated,
41 #[mesh(2)]
43 Failed(Error),
44 #[mesh(3)]
46 Value(Value),
47 #[mesh(4)]
49 Dir(Vec<Entry>),
50}
51
52#[derive(Debug, Clone, PartialEq, MeshPayload)]
53#[mesh(package = "inspect")]
54#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
55pub struct Entry {
57 #[mesh(1)]
59 pub name: String,
60 #[mesh(2)]
62 pub node: Node,
63 #[mesh(3)]
65 pub sensitivity: SensitivityLevel,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Error, MeshPayload)]
70#[mesh(package = "inspect")]
71#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
72pub enum Error {
73 #[error("unresolved")]
75 #[mesh(1)]
76 Unresolved,
77 #[error("channel error: {0}")]
79 #[mesh(2)]
80 Mesh(String),
81 #[error("immutable node")]
83 #[mesh(3)]
84 Immutable,
85 #[error("update error: {0}")]
87 #[mesh(4)]
88 Update(String),
89 #[error("not a directory")]
91 #[mesh(5)]
92 NotADirectory,
93 #[error("not found")]
95 #[mesh(6)]
96 NotFound,
97 #[error("internal error")]
99 #[mesh(7)]
100 Internal,
101}
102
103impl From<InternalError> for Error {
104 fn from(value: InternalError) -> Self {
105 match value {
106 InternalError::Immutable => Self::Immutable,
107 InternalError::Update(v) => Self::Update(v),
108 InternalError::NotADirectory => Self::NotADirectory,
109 InternalError::Unresolved => Self::Unresolved,
110 InternalError::Mesh(v) => Self::Mesh(v),
111 }
112 }
113}
114
115struct DebugFromDisplay<T>(T);
117
118impl<T: fmt::Display> fmt::Debug for DebugFromDisplay<T> {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 self.0.fmt(f)
121 }
122}
123
124impl fmt::Display for Node {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 Node::Unevaluated => f.pad("_"),
128 Node::Failed(err) => write!(f, "error ({err})"),
129 Node::Value(v) => fmt::Display::fmt(v, f),
130 Node::Dir(children) => {
131 let mut map = f.debug_map();
132 for entry in children {
133 map.entry(
134 &DebugFromDisplay(&entry.name),
135 &DebugFromDisplay(&entry.node),
136 );
137 }
138 map.finish()
139 }
140 }
141 }
142}
143
144impl Node {
145 fn merge_list(children: &mut Vec<Entry>) {
146 children.sort_by(|a, b| natural_sort::compare(&a.name, &b.name));
148
149 {
151 let mut last: Option<&mut Entry> = None;
152 for entry in children.iter_mut() {
153 if entry.name.is_empty() {
154 continue;
155 }
156 match &mut last {
157 Some(last_entry) if *last_entry.name == entry.name => {
158 last_entry
159 .node
160 .merge(core::mem::replace(&mut entry.node, Node::Unevaluated));
161 entry.name.clear();
162 }
163 _ => {
164 last = Some(entry);
165 }
166 }
167 }
168 }
169
170 children.retain(|entry| !entry.name.is_empty());
172 }
173
174 fn merge(&mut self, other: Node) {
175 if matches!(other, Node::Unevaluated) {
176 return;
177 }
178 match self {
179 Node::Unevaluated | Node::Failed(_) | Node::Value(_) => {
180 *self = other;
182 }
183
184 Node::Dir(children) => match other {
185 Node::Unevaluated | Node::Failed(_) | Node::Value(_) => {
186 }
188 Node::Dir(mut other_children) => {
189 children.append(&mut other_children);
190 Self::merge_list(children);
191 }
192 },
193 }
194 }
195
196 fn skip(mut self, mut n: usize) -> Node {
197 while n > 0 {
198 self = match self {
199 Node::Dir(d) => {
200 if d.len() == 1 {
201 d.into_iter().next().unwrap().node
202 } else if d.is_empty() {
203 return Node::Failed(Error::NotFound);
204 } else {
205 return Node::Failed(Error::Internal);
208 }
209 }
210 Node::Failed(_) | Node::Unevaluated => return self,
211 Node::Value(_) => {
212 return Node::Failed(Error::Internal);
214 }
215 };
216 n -= 1;
217 }
218 self
219 }
220
221 fn compute_since(&self, last: &Node, t: f64) -> Node {
222 match (self, last) {
223 (Node::Value(value), Node::Value(last)) if value.flags.count() => {
224 let kind = match (&value.kind, &last.kind) {
225 (ValueKind::Unsigned(x), ValueKind::Unsigned(y)) => {
226 ValueKind::Double((x - y) as f64 / t)
227 }
228 (ValueKind::Signed(x), ValueKind::Signed(y)) => {
229 ValueKind::Double((x - y) as f64 / t)
230 }
231 (ValueKind::Float(x), ValueKind::Float(y)) => {
232 ValueKind::Double((x - y) as f64 / t)
233 }
234 (ValueKind::Double(x), ValueKind::Double(y)) => ValueKind::Double((x - y) / t),
235 (kind, _) => kind.clone(),
236 };
237 Node::Value(Value {
238 kind,
239 flags: value.flags,
240 })
241 }
242 (Node::Dir(this), Node::Dir(last)) => {
243 let mut children = Vec::new();
244 let mut this = this.iter().peekable();
245 let mut last = last.iter().peekable();
246 while let (Some(&this_entry), Some(&last_entry)) = (this.peek(), last.peek()) {
247 match this_entry.name.cmp(&last_entry.name) {
248 Ordering::Less => {
249 children.push(this_entry.clone());
250 this.next();
251 }
252 Ordering::Equal => {
253 children.push(Entry {
254 node: this_entry.node.compute_since(&last_entry.node, t),
255 ..this_entry.clone()
256 });
257 this.next();
258 last.next();
259 }
260 Ordering::Greater => {
261 last.next();
262 }
263 }
264 }
265 children.extend(this.cloned());
266 Node::Dir(children)
267 }
268 (node, _) => node.clone(),
269 }
270 }
271
272 pub fn since(&self, last: &Node, duration: Duration) -> Self {
282 self.compute_since(last, duration.as_secs_f64())
283 }
284
285 pub fn json(&self) -> impl '_ + fmt::Display {
287 JsonDisplay(self)
288 }
289}
290
291struct JsonDisplay<'a>(&'a Node);
292
293impl fmt::Display for JsonDisplay<'_> {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 match self.0 {
296 Node::Unevaluated | Node::Failed(_) => f.write_str("null"),
297 Node::Value(value) => match &value.kind {
298 ValueKind::Signed(v) => write!(f, "{}", v),
299 ValueKind::Unsigned(v) => write!(f, "{}", v),
300 ValueKind::Float(v) => write!(f, "{}", v),
301 ValueKind::Double(v) => write!(f, "{}", v),
302 ValueKind::Bool(v) => write!(f, "{}", v),
303 ValueKind::String(v) => write!(f, "{:?}", v),
304 ValueKind::Bytes(b) => {
305 write!(
307 f,
308 r#""{}""#,
309 Base64Display::new(b, &base64::engine::general_purpose::STANDARD_NO_PAD)
310 )
311 }
312 },
313 Node::Dir(children) => {
314 f.write_char('{')?;
315 let mut comma = "";
316 for entry in children {
317 let child = JsonDisplay(&entry.node);
318 let name = &entry.name;
319 write!(f, "{comma}{name:?}:{child}")?;
320 comma = ",";
321 }
322 f.write_char('}')?;
323 Ok(())
324 }
325 }
326 }
327}
328
329fn path_node_count(path: &str) -> usize {
330 path.split('/').filter(|x| !x.is_empty()).count()
331}
332
333pub struct InspectionBuilder<'a> {
335 path: &'a str,
336 depth: Option<usize>,
337 sensitivity: Option<SensitivityLevel>,
338}
339
340impl<'a> InspectionBuilder<'a> {
341 pub fn new(path: &'a str) -> Self {
343 Self {
344 path,
345 depth: None,
346 sensitivity: None,
347 }
348 }
349
350 pub fn depth(mut self, depth: Option<usize>) -> Self {
352 self.depth = depth;
353 self
354 }
355
356 pub fn sensitivity(mut self, sensitivity: Option<SensitivityLevel>) -> Self {
358 self.sensitivity = sensitivity;
359 self
360 }
361
362 pub fn inspect(self, obj: impl InspectMut) -> Inspection {
364 let (root, skip) = self.run(None, obj);
365 Inspection {
366 node: root.node,
367 skip,
368 }
369 }
370
371 pub fn update(self, value: &str, obj: impl InspectMut) -> Update {
373 let (root, skip) = self.run(Some(value), obj);
374 Update {
375 node: Some(root.node),
376 skip,
377 }
378 }
379
380 fn run(&self, value: Option<&'a str>, mut obj: impl InspectMut) -> (RequestRoot<'a>, usize) {
381 let Self {
382 path,
383 depth,
384 sensitivity,
385 } = self;
386 const MAX_INSPECT_DEPTH: usize = 4096;
390 let depth_with_root = if let Some(depth) = depth {
391 depth.saturating_add(1).min(MAX_INSPECT_DEPTH)
392 } else {
393 MAX_INSPECT_DEPTH
394 };
395 let mut root = RequestRoot::new(
396 path,
397 depth_with_root,
398 value,
399 sensitivity.unwrap_or(SensitivityLevel::Sensitive),
400 );
401 obj.inspect_mut(root.request());
402 (root, path_node_count(path))
403 }
404}
405
406pub fn inspect(path: &str, obj: impl InspectMut) -> Inspection {
424 InspectionBuilder::new(path).inspect(obj)
425}
426
427#[derive(Debug)]
429pub struct Inspection {
430 node: InternalNode,
431 skip: usize,
432}
433
434impl Inspection {
435 pub async fn resolve(&mut self) {
442 self.node.resolve().await
443 }
444
445 pub fn results(self) -> Node {
450 self.node.into_node().skip(self.skip)
451 }
452}
453
454pub fn update(path: &str, value: &str, obj: impl InspectMut) -> Update {
456 InspectionBuilder::new(path).update(value, obj)
457}
458
459pub struct Update {
461 node: Option<InternalNode>,
462 skip: usize,
463}
464
465impl Future for Update {
466 type Output = Result<Value, Error>;
467
468 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
469 let this = self.get_mut();
470 core::task::ready!(this.node.as_mut().unwrap().poll_resolve(cx));
471 Poll::Ready(
472 match this.node.take().unwrap().into_node().skip(this.skip) {
473 Node::Unevaluated => Err(Error::Unresolved),
474 Node::Failed(err) => Err(err),
475 Node::Value(v) => Ok(v),
476 Node::Dir(_) => Err(Error::Unresolved),
477 },
478 )
479 }
480}
481
482impl InternalNode {
483 fn poll_resolve(&mut self, cx: &mut Context<'_>) -> Poll<()> {
484 loop {
485 match self {
486 InternalNode::Dir(children) => {
487 if !children
491 .iter_mut()
492 .all(|entry| entry.node.poll_resolve(cx).is_ready())
493 {
494 break Poll::Pending;
495 }
496 *self = InternalNode::DirResolved(core::mem::take(children));
499 }
500 InternalNode::Deferred(recv) => match Pin::new(recv).poll(cx) {
501 Poll::Ready(node) => {
502 *self = match node {
503 Ok(node) => {
504 node
507 }
508 Err(err) => InternalNode::Failed(match err {
509 mesh::RecvError::Closed => InternalError::Unresolved,
510 mesh::RecvError::Error(err) => InternalError::Mesh(err.to_string()),
511 }),
512 };
513 }
514 _ => break Poll::Pending,
515 },
516 _ => break Poll::Ready(()),
517 }
518 }
519 }
520
521 async fn resolve(&mut self) {
522 poll_fn(|cx| self.poll_resolve(cx)).await
523 }
524
525 fn into_node(self) -> Node {
526 match self {
527 InternalNode::Dir(children) | InternalNode::DirResolved(children) => {
528 let mut child_nodes = Vec::new();
530 for entry in children {
531 if matches!(entry.node, InternalNode::Ignored) {
532 continue;
533 }
534 let mut child_node = entry.node.into_node();
535
536 if entry.name.is_empty() {
537 if let Node::Dir(grandchildren) = child_node {
538 child_nodes.extend(grandchildren);
540 }
541 } else {
542 let mut name = entry.name;
543 let root_len = {
544 let mut names = name.split('/');
546 let root_name = names.next().unwrap();
547 for interior_name in names.rev() {
548 child_node = Node::Dir(vec![Entry {
549 name: interior_name.to_owned(),
550 node: child_node,
551 sensitivity: entry.sensitivity,
552 }]);
553 }
554 root_name.len()
555 };
556 name.truncate(root_len);
557 child_nodes.push(Entry {
558 name,
559 node: child_node,
560 sensitivity: entry.sensitivity,
561 });
562 }
563 }
564
565 Node::merge_list(&mut child_nodes);
566 Node::Dir(child_nodes)
567 }
568 InternalNode::Value(v) => Node::Value(v),
569 InternalNode::Failed(err) => Node::Failed(err.into()),
570 InternalNode::Deferred(_) => Node::Failed(Error::Unresolved),
571 InternalNode::DepthExhausted | InternalNode::Unevaluated | InternalNode::Ignored => {
572 Node::Unevaluated
573 }
574 }
575 }
576}