| // 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. |
| |
| #include <lib/fit/bridge.h> |
| #include <lib/inspect/cpp/reader.h> |
| #include <lib/inspect/service/cpp/reader.h> |
| |
| using inspect::internal::SnapshotTree; |
| |
| namespace inspect { |
| |
| namespace { |
| fit::promise<SnapshotTree> SnapshotTreeFromTree(fuchsia::inspect::TreePtr tree) { |
| fit::bridge<fuchsia::inspect::TreeContent> content_bridge; |
| fuchsia::inspect::TreeNameIteratorPtr child_ptr; |
| tree->GetContent(content_bridge.completer.bind()); |
| tree->ListChildNames(child_ptr.NewRequest()); |
| return fit::join_promises(content_bridge.consumer.promise_or(fit::error()), |
| ReadAllChildNames(std::move(child_ptr))) |
| .and_then([tree = std::move(tree)]( |
| std::tuple<fit::result<fuchsia::inspect::TreeContent>, |
| fit::result<std::vector<std::string>>>& result) mutable |
| -> fit::promise<SnapshotTree> { |
| auto& content = std::get<0>(result); |
| auto& children = std::get<1>(result); |
| |
| SnapshotTree ret; |
| if (!content.is_ok() || !children.is_ok() || |
| Snapshot::Create(content.take_value().buffer().vmo, &ret.snapshot)) { |
| return fit::make_result_promise<SnapshotTree>(fit::error()); |
| } |
| |
| // Sequence all child reads for depth-first traversal. |
| fit::sequencer seq; |
| std::vector<fit::promise<SnapshotTree>> child_promises; |
| for (const auto& child_name : children.value()) { |
| fuchsia::inspect::TreePtr child_ptr; |
| tree->OpenChild(child_name, child_ptr.NewRequest()); |
| child_promises.emplace_back(SnapshotTreeFromTree(std::move(child_ptr)).wrap_with(seq)); |
| } |
| |
| return join_promise_vector(std::move(child_promises)) |
| .and_then( |
| [ret = std::move(ret), tree = std::move(tree), children = children.take_value()]( |
| std::vector<fit::result<SnapshotTree>>& results) mutable { |
| ZX_ASSERT(children.size() == results.size()); |
| |
| for (size_t i = 0; i < results.size(); i++) { |
| if (results[i].is_ok()) { |
| ret.children.emplace(std::move(children[i]), results[i].take_value()); |
| } |
| } |
| |
| return fit::ok(std::move(ret)); |
| }); |
| |
| return fit::make_result_promise<SnapshotTree>(fit::error()); |
| }); |
| } |
| } // namespace |
| |
| fit::promise<std::vector<std::string>> ReadAllChildNames( |
| fuchsia::inspect::TreeNameIteratorPtr iterator) { |
| fit::bridge<std::vector<std::string>> bridge; |
| |
| iterator->GetNext(bridge.completer.bind()); |
| |
| return bridge.consumer.promise_or(fit::error()) |
| .then([it = std::move(iterator)](fit::result<std::vector<std::string>>& result) mutable |
| -> fit::promise<std::vector<std::string>> { |
| if (!result.is_ok() || result.value().size() == 0) { |
| return fit::make_ok_promise(std::vector<std::string>()); |
| } |
| |
| return ReadAllChildNames(std::move(it)) |
| .then( |
| [ret = result.take_value()](fit::result<std::vector<std::string>>& result) mutable { |
| if (result.is_ok()) { |
| for (auto& v : result.take_value()) { |
| ret.emplace_back(std::move(v)); |
| } |
| } |
| return fit::make_ok_promise(std::move(ret)); |
| }); |
| }); |
| } |
| |
| fit::promise<Hierarchy> ReadFromTree(fuchsia::inspect::TreePtr tree) { |
| return SnapshotTreeFromTree(std::move(tree)).and_then(internal::ReadFromSnapshotTree); |
| } |
| |
| } // namespace inspect |