diff options
Diffstat (limited to 'src/perfetto/rx_producer.h')
-rw-r--r-- | src/perfetto/rx_producer.h | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/src/perfetto/rx_producer.h b/src/perfetto/rx_producer.h index f4c40b4..4e93f0d 100644 --- a/src/perfetto/rx_producer.h +++ b/src/perfetto/rx_producer.h @@ -51,10 +51,39 @@ struct PerfettoDependencies { uint32_t buffer_size = 4096); }; +namespace detail { + template <typename T> + struct concept_message_lite_base { + static_assert(std::is_base_of_v<::google::protobuf::MessageLite, T>, + "T must inherit from MessageLite"); + using type = T; + }; + + template <typename T> + using concept_message_lite_base_t = typename concept_message_lite_base<T>::type; +} // namespace detail + +/* + * In Android's version of libprotobuf, move-constructors are not generated. + * This results in a legitimate (~10sec per TracePacket being compiled) slowdown, + * so we need to avoid it everywhere. + * + * 1) Don't copy the protos, move them instead. + * 2) Use 'shared_ptr' because rxcpp won't compile with unique_ptr. + */ +template <typename T> +using ProtobufPtr = std::shared_ptr<detail::concept_message_lite_base_t<const T>>; + +template <typename T> +using ProtobufMutablePtr = std::shared_ptr<detail::concept_message_lite_base_t<T>>; + // This acts as a lightweight type marker so that we know what data has actually // encoded under the hood. template <typename T> struct BinaryWireProtobuf { + static_assert(std::is_base_of_v<::google::protobuf::MessageLite, T>, + "T should be a base class of MessageLite"); + std::vector<std::byte>& data() { return data_; } @@ -78,13 +107,21 @@ struct BinaryWireProtobuf { data_.data()); } + explicit BinaryWireProtobuf(std::vector<std::byte> data) : data_{std::move(data)} { + } + + // You wouldn't want to accidentally copy a giant multi-megabyte chunk would you? + // BinaryWireProtobuf(const BinaryWireProtobuf& other) = delete; // FIXME: rx likes to copy. + BinaryWireProtobuf(const BinaryWireProtobuf& other) = default; + BinaryWireProtobuf(BinaryWireProtobuf&& other) = default; + // Important: Deserialization could fail, for example data is truncated or // some minor disc corruption occurred. template <typename U> - std::optional<U> MaybeUnserialize() { - U unencoded; + std::optional<ProtobufPtr<U>> MaybeUnserialize() { + ProtobufMutablePtr<U> unencoded{new U{}}; - if (!unencoded.ParseFromArray(data_.data(), data_.size())) { + if (!unencoded->ParseFromArray(data_.data(), data_.size())) { return std::nullopt; } @@ -94,10 +131,20 @@ struct BinaryWireProtobuf { bool WriteFullyToFile(const std::string& path, bool follow_symlinks = false) const; + static std::optional<BinaryWireProtobuf<T>> ReadFullyFromFile(const std::string& path, + bool follow_symlinks = false); + + bool operator==(const BinaryWireProtobuf<T>& other) const; + bool operator!=(const BinaryWireProtobuf<T>& other) const { + return !(*this == other); + } + private: static bool CleanUpAfterFailedWrite(const std::string& path); bool WriteStringToFd(int fd) const; + static bool ReadFdToString(int fd, /*out*/std::vector<std::byte>* data); + std::vector<std::byte> data_; }; |