|  | // Copyright 2020 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. | 
|  |  | 
|  | #ifndef SRC_DEVELOPER_SHELL_COMMON_RESULT_H_ | 
|  | #define SRC_DEVELOPER_SHELL_COMMON_RESULT_H_ | 
|  |  | 
|  | #include <lib/fidl/llcpp/vector_view.h> | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <map> | 
|  | #include <memory> | 
|  | #include <ostream> | 
|  | #include <sstream> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "fuchsia/shell/llcpp/fidl.h" | 
|  |  | 
|  | namespace shell::common { | 
|  |  | 
|  | // Base class for all the types. | 
|  | class ResultType { | 
|  | public: | 
|  | ResultType() = default; | 
|  | virtual ~ResultType() = default; | 
|  |  | 
|  | // Dumps the type. | 
|  | virtual void Dump(std::ostream& os, const char* separator) const {} | 
|  | }; | 
|  |  | 
|  | class ResultTypeUint64 : public ResultType { | 
|  | public: | 
|  | ResultTypeUint64() = default; | 
|  |  | 
|  | void Dump(std::ostream& os, const char* separator) const override { os << separator << "uint64"; } | 
|  | }; | 
|  |  | 
|  | class ResultTypeString : public ResultType { | 
|  | public: | 
|  | ResultTypeString() = default; | 
|  |  | 
|  | void Dump(std::ostream& os, const char* separator) const override { os << separator << "string"; } | 
|  | }; | 
|  |  | 
|  | // Defines a field for a result object schema. | 
|  | class ResultSchemaField { | 
|  | public: | 
|  | ResultSchemaField(uint64_t node_id, const fidl::StringView& name, | 
|  | std::unique_ptr<ResultType> type) | 
|  | : node_id_(node_id), name_(name.data(), name.size()), type_(std::move(type)) {} | 
|  |  | 
|  | uint64_t node_id() const { return node_id_; } | 
|  | const std::string& name() const { return name_; } | 
|  | const ResultType* type() const { return type_.get(); } | 
|  |  | 
|  | private: | 
|  | const uint64_t node_id_; | 
|  | const std::string name_; | 
|  | std::unique_ptr<ResultType> type_; | 
|  | }; | 
|  |  | 
|  | // Defines an object shema for a result. | 
|  | class ResultSchema { | 
|  | public: | 
|  | ResultSchema() = default; | 
|  |  | 
|  | void AddField(uint64_t node_id, const fidl::StringView& name, std::unique_ptr<ResultType> type) { | 
|  | fields_.emplace_back(std::make_shared<ResultSchemaField>(node_id, name, std::move(type))); | 
|  | } | 
|  |  | 
|  | std::shared_ptr<ResultSchemaField> SearchField(uint64_t field_id) const { | 
|  | for (const auto& field : fields_) { | 
|  | if (field->node_id() == field_id) { | 
|  | return field; | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::vector<std::shared_ptr<ResultSchemaField>> fields_; | 
|  | }; | 
|  |  | 
|  | // Defines an object type for a result. | 
|  | class ResultTypeObject : public ResultType { | 
|  | public: | 
|  | ResultTypeObject(std::shared_ptr<ResultSchema> schema) : schema_(schema) {} | 
|  |  | 
|  | private: | 
|  | std::shared_ptr<ResultSchema> schema_; | 
|  | }; | 
|  |  | 
|  | // Base class for a result. | 
|  | class ResultNode { | 
|  | public: | 
|  | ResultNode() = default; | 
|  | virtual ~ResultNode() = default; | 
|  |  | 
|  | // Dumps the result. | 
|  | virtual void Dump(std::ostream& os) const = 0; | 
|  | }; | 
|  |  | 
|  | // Defines an integer literal result. | 
|  | class ResultNodeIntegerLiteral : public ResultNode { | 
|  | public: | 
|  | ResultNodeIntegerLiteral(const fidl::VectorView<uint64_t>& absolute_value, bool negative) | 
|  | : negative_(negative) { | 
|  | for (auto value : absolute_value) { | 
|  | absolute_value_.push_back(value); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Dump(std::ostream& os) const override { | 
|  | if (negative_) { | 
|  | os << '-'; | 
|  | } | 
|  | if (absolute_value_.empty()) { | 
|  | os << '0'; | 
|  | } else if (absolute_value_.size() == 1) { | 
|  | os << absolute_value_[0]; | 
|  | } else { | 
|  | os << "???"; | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::vector<uint64_t> absolute_value_; | 
|  | const bool negative_; | 
|  | }; | 
|  |  | 
|  | // Define a string literal result. | 
|  | class ResultNodeStringLiteral : public ResultNode { | 
|  | public: | 
|  | ResultNodeStringLiteral(const fidl::StringView& string) : string_(string.data(), string.size()) {} | 
|  |  | 
|  | void Dump(std::ostream& os) const override { os << '"' << string_ << '"'; } | 
|  |  | 
|  | private: | 
|  | const std::string string_; | 
|  | }; | 
|  |  | 
|  | // Defines a field for an object result. | 
|  | class ResultNodeObjectField { | 
|  | public: | 
|  | ResultNodeObjectField(std::shared_ptr<ResultSchemaField> field, std::unique_ptr<ResultNode> value) | 
|  | : field_(field), value_(std::move(value)) {} | 
|  |  | 
|  | void Dump(std::ostream& os) const { | 
|  | os << field_->name() << ": "; | 
|  |  | 
|  | if (field_->type() != nullptr) { | 
|  | field_->type()->Dump(os, ""); | 
|  | os << "("; | 
|  | value_->Dump(os); | 
|  | os << ")"; | 
|  | } else { | 
|  | value_->Dump(os); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::shared_ptr<ResultSchemaField> field_; | 
|  | std::unique_ptr<ResultNode> value_; | 
|  | }; | 
|  |  | 
|  | // Defines an object result. | 
|  | class ResultNodeObject : public ResultNode { | 
|  | public: | 
|  | ResultNodeObject(std::shared_ptr<ResultSchema> schema) : schema_(schema) {} | 
|  |  | 
|  | void AddField(std::shared_ptr<ResultSchemaField> field, std::unique_ptr<ResultNode> value) { | 
|  | fields_.emplace_back(std::make_unique<ResultNodeObjectField>(field, std::move(value))); | 
|  | } | 
|  |  | 
|  | void Dump(std::ostream& os) const override { | 
|  | os << '{'; | 
|  | const char* separator = ""; | 
|  | for (const auto& field : fields_) { | 
|  | os << separator; | 
|  | field->Dump(os); | 
|  | separator = ", "; | 
|  | } | 
|  | os << '}'; | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::shared_ptr<ResultSchema> schema_; | 
|  | std::vector<std::unique_ptr<ResultNodeObjectField>> fields_; | 
|  | }; | 
|  |  | 
|  | // Helper for a result deserialization from a vector of nodes. | 
|  | class DeserializeResult { | 
|  | public: | 
|  | DeserializeResult() = default; | 
|  |  | 
|  | // Deserializes a result from a vector of nodes. | 
|  | std::unique_ptr<ResultNode> Deserialize( | 
|  | const fidl::VectorView<llcpp::fuchsia::shell::Node>& nodes); | 
|  |  | 
|  | // Deserializes a node (value). | 
|  | std::unique_ptr<ResultNode> DeserializeNode( | 
|  | const fidl::VectorView<llcpp::fuchsia::shell::Node>& nodes, uint64_t node_id); | 
|  |  | 
|  | // Deserializes an object schema. | 
|  | std::shared_ptr<ResultSchema> DeserializeSchema( | 
|  | const fidl::VectorView<llcpp::fuchsia::shell::Node>& nodes, uint64_t node_id); | 
|  |  | 
|  | // Deserializes a type. | 
|  | std::unique_ptr<ResultType> DeserializeType( | 
|  | const fidl::VectorView<llcpp::fuchsia::shell::Node>& nodes, | 
|  | const llcpp::fuchsia::shell::ShellType& shell_type); | 
|  |  | 
|  | private: | 
|  | // All the schema which have already been deserialized. | 
|  | std::map<uint64_t, std::shared_ptr<ResultSchema>> schemas_; | 
|  | }; | 
|  |  | 
|  | }  // namespace shell::common | 
|  |  | 
|  | #endif  // SRC_DEVELOPER_SHELL_COMMON_RESULT_H_ |