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::reader::ReaderError;
9use crate::Inspector;
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 result = self.state().and_then(|state| match state.try_lock() {
52            Err(_) => None,
53            Ok(state) => state.callbacks().get(name).map(|cb| cb()),
54        });
55        match result {
56            Some(cb_result) => cb_result.await.map_err(ReaderError::LazyCallback),
57            None => return Err(ReaderError::FailedToLoadTree(name.to_string())),
58        }
59    }
60}
61
62#[cfg(target_os = "fuchsia")]
63#[async_trait]
64impl ReadableTree for fidl_fuchsia_inspect::TreeProxy {
65    async fn vmo(&self) -> Result<zx::Vmo, ReaderError> {
66        let tree_content = self.get_content().await.map_err(|e| ReaderError::Fidl(e.into()))?;
67        tree_content.buffer.map(|b| b.vmo).ok_or(ReaderError::FetchVmo)
68    }
69
70    async fn tree_names(&self) -> Result<Vec<String>, ReaderError> {
71        let (name_iterator, server_end) =
72            fidl::endpoints::create_proxy::<fidl_fuchsia_inspect::TreeNameIteratorMarker>();
73        self.list_child_names(server_end).map_err(|e| ReaderError::Fidl(e.into()))?;
74        let mut names = vec![];
75        loop {
76            let subset_names =
77                name_iterator.get_next().await.map_err(|e| ReaderError::Fidl(e.into()))?;
78            if subset_names.is_empty() {
79                return Ok(names);
80            }
81            names.extend(subset_names);
82        }
83    }
84
85    async fn read_tree(&self, name: &str) -> Result<Self, ReaderError> {
86        let (child_tree, server_end) =
87            fidl::endpoints::create_proxy::<fidl_fuchsia_inspect::TreeMarker>();
88        self.open_child(name, server_end).map_err(|e| ReaderError::Fidl(e.into()))?;
89        Ok(child_tree)
90    }
91}