| /* | |
| * Copyright (C) 2025 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "src/protovm/rw_proto.h" | |
| #include "perfetto/protozero/proto_utils.h" | |
| #include "perfetto/protozero/scattered_heap_buffer.h" | |
| namespace perfetto { | |
| namespace protovm { | |
| RwProto::RwProto(Allocator* allocator) | |
| : allocator_{allocator}, root_{Node::Empty{}} {} | |
| RwProto::~RwProto() { | |
| allocator_->DeleteReferencedData(&root_); | |
| } | |
| RwProto::Cursor RwProto::GetRoot() { | |
| return Cursor{&root_, allocator_}; | |
| } | |
| std::string RwProto::SerializeAsString() const { | |
| if (root_.GetIf<Node::Empty>()) { | |
| return ""; | |
| } | |
| if (auto* bytes = root_.GetIf<Node::Bytes>()) { | |
| return std::string(static_cast<char*>(bytes->data.get()), bytes->size); | |
| } | |
| protozero::HeapBuffered<protozero::Message> proto; | |
| auto* message = root_.GetIf<Node::Message>(); | |
| PERFETTO_DCHECK(message); | |
| for (auto it = message->field_id_to_node.begin(); it; ++it) { | |
| auto field_id = static_cast<uint32_t>(it->key); | |
| SerializeField(field_id, *it->value, proto.get()); | |
| } | |
| return proto.SerializeAsString(); | |
| } | |
| void RwProto::SerializeField(uint32_t field_id, | |
| const Node& node, | |
| protozero::Message* proto) const { | |
| if (node.GetIf<Node::Empty>()) { | |
| return; | |
| } | |
| if (auto* bytes = node.GetIf<Node::Bytes>()) { | |
| proto->AppendBytes(field_id, bytes->data.get(), bytes->size); | |
| return; | |
| } | |
| if (auto* scalar = node.GetIf<Scalar>()) { | |
| if (scalar->wire_type == protozero::proto_utils::ProtoWireType::kFixed32) { | |
| proto->AppendFixed(field_id, static_cast<uint32_t>(scalar->value)); | |
| return; | |
| } | |
| if (scalar->wire_type == protozero::proto_utils::ProtoWireType::kFixed64) { | |
| proto->AppendFixed(field_id, static_cast<uint64_t>(scalar->value)); | |
| return; | |
| } | |
| proto->AppendVarInt(field_id, scalar->value); | |
| return; | |
| } | |
| if (auto* message = node.GetIf<Node::Message>()) { | |
| auto* message_proto = | |
| proto->BeginNestedMessage<protozero::Message>(field_id); | |
| for (auto it = message->field_id_to_node.begin(); it; ++it) { | |
| auto message_field_id = static_cast<uint32_t>(it->key); | |
| SerializeField(message_field_id, *it->value, message_proto); | |
| } | |
| } | |
| if (node.GetIf<Node::IndexedRepeatedField>() || | |
| node.GetIf<Node::MappedRepeatedField>()) { | |
| const IntrusiveMap* map; | |
| if (auto* indexed = node.GetIf<Node::IndexedRepeatedField>()) { | |
| map = &indexed->index_to_node; | |
| } else { | |
| map = &node.GetIf<Node::MappedRepeatedField>()->key_to_node; | |
| } | |
| for (auto it = map->begin(); it; ++it) { | |
| SerializeField(field_id, *it->value, proto); | |
| } | |
| } | |
| } | |
| } // namespace protovm | |
| } // namespace perfetto |