| // 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) |
| } |
| } |