Skip to content

Commit

Permalink
Merge pull request eclipse-uprotocol#161 from pranavishere2/payloadBu…
Browse files Browse the repository at this point in the history
…ilder

Implement PayloadBuilder Class and implement unit tests
  • Loading branch information
gregmedd committed Jun 21, 2024
2 parents 8f56461 + 1b36df7 commit cba9666
Show file tree
Hide file tree
Showing 3 changed files with 659 additions and 15 deletions.
41 changes: 31 additions & 10 deletions include/up-cpp/datamodel/builder/Payload.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ struct Payload {
/// @brief A serialized payload as a pairing of bytes and format.
using Serialized = std::tuple<PbBytes, v1::UPayloadFormat>;

/// @brief The two types of data that can be stored in a Serialized payload.
enum PayloadType { Data, Format };

/// @brief Constructs a Payload builder with the payload populated by
/// a serialized protobuf.
///
Expand All @@ -43,7 +46,13 @@ struct Payload {
/// @remarks The UPayloadFormat will automatically be set to
/// UPAYLOAD_FORMAT_PROTOBUF
template <typename ProtobufT>
explicit Payload(const ProtobufT&);
explicit Payload(const ProtobufT& message) {
std::string serialized;
message.SerializeToString(&serialized);
payload_ =
std::make_tuple(std::move(serialized),
v1::UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF);
}

/// @brief Creates a Payload builder with the payload populated by the
/// result of Serializer::serialize(data).
Expand All @@ -70,15 +79,23 @@ struct Payload {
/// will compile out.
/// @param data Data to be serialized and stored.
template <typename Serializer, typename ValueT>
Payload(Serializer s, const ValueT& data);
Payload(Serializer s, const ValueT& data) {
auto serializedData = Serializer::serialize(data);
if (!UPayloadFormat_IsValid(
std::get<PayloadType::Format>(serializedData))) {
throw std::out_of_range("Invalid Serializer payload format");
}
payload_ = std::move(serializedData);
}

/// @brief Creates a Payload builder with a provided pre-serialized data.
///
/// @param value_bytes A byte array containing the serialized payload.
/// @param format The data format of the payload in value_bytes.
///
/// @throws std::out_of_range If format is not valid for v1::UPayloadFormat
Payload(const std::vector<uint8_t>& value_bytes, v1::UPayloadFormat format);
Payload(const std::vector<uint8_t>& value_bytes,
const v1::UPayloadFormat format);

/// @brief Creates a Payload builder with a provided pre-serialized data.
///
Expand All @@ -89,7 +106,7 @@ struct Payload {
///
/// @note This would typically be used for UPAYLOAD_FORMAT_TEXT or
/// UPAYLOAD_FORMAT_JSON, but can be used for other payload formats.
Payload(const std::string& value, v1::UPayloadFormat format);
Payload(const std::string& value, const v1::UPayloadFormat format);

/// @brief Creates a Payload builder with a provided pre-serialized data.
///
Expand All @@ -102,7 +119,7 @@ struct Payload {
///
/// @note This would typically be used for UPAYLOAD_FORMAT_TEXT or
/// UPAYLOAD_FORMAT_JSON, but can be used for other payload formats.
Payload(std::string&& value, v1::UPayloadFormat format);
Payload(std::string&& value, const v1::UPayloadFormat format);

/// @brief Creates a Payload builder with a provided pre-serialized data.
///
Expand Down Expand Up @@ -138,20 +155,24 @@ struct Payload {

/// @brief Get a reference to the internal data from this builder.
///
/// @throws PayloadMoved if called after move() has already been called.
[[nodiscard]] constexpr const Serialized& build() const;
/// @throws PayloadMoved if called after buildMove() has already been
/// called.
[[nodiscard]] const Serialized& buildCopy() const;

/// @brief Get an xvalue of the internal data that can be moved into a
/// UMessage.
///
/// @post This Payload builder will no longer be valid. Calling `build()`
/// @post This Payload builder will no longer be valid. Calling
/// `buildCopy()`
/// or `movePayload()` after this will result in an exception.
///
/// @throws PayloadMoved if called after move() has already been called.
[[nodiscard]] constexpr Serialized move() &&;
/// @throws PayloadMoved if called after buildMove() has already been
/// called.
[[nodiscard]] Serialized buildMove() &&;

private:
Serialized payload_;
bool moved_{false};
};

} // namespace uprotocol::datamodel::builder
Expand Down
98 changes: 98 additions & 0 deletions src/datamodel/builder/Payload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,101 @@
// SPDX-License-Identifier: Apache-2.0

#include "up-cpp/datamodel/builder/Payload.h"
namespace uprotocol::datamodel::builder {

// Byte vector constructor
Payload::Payload(const std::vector<uint8_t>& value_bytes,
const v1::UPayloadFormat format) {
if (!UPayloadFormat_IsValid(format)) {
throw std::out_of_range("Invalid Byte vector payload format");
}
std::string serialized(value_bytes.begin(), value_bytes.end());
payload_ = std::make_tuple(std::move(serialized), format);
}

// String constructor
Payload::Payload(const std::string& value, const v1::UPayloadFormat format) {
if (!UPayloadFormat_IsValid(format)) {
throw std::out_of_range("Invalid String payload format");
}
payload_ = std::make_tuple(std::move(value), format);
}

// Move string constructor
Payload::Payload(std::string&& value, const v1::UPayloadFormat format) {
if (!UPayloadFormat_IsValid(format)) {
throw std::out_of_range("Invalid RValue String payload format");
}
payload_ = std::make_tuple(std::move(value), format);
}

// Move Serialized constructor
Payload::Payload(Serialized&& serialized) {
if (!UPayloadFormat_IsValid(std::get<PayloadType::Format>(serialized))) {
throw std::out_of_range("Invalid RValue Serialized payload format");
}
payload_ = std::move(serialized);
}

// Move constructor
Payload::Payload(Payload&& other) noexcept
: payload_(std::move(other.payload_)), moved_(std::move(other.moved_)) {}

// Copy constructor
Payload::Payload(const Payload& other)
: payload_(other.payload_), moved_(other.moved_) {}

// Move assignment operator
Payload& Payload::operator=(Payload&& other) noexcept {
payload_ = std::move(other.payload_);
moved_ = std::move(other.moved_);
return *this;
}

// Copy assignment operator
Payload& Payload::operator=(const Payload& other) {
payload_ = other.payload_;
moved_ = other.moved_;
return *this;
}

Payload::PayloadMoved::PayloadMoved(PayloadMoved&& other) noexcept
: std::runtime_error(std::move(other)) {}

// PayloadMoved move assignment operator
Payload::PayloadMoved& Payload::PayloadMoved::operator=(
PayloadMoved&& other) noexcept {
std::runtime_error::operator=(std::move(other));
return *this;
}

// PayloadMoved copy constructor
Payload::PayloadMoved::PayloadMoved(const PayloadMoved& other)
: std::runtime_error(other) {}

// PayloadMoved copy assignment operator
Payload::PayloadMoved& Payload::PayloadMoved::operator=(
const PayloadMoved& other) {
std::runtime_error::operator=(other);
return *this;
}

// buildCopy method
[[nodiscard]] const Payload::Serialized& Payload::buildCopy() const {
if (moved_) {
throw PayloadMoved("Payload has been already moved");
}
return payload_;
}

// buildMove method
[[nodiscard]] Payload::Serialized Payload::buildMove() && {
// Check if payload_ is in the "moved" state
if (moved_) {
throw PayloadMoved("Payload has been already moved");
}
// Set payload_ to the "moved" state
moved_ = true;
return std::move(payload_);
}
} // namespace uprotocol::datamodel::builder
Loading

0 comments on commit cba9666

Please sign in to comment.