fuchsia_inspect/reader/
readable_tree.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Provides implementations for common structs that can be read in its entirety. These are structs
6//! that can be interpreted using the `fuchsia.inspect.Tree` protocol.
7
8use crate::Inspector;
9use crate::reader::ReaderError;
10use async_trait::async_trait;
11
12#[cfg(target_os = "fuchsia")]
13pub type SnapshotSource = zx::Vmo;
14
15#[cfg(not(target_os = "fuchsia"))]
16pub type SnapshotSource = Vec<u8>;
17
18/// Trait implemented by structs that can provide inspect data and their lazy links.
19#[async_trait]
20pub trait ReadableTree: Sized {
21    /// Returns the lazy links names.
22    async fn tree_names(&self) -> Result<Vec<String>, ReaderError>;
23
24    /// Returns the vmo of the current root node.
25    async fn vmo(&self) -> Result<SnapshotSource, ReaderError>;
26
27    /// Loads the lazy link of the given `name`.
28    async fn read_tree(&self, name: &str) -> Result<Self, ReaderError>;
29}
30
31#[async_trait]
32impl ReadableTree for Inspector {
33    async fn vmo(&self) -> Result<SnapshotSource, ReaderError> {
34        self.duplicate_vmo().ok_or(ReaderError::DuplicateVmo)
35    }
36
37    async fn tree_names(&self) -> Result<Vec<String>, ReaderError> {
38        match self.state() {
39            // A no-op inspector.
40            None => Ok(vec![]),
41            Some(state) => {
42                let state = state.try_lock().map_err(ReaderError::FailedToLockState)?;
43                let names =
44                    state.callbacks().keys().map(|k| k.to_string()).collect::<Vec<String>>();
45                Ok(names)
46            }
47        }
48    }
49
50    async fn read_tree(&self, name: &str) -> Result<Self, ReaderError> {
51        let cloned_callbacks = self.state().and_then(|state| match state.try_lock() {
52            Err(_) => None,
53            Ok(state) => state.callbacks().get(name).cloned(),
54        });
55        let result = cloned_callbacks.map(|value| value());
56        match result {
57            Some(cb_result) => cb_result.await.map_err(ReaderError::LazyCallback),
58            None => return Err(ReaderError::FailedToLoadTree(name.to_string())),
59        }
60    }
61}
62
63#[cfg(target_os = "fuchsia")]
64#[async_trait]
65impl ReadableTree for fidl_fuchsia_inspect::TreeProxy {
66    async fn vmo(&self) -> Result<zx::Vmo, ReaderError> {
67        let tree_content = self.get_content().await.map_err(|e| ReaderError::Fidl(e.into()))?;
68        tree_content.buffer.map(|b| b.vmo).ok_or(ReaderError::FetchVmo)
69    }
70
71    async fn tree_names(&self) -> Result<Vec<String>, ReaderError> {
72        let (name_iterator, server_end) =
73            fidl::endpoints::create_proxy::<fidl_fuchsia_inspect::TreeNameIteratorMarker>();
74        self.list_child_names(server_end).map_err(|e| ReaderError::Fidl(e.into()))?;
75        let mut names = vec![];
76        loop {
77            let subset_names =
78                name_iterator.get_next().await.map_err(|e| ReaderError::Fidl(e.into()))?;
79            if subset_names.is_empty() {
80                return Ok(names);
81            }
82            names.extend(subset_names);
83        }
84    }
85
86    async fn read_tree(&self, name: &str) -> Result<Self, ReaderError> {
87        let (child_tree, server_end) =
88            fidl::endpoints::create_proxy::<fidl_fuchsia_inspect::TreeMarker>();
89        self.open_child(name, server_end).map_err(|e| ReaderError::Fidl(e.into()))?;
90        Ok(child_tree)
91    }
92}