blob: d4e05aaa8660d582f77ea064cfc04eb35c534074 [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.
#include "wire_object.h"
#include <iomanip>
#include <iostream>
#include <memory>
#include <vector>
#include "src/lib/fidl_codec/colors.h"
#include "src/lib/fidl_codec/display_handle.h"
#include "src/lib/fidl_codec/json_visitor.h"
#include "src/lib/fidl_codec/library_loader.h"
#include "src/lib/fidl_codec/visitor.h"
#include "src/lib/fidl_codec/wire_types.h"
#include "src/lib/fxl/logging.h"
namespace fidl_codec {
constexpr char kInvalid[] = "invalid";
constexpr char kNull[] = "null";
const Colors WithoutColors("", "", "", "", "", "");
const Colors WithColors(/*new_reset=*/"\u001b[0m", /*new_red=*/"\u001b[31m",
/*new_green=*/"\u001b[32m", /*new_blue=*/"\u001b[34m",
/*new_white_on_magenta=*/"\u001b[45m\u001b[37m",
/*new_yellow_background=*/"\u001b[103m");
void Value::Visit(Visitor* visitor) const { visitor->VisitValue(this); }
bool NullableValue::DecodeNullable(MessageDecoder* decoder, uint64_t offset, uint64_t size) {
uintptr_t data;
if (!decoder->GetValueAt(offset, &data)) {
return false;
}
if (data == FIDL_ALLOC_ABSENT) {
is_null_ = true;
return true;
}
if (data != FIDL_ALLOC_PRESENT) {
if (type() == nullptr) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec
<< ": Invalid value <" << std::hex << data << std::dec
<< "> for nullable\n";
} else {
decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec
<< ": Invalid value <" << std::hex << data << std::dec
<< "> for nullable " << type()->Name() << "\n";
}
return false;
}
uint64_t nullable_offset = decoder->next_object_offset();
// Set the offset for the next object (just after this one).
decoder->SkipObject(size);
// Decode the object.
DecodeContent(decoder, nullable_offset);
return true;
}
void NullableValue::Visit(Visitor* visitor) const { visitor->VisitNullableValue(this); }
void InlineValue::DecodeContent(MessageDecoder* /*decoder*/, uint64_t /*offset*/) {
FXL_LOG(FATAL) << "Value is defined inline";
}
void InlineValue::Visit(Visitor* visitor) const { visitor->VisitInlineValue(this); }
int RawValue::DisplaySize(int /*remaining_size*/) const {
return data_ ? static_cast<int>(data_->size()) * 3 - 1 : 0;
}
void RawValue::PrettyPrint(std::ostream& os, const Colors& /*colors*/,
const fidl_message_header_t* /*header*/,
std::string_view /*line_header*/, int /*tabs*/, int /*remaining_size*/,
int /*max_line_size*/) const {
if (!data_ || data_->size() == 0) {
return;
}
size_t buffer_size = data_->size() * 3;
std::vector<char> buffer(buffer_size);
for (size_t i = 0; i < data_->size(); ++i) {
if (i != 0) {
buffer[i * 3 - 1] = ' ';
}
snprintf(buffer.data() + (i * 3), 4, "%02x", (*data_)[i]);
}
os << buffer.data();
}
void RawValue::Visit(Visitor* visitor) const { visitor->VisitRawValue(this); }
template <>
void NumericValue<uint8_t>::Visit(Visitor* visitor) const {
visitor->VisitU8Value(this);
}
template <>
void NumericValue<uint16_t>::Visit(Visitor* visitor) const {
visitor->VisitU16Value(this);
}
template <>
void NumericValue<uint32_t>::Visit(Visitor* visitor) const {
visitor->VisitU32Value(this);
}
template <>
void NumericValue<uint64_t>::Visit(Visitor* visitor) const {
visitor->VisitU64Value(this);
}
template <>
void NumericValue<int8_t>::Visit(Visitor* visitor) const {
visitor->VisitI8Value(this);
}
template <>
void NumericValue<int16_t>::Visit(Visitor* visitor) const {
visitor->VisitI16Value(this);
}
template <>
void NumericValue<int32_t>::Visit(Visitor* visitor) const {
visitor->VisitI32Value(this);
}
template <>
void NumericValue<int64_t>::Visit(Visitor* visitor) const {
visitor->VisitI64Value(this);
}
template <>
void NumericValue<float>::Visit(Visitor* visitor) const {
visitor->VisitF32Value(this);
}
template <>
void NumericValue<double>::Visit(Visitor* visitor) const {
visitor->VisitF64Value(this);
}
int StringValue::DisplaySize(int /*remaining_size*/) const {
if (is_null()) {
return strlen(kNull);
}
if (!string_) {
return strlen(kInvalid);
}
return static_cast<int>(string_->size()) + 2; // The two quotes.
}
void StringValue::DecodeContent(MessageDecoder* decoder, uint64_t offset) {
auto data = reinterpret_cast<const char*>(decoder->GetAddress(offset, string_length_));
string_ = data ? std::optional(std::string(data, data + string_length_)) : std::nullopt;
}
void StringValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* /*header*/,
std::string_view /*line_header*/, int /*tabs*/,
int /*remaining_size*/, int /*max_line_size*/) const {
os << colors.red;
if (is_null()) {
os << kNull;
} else if (!string_) {
os << kInvalid;
} else {
os << '"' << *string_ << '"';
}
os << colors.reset;
}
void StringValue::Visit(Visitor* visitor) const { visitor->VisitStringValue(this); }
int BoolValue::DisplaySize(int /*remaining_size*/) const {
constexpr int kTrueSize = 4;
constexpr int kFalseSize = 5;
constexpr int kInvalidSize = 7;
return value_ ? kInvalidSize : (*value_ ? kTrueSize : kFalseSize);
}
void BoolValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* /*header*/,
std::string_view /*line_header*/, int /*tabs*/, int /*remaining_size*/,
int /*max_line_size*/) const {
if (!value_) {
os << colors.red << "invalid" << colors.reset;
} else {
os << colors.blue << (*value_ ? "true" : "false") << colors.reset;
}
}
void BoolValue::Visit(Visitor* visitor) const { visitor->VisitBoolValue(this); }
int Object::DisplaySize(int remaining_size) const {
if (is_null()) {
return 4;
}
int size = 0;
for (const auto& [name, value] : fields_) {
// Two characters for the separator ("{ " or ", ") and three characters for
// equal (" = ").
constexpr int kExtraSize = 5;
size += static_cast<int>(name.size()) + kExtraSize;
if (value->type() != nullptr) {
// Two characters for ": ".
size += static_cast<int>(value->type()->Name().size()) + 2;
}
size += value->DisplaySize(remaining_size - size);
if (size > remaining_size) {
return size;
}
}
// Two characters for the closing brace (" }").
size += 2;
return size;
}
void Object::DecodeContent(MessageDecoder* decoder, uint64_t offset) { DecodeAt(decoder, offset); }
void Object::DecodeAt(MessageDecoder* decoder, uint64_t base_offset) {
for (const auto& member : struct_definition_.members()) {
std::unique_ptr<Value> value =
member->type()->Decode(decoder, base_offset + member->Offset(decoder));
if (value != nullptr) {
fields_[std::string(member->name())] = std::move(value);
}
}
}
void Object::ExtractJson(rapidjson::Document::AllocatorType& allocator,
rapidjson::Value& result) const {
JsonVisitor visitor(&result, &allocator);
Visit(&visitor);
}
void Object::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* header, std::string_view line_header,
int tabs, int remaining_size, int max_line_size) const {
if (is_null()) {
os << colors.blue << "null" << colors.reset;
} else if (fields_.empty()) {
os << "{}";
} else if (DisplaySize(remaining_size) + static_cast<int>(line_header.size()) <= remaining_size) {
const char* separator = "{ ";
for (const auto& member : struct_definition_.members()) {
auto it = fields_.find(std::string(member->name()));
if (it == fields_.end())
continue;
const auto& [name, value] = *it;
os << separator << name;
separator = ", ";
if (value->type() != nullptr) {
std::string type_name = value->type()->Name();
os << ": " << colors.green << type_name << colors.reset;
}
os << " = ";
value->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size, max_line_size);
}
os << " }";
} else {
os << "{\n";
for (const auto& member : struct_definition_.members()) {
auto it = fields_.find(std::string(member->name()));
if (it == fields_.end())
continue;
const auto& [name, value] = *it;
int size = (tabs + 1) * kTabSize + static_cast<int>(name.size());
os << line_header << std::string((tabs + 1) * kTabSize, ' ') << name;
if (value->type() != nullptr) {
std::string type_name = value->type()->Name();
// Two characters for ": ".
size += static_cast<int>(type_name.size()) + 2;
os << ": " << colors.green << type_name << colors.reset;
}
size += 3;
os << " = ";
value->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size - size,
max_line_size);
os << "\n";
}
os << line_header << std::string(tabs * kTabSize, ' ') << '}';
}
}
void Object::Visit(Visitor* visitor) const { visitor->VisitObject(this); }
EnvelopeValue::EnvelopeValue(const Type* type) : NullableValue(type) {}
int EnvelopeValue::DisplaySize(int remaining_size) const {
if (is_null() || (value_ == nullptr)) {
return 4;
}
return value_->DisplaySize(remaining_size);
}
void EnvelopeValue::DecodeContent(MessageDecoder* decoder, uint64_t offset) {
if (offset + num_bytes_ > decoder->num_bytes()) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec
<< ": Not enough data to decode an envelope\n";
return;
}
if (num_handles_ > decoder->GetRemainingHandles()) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + offset) << std::dec
<< ": Not enough handles to decode an envelope\n";
return;
}
MessageDecoder envelope_decoder(decoder, offset, num_bytes_, num_handles_);
value_ = envelope_decoder.DecodeValue(type());
}
void EnvelopeValue::DecodeAt(MessageDecoder* decoder, uint64_t base_offset) {
decoder->GetValueAt(base_offset, &num_bytes_);
base_offset += sizeof(num_bytes_);
decoder->GetValueAt(base_offset, &num_handles_);
base_offset += sizeof(num_handles_);
if (DecodeNullable(decoder, base_offset, num_bytes_)) {
if (type() == nullptr) {
if (!is_null()) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + base_offset) << std::dec
<< ": The envelope should be null\n";
}
}
if (is_null()) {
if (num_bytes_ != 0) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + base_offset) << std::dec
<< ": Null envelope shouldn't have bytes\n";
}
if (num_handles_ != 0) {
decoder->AddError() << std::hex << (decoder->absolute_offset() + base_offset) << std::dec
<< ": Null envelope shouldn't have handles\n";
}
}
}
}
void EnvelopeValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* header, std::string_view line_header,
int tabs, int remaining_size, int max_line_size) const {
if (is_null() || (value_ == nullptr)) {
os << colors.red << "null" << colors.reset;
} else {
value_->PrettyPrint(os, colors, header, line_header, tabs, remaining_size, max_line_size);
}
}
void EnvelopeValue::Visit(Visitor* visitor) const { visitor->VisitEnvelopeValue(this); }
TableValue::TableValue(const Type* type, const Table& table_definition, uint64_t envelope_count)
: NullableValue(type), table_definition_(table_definition), envelope_count_(envelope_count) {}
int TableValue::DisplaySize(int remaining_size) const {
int size = 0;
for (const auto& field : envelopes_) {
if ((field.value() != nullptr) && !field.value()->is_null()) {
// Two characters for the separator ("{ " or ", ") and three characters
// for equal (" = ").
constexpr int kExtraSize = 5;
size += static_cast<int>(field.name().size()) + kExtraSize;
if (field.value()->type() != nullptr) {
size += static_cast<int>(field.value()->type()->Name().size()) + 2;
}
size += field.value()->DisplaySize(remaining_size - size);
if (size > remaining_size) {
return size;
}
}
}
// Two characters for the closing brace (" }").
size += 2;
return size;
}
void TableValue::DecodeContent(MessageDecoder* decoder, uint64_t offset) {
for (uint64_t envelope_id = 0; envelope_id < envelope_count_; ++envelope_id) {
const TableMember* member = (envelope_id < table_definition_.members().size() - 1)
? table_definition_.members()[envelope_id + 1]
: nullptr;
std::unique_ptr<EnvelopeValue> envelope;
std::string key_name;
if (member == nullptr) {
key_name = std::string("unknown$") + std::to_string(envelope_id + 1);
envelope = std::make_unique<EnvelopeValue>(table_definition_.unknown_member_type());
} else {
key_name = member->name();
envelope = std::make_unique<EnvelopeValue>(member->type());
}
envelope->DecodeAt(decoder, offset);
envelopes_.emplace_back(key_name, std::move(envelope));
offset += 2 * sizeof(uint64_t);
}
}
void TableValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* header, std::string_view line_header,
int tabs, int remaining_size, int max_line_size) const {
int display_size = DisplaySize(remaining_size);
if (display_size == 2) {
os << "{}";
} else if (DisplaySize(remaining_size) + static_cast<int>(line_header.size()) <= remaining_size) {
const char* separator = "{ ";
for (const auto& field : envelopes_) {
if ((field.value() != nullptr) && !field.value()->is_null()) {
os << separator << field.name();
separator = ", ";
if (field.value()->type() != nullptr) {
std::string type_name = field.value()->type()->Name();
os << ": " << colors.green << type_name << colors.reset;
}
os << " = ";
field.value()->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size,
max_line_size);
}
}
os << " }";
} else {
os << "{\n";
for (const auto& field : envelopes_) {
if ((field.value() != nullptr) && !field.value()->is_null()) {
int size = (tabs + 1) * kTabSize + static_cast<int>(field.name().size()) + 3;
os << line_header << std::string((tabs + 1) * kTabSize, ' ') << field.name();
if (field.value()->type() != nullptr) {
std::string type_name = field.value()->type()->Name();
size += static_cast<int>(type_name.size()) + 2;
os << ": " << colors.green << type_name << colors.reset;
}
os << " = ";
field.value()->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size - size,
max_line_size);
os << "\n";
}
}
os << line_header << std::string(tabs * kTabSize, ' ') << '}';
}
}
void TableValue::Visit(Visitor* visitor) const { visitor->VisitTableValue(this); }
int UnionValue::DisplaySize(int remaining_size) const {
if (is_null() || field_.value()->is_null()) {
return 4;
}
// Two characters for the opening brace ("{ ") + three characters for equal
// (" = ") and two characters for the closing brace (" }").
constexpr int kExtraSize = 7;
int size = static_cast<int>(field_.name().size()) + kExtraSize;
if (field_.value() != nullptr) {
if (field_.value()->type() != nullptr) {
// Two characters for ": ".
size += static_cast<int>(field_.value()->type()->Name().size()) + 2;
}
size += field_.value()->DisplaySize(remaining_size - size);
}
return size;
}
void UnionValue::DecodeContent(MessageDecoder* decoder, uint64_t offset) {
DecodeAt(decoder, offset);
}
void UnionValue::DecodeAt(MessageDecoder* decoder, uint64_t base_offset) {
uint32_t tag = 0;
decoder->GetValueAt(base_offset, &tag);
const UnionMember* member = union_definition_.MemberWithTag(tag);
if (member == nullptr) {
field_ =
Field("unknown$" + std::to_string(tag), std::make_unique<RawValue>(nullptr, std::nullopt));
} else {
field_ = Field(std::string(member->name()),
member->type()->Decode(decoder, base_offset + member->offset()));
}
}
void UnionValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* header, std::string_view line_header,
int tabs, int remaining_size, int max_line_size) const {
if (header != nullptr) {
os << (fidl_should_decode_union_from_xunion(header) ? "v1!" : "v0!");
}
if (is_null() || field_.value()->is_null()) {
os << colors.blue << "null" << colors.reset;
} else if (DisplaySize(remaining_size) + static_cast<int>(line_header.size()) <= remaining_size) {
// Two characters for the opening brace ("{ ") + three characters for equal
// (" = ") and two characters for the closing brace (" }").
constexpr int kExtraSize = 7;
int size = static_cast<int>(field_.name().size()) + kExtraSize;
os << "{ " << field_.name();
if (field_.value() != nullptr) {
if (field_.value()->type() != nullptr) {
std::string type_name = field_.value()->type()->Name();
// Two characters for ": ".
size += static_cast<int>(type_name.size()) + 2;
os << ": " << colors.green << type_name << colors.reset;
}
os << " = ";
field_.value()->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size - size,
max_line_size);
}
os << " }";
} else {
os << "{\n";
// Three characters for " = ".
int size = (tabs + 1) * kTabSize + static_cast<int>(field_.name().size()) + 3;
os << line_header << std::string((tabs + 1) * kTabSize, ' ') << field_.name();
if (field_.value() != nullptr) {
if (field_.value()->type() != nullptr) {
std::string type_name = field_.value()->type()->Name();
// Two characters for ": ".
size += static_cast<int>(type_name.size()) + 2;
os << ": " << colors.green << type_name << colors.reset;
}
os << " = ";
field_.value()->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size - size,
max_line_size);
}
os << '\n';
os << line_header << std::string(tabs * kTabSize, ' ') << "}";
}
}
void UnionValue::Visit(Visitor* visitor) const { visitor->VisitUnionValue(this); }
void XUnionValue::Visit(Visitor* visitor) const { visitor->VisitXUnionValue(this); }
int ArrayValue::DisplaySize(int remaining_size) const {
int size = 2;
for (const auto& value : values_) {
// Two characters for ", ".
size += value->DisplaySize(remaining_size - size) + 2;
if (size > remaining_size) {
return size;
}
}
return size;
}
void ArrayValue::DecodeContent(MessageDecoder* /*decoder*/, uint64_t /*offset*/) {
FXL_LOG(FATAL) << "Value is defined inline";
}
void ArrayValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* header, std::string_view line_header,
int tabs, int remaining_size, int max_line_size) const {
if (values_.empty()) {
os << "[]";
} else if (DisplaySize(remaining_size) + static_cast<int>(line_header.size()) <= remaining_size) {
const char* separator = "[ ";
for (const auto& value : values_) {
os << separator;
separator = ", ";
value->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size, max_line_size);
}
os << " ]";
} else {
os << "[\n";
for (const auto& value : values_) {
int size = (tabs + 1) * kTabSize;
os << line_header << std::string((tabs + 1) * kTabSize, ' ');
value->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size - size,
max_line_size);
os << "\n";
}
os << line_header << std::string(tabs * kTabSize, ' ') << ']';
}
}
void ArrayValue::Visit(Visitor* visitor) const { visitor->VisitArrayValue(this); }
int VectorValue::DisplaySize(int remaining_size) const {
if (is_null()) {
return 4;
}
if (is_string_) {
return static_cast<int>(size_ + 2); // The string and the two quotes.
}
int size = 0;
for (const auto& value : values_) {
// Two characters for the separator ("[ " or ", ").
size += value->DisplaySize(remaining_size - size) + 2;
if (size > remaining_size) {
return size;
}
}
// Two characters for the closing bracket (" ]").
size += 2;
return size;
}
void VectorValue::DecodeContent(MessageDecoder* decoder, uint64_t offset) {
if (size_ == 0) {
return;
}
is_string_ = true;
for (uint64_t i = 0;
(i < size_) && (offset + component_type_->InlineSize(decoder) <= decoder->num_bytes());
++i) {
std::unique_ptr<Value> value = component_type_->Decode(decoder, offset);
if (value != nullptr) {
uint8_t uvalue = value->GetUint8Value();
if (!std::isprint(uvalue)) {
if ((uvalue == '\r') || (uvalue == '\n')) {
has_new_line_ = true;
} else {
is_string_ = false;
}
}
values_.push_back(std::move(value));
}
offset += component_type_->InlineSize(decoder);
}
}
void VectorValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* header, std::string_view line_header,
int tabs, int remaining_size, int max_line_size) const {
if (is_null()) {
os << colors.blue << "null" << colors.reset;
} else if (values_.empty()) {
os << "[]";
} else if (is_string_) {
if (has_new_line_) {
os << "[\n";
bool needs_header = true;
for (const auto& value : values_) {
if (needs_header) {
os << line_header << std::string((tabs + 1) * kTabSize, ' ');
needs_header = false;
}
uint8_t uvalue = value->GetUint8Value();
os << uvalue;
if (uvalue == '\n') {
needs_header = true;
}
}
if (!needs_header) {
os << '\n';
}
os << line_header << std::string(tabs * kTabSize, ' ') << ']';
} else {
os << '"';
for (const auto& value : values_) {
os << value->GetUint8Value();
}
os << '"';
}
} else if (DisplaySize(remaining_size) + static_cast<int>(line_header.size()) <= remaining_size) {
const char* separator = "[ ";
for (const auto& value : values_) {
os << separator;
separator = ", ";
value->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size, max_line_size);
}
os << " ]";
} else {
os << "[\n";
int size = 0;
for (const auto& value : values_) {
int value_size = value->DisplaySize(max_line_size - size);
if (size == 0) {
os << line_header << std::string((tabs + 1) * kTabSize, ' ');
size = (tabs + 1) * kTabSize;
} else if (value_size + 3 > max_line_size - size) {
os << ",\n";
os << line_header << std::string((tabs + 1) * kTabSize, ' ');
size = (tabs + 1) * kTabSize;
} else {
os << ", ";
size += 2;
}
value->PrettyPrint(os, colors, header, line_header, tabs + 1, max_line_size - size,
max_line_size);
size += value_size;
}
os << '\n';
os << line_header << std::string(tabs * kTabSize, ' ') << ']';
}
}
void VectorValue::Visit(Visitor* visitor) const { visitor->VisitVectorValue(this); }
int EnumValue::DisplaySize(int /*remaining_size*/) const {
if (!data_) {
return strlen(kInvalid);
}
return enum_definition_.GetNameFromBytes(data_->data()).size();
}
void EnumValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* /*header*/,
std::string_view /*line_header*/, int /*tabs*/, int /*remaining_size*/,
int /*max_line_size*/) const {
if (!data_) {
os << colors.red << kInvalid << colors.reset;
} else {
os << colors.blue << enum_definition_.GetNameFromBytes(data_->data()) << colors.reset;
}
}
void EnumValue::Visit(Visitor* visitor) const { visitor->VisitEnumValue(this); }
int BitsValue::DisplaySize(int /*remaining_size*/) const {
if (!data_) {
return strlen(kInvalid);
}
return bits_definition_.GetNameFromBytes(data_->data()).size();
}
void BitsValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* /*header*/,
std::string_view /*line_header*/, int /*tabs*/, int /*remaining_size*/,
int /*max_line_size*/) const {
if (!data_) {
os << colors.red << kInvalid << colors.reset;
} else {
os << colors.blue << bits_definition_.GetNameFromBytes(data_->data()) << colors.reset;
}
}
void BitsValue::Visit(Visitor* visitor) const { visitor->VisitBitsValue(this); }
int HandleValue::DisplaySize(int /*remaining_size*/) const {
return std::to_string(handle_.handle).size();
}
void HandleValue::DecodeContent(MessageDecoder* /*decoder*/, uint64_t /*offset*/) {
FXL_LOG(FATAL) << "Handle value is defined inline";
}
void HandleValue::PrettyPrint(std::ostream& os, const Colors& colors,
const fidl_message_header_t* /*header*/,
std::string_view /*line_header*/, int /*tabs*/,
int /*remaining_size*/, int /*max_line_size*/) const {
DisplayHandle(colors, handle_, os);
}
void HandleValue::Visit(Visitor* visitor) const { visitor->VisitHandleValue(this); }
} // namespace fidl_codec