blob: add1a492913a9bfe8679c3e27d81b5f5218aad4b [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 <utility>
#include <vector>
#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(fxl::StringView data,
fit::function<const M*(const uint8_t*)> get_message)
: data_(data.begin(), data.end()), message_(get_message(data_.data())) {}
// Create a new MessageHolder from the provided data and a parser.
MessageHolder(std::vector<uint8_t> data,
fit::function<const M*(const uint8_t*)> get_message)
: data_(std::move(data)), message_(get_message(data_.data())) {}
// 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::vector<uint8_t> data_;
const M* message_;
};
} // namespace p2p_sync
#endif // SRC_LEDGER_BIN_P2P_SYNC_IMPL_MESSAGE_HOLDER_H_