blob: eddf24c1494173f7488fe664253772431afda439 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Provides implementations for common structs that can be read in its entirety. These are structs
//! that can be interpreted using the `fuchsia.inspect.Tree` protocol.
use {
crate::{reader::ReaderError, Inspector},
async_trait::async_trait,
fidl_fuchsia_inspect::{TreeMarker, TreeNameIteratorMarker, TreeProxy},
fuchsia_zircon as zx,
};
/// Trait implemented by structs that can provide inspect data and their lazy links.
#[async_trait]
pub trait ReadableTree: Sized {
/// Returns the lazy links names.
async fn tree_names(&self) -> Result<Vec<String>, ReaderError>;
/// Returns the vmo of the current root node.
async fn vmo(&self) -> Result<zx::Vmo, ReaderError>;
/// Loads the lazy link of the given `name`.
async fn read_tree(&self, name: &str) -> Result<Self, ReaderError>;
}
#[async_trait]
impl ReadableTree for Inspector {
async fn vmo(&self) -> Result<zx::Vmo, ReaderError> {
self.duplicate_vmo().ok_or(ReaderError::DuplicateVmo)
}
async fn tree_names(&self) -> Result<Vec<String>, ReaderError> {
match self.state() {
// A no-op inspector.
None => Ok(vec![]),
Some(state) => {
let state = state.try_lock().map_err(ReaderError::FailedToLockState)?;
let names =
state.callbacks().keys().map(|k| k.to_string()).collect::<Vec<String>>();
Ok(names)
}
}
}
async fn read_tree(&self, name: &str) -> Result<Self, ReaderError> {
let result = self.state().and_then(|state| match state.try_lock() {
Err(_) => None,
Ok(state) => state.callbacks().get(name).map(|cb| cb()),
});
match result {
Some(cb_result) => cb_result.await.map_err(ReaderError::LazyCallback),
None => return Err(ReaderError::FailedToLoadTree(name.to_string())),
}
}
}
#[async_trait]
impl ReadableTree for TreeProxy {
async fn vmo(&self) -> Result<zx::Vmo, ReaderError> {
let tree_content = self.get_content().await.map_err(|e| ReaderError::Fidl(e.into()))?;
tree_content.buffer.map(|b| b.vmo).ok_or(ReaderError::FetchVmo)
}
async fn tree_names(&self) -> Result<Vec<String>, ReaderError> {
let (name_iterator, server_end) = fidl::endpoints::create_proxy::<TreeNameIteratorMarker>()
.map_err(|e| ReaderError::Fidl(e.into()))?;
self.list_child_names(server_end).map_err(|e| ReaderError::Fidl(e.into()))?;
let mut names = vec![];
loop {
let subset_names =
name_iterator.get_next().await.map_err(|e| ReaderError::Fidl(e.into()))?;
if subset_names.is_empty() {
return Ok(names);
}
names.extend(subset_names.into_iter());
}
}
async fn read_tree(&self, name: &str) -> Result<Self, ReaderError> {
let (child_tree, server_end) = fidl::endpoints::create_proxy::<TreeMarker>()
.map_err(|e| ReaderError::Fidl(e.into()))?;
self.open_child(name, server_end).map_err(|e| ReaderError::Fidl(e.into()))?;
Ok(child_tree)
}
}