blob: 5f4bc43f8c196f15201cfe501185143750558319 [file] [log] [blame]
// Copyright 2018 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_LEDGER_BIN_P2P_SYNC_IMPL_MESSAGE_HOLDER_H_
#define SRC_LEDGER_BIN_P2P_SYNC_IMPL_MESSAGE_HOLDER_H_
#include <lib/fit/function.h>
#include <functional>
#include <optional>
#include <utility>
#include <vector>
#include "peridot/lib/convert/convert.h"
#include "src/ledger/bin/p2p_sync/impl/encoding.h"
#include "src/lib/fxl/strings/string_view.h"
namespace p2p_sync {
// MessageHolder is used to hold a parsed Flatbuffer message along with its
// data.
template <class M>
class MessageHolder {
public:
// Create a new MessageHolder from the provided data and a parser.
MessageHolder(std::unique_ptr<std::vector<uint8_t>> data, const M* message)
: data_(std::move(data)), message_(message) {}
// Create a new MessageHolder from the current object and a function to
// specialize the message. The current message holder is destroyed in the
// process. It can be used as follows:
// MessageHolder<Message> message = ...;
// MessageHolder<Request> request = std::move(message).TakeAndMap<Request>(
// [](const Message* message) {
// return static_cast<const Request*>(message->message());
// });
template <class T>
MessageHolder<T> TakeAndMap(
fit::function<const T*(const M*)> get_message) && {
return MessageHolder<T>(std::move(*this), std::move(get_message));
}
// Allow moves.
MessageHolder(MessageHolder&& other) noexcept = default;
MessageHolder& operator=(MessageHolder&& other) noexcept = default;
// Delete copy constructor and assignment. We cannot easily copy a
// MessageHolder because of the need to re-parse the data and reapply the
// chain of specializations to recreate the object.
MessageHolder(const MessageHolder& other) = delete;
MessageHolder& operator=(const MessageHolder<M>& other) = delete;
// Allow MessageHolder<T> to be used as a T* for reading data.
const M* operator->() const { return message_; }
const M& operator*() const { return *message_; }
private:
template <typename U>
friend class MessageHolder;
// Equivalent constructor to the TakeAndMap factory. Using the factory allows
// to explicitly declare template parameters, permitting the use of a lambda
// directly.
template <class T>
MessageHolder(MessageHolder<T>&& other,
fit::function<const M*(const T*)> get_message)
: data_(std::move(other.data_)), message_(get_message(other.message_)) {
other.message_ = nullptr;
}
std::unique_ptr<std::vector<uint8_t>> data_;
const M* message_;
};
// Creates a new MessageHolder to contained a message, or nullopt if no message
// can be obtained.
template <class M>
std::optional<MessageHolder<M>> CreateMessageHolder(
fxl::StringView data,
fit::function<const M*(convert::ExtendedStringView)> get_message) {
std::unique_ptr<std::vector<uint8_t>> data_vec =
std::make_unique<std::vector<uint8_t>>(data.begin(), data.end());
const M* message = get_message(*data_vec);
if (!message) {
return std::nullopt;
}
return MessageHolder<M>(std::move(data_vec), message);
}
} // namespace p2p_sync
#endif // SRC_LEDGER_BIN_P2P_SYNC_IMPL_MESSAGE_HOLDER_H_