Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add protobuf/echo/ProtoMessageBuilder #416

Merged
merged 25 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
caf1d6d
feat: add protobuf/echo/ProtoMessageBuilder
richardapeters Sep 14, 2023
3659327
ProtoCEchoPlugin: Fix superfluous typename
richardapeters Sep 14, 2023
4850e98
protobuf/echoProtoMessageBuilder: Parse a lot of different types
richardapeters Sep 17, 2023
7ad854d
protobuf/echoProtoMessageBuilder: Parse enums, strings, extract Bufer…
richardapeters Sep 17, 2023
7af4bfd
Resolve code warnings, increase coverage
richardapeters Sep 17, 2023
7143d43
protobuf/echo: Add BufferingStreamWriter
richardapeters Sep 18, 2023
9f6c3ad
protobuf/echo: Add half of ProtoMessageSender
richardapeters Sep 18, 2023
5c9f178
protobuf/echo/ProtoMessageSender: Serialize lots of types
richardapeters Sep 21, 2023
2b44b0f
protobuf/echo/ProtoMessageSender: Fix missing template keyword
richardapeters Sep 21, 2023
50f67fa
protobuf/echo/ProtoMessageSender: Serialize lots of types
richardapeters Sep 21, 2023
f3b4b37
protobuf/protoc_echo_plugin/ProtoCEchoPlugin: Modify result of Messag…
richardapeters Sep 21, 2023
7ff3ff4
Apply suggestions from code review
richardapeters Sep 21, 2023
4d866f2
protobuf/echo/BufferingStreamReader: Make BufferingStreamReader accep…
richardapeters Sep 22, 2023
e216526
protobuf/echo/BufferingStreamReader: Remove useless comment
richardapeters Sep 22, 2023
88b5d8a
Resolve Sonar warnings
richardapeters Sep 23, 2023
67182ec
Resolve Sonar warnings
richardapeters Sep 24, 2023
62b5a07
Move BufferingSteamReader and BufferingStreamWriter to infra/stream
richardapeters Sep 25, 2023
d6cf3e4
infra/stream/test: Add tests for BufferingStreamReader and BufferingS…
richardapeters Sep 26, 2023
cf83d99
Apply suggestions from code review
richardapeters Sep 26, 2023
7ec732d
Resolve Sonar warnings
richardapeters Sep 26, 2023
3625a48
Resolve Sonar warnings
richardapeters Sep 27, 2023
a0b2451
Resolve Sonar warnings
richardapeters Sep 27, 2023
2b8cfea
Reduce duplication
richardapeters Sep 28, 2023
84d2f94
Update services/network/test_doubles/Certificates.cpp
richardapeters Sep 28, 2023
9cc8c23
Merge branch 'main' into feature/proto_message_builder
rjaegers Sep 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion protobuf/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
add_subdirectory(echo)
add_subdirectory(echo_attributes)
add_subdirectory(echo)
add_subdirectory(protoc_echo_plugin)
add_subdirectory(protoc_echo_plugin_csharp)
add_subdirectory(protoc_echo_plugin_java)
2 changes: 2 additions & 0 deletions protobuf/echo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ target_link_libraries(protobuf.echo PUBLIC
target_sources(protobuf.echo PRIVATE
Echo.cpp
Echo.hpp
ProtoMessageBuilder.cpp
ProtoMessageBuilder.hpp
ServiceForwarder.cpp
ServiceForwarder.hpp
TracingEcho.cpp
Expand Down
102 changes: 102 additions & 0 deletions protobuf/echo/ProtoMessageBuilder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "protobuf/echo/ProtoMessageBuilder.hpp"

namespace services
{
BufferingStreamReader::BufferingStreamReader(infra::BoundedDeque<uint8_t>& buffer, infra::ConstByteRange data)
: buffer(buffer)
, data(data)
{}

void BufferingStreamReader::ConsumeCurrent()
{
std::size_t bufferDecrease = std::min(buffer.size(), index);
buffer.erase(buffer.begin(), buffer.begin() + bufferDecrease);
index -= bufferDecrease;

data.pop_front(index);
index = 0;
}

void BufferingStreamReader::StoreRemainder()
{
buffer.insert(buffer.end(), data.begin(), data.end());
}

void BufferingStreamReader::Extract(infra::ByteRange range, infra::StreamErrorPolicy& errorPolicy)
{
if (index != buffer.size())
{
auto from = infra::Head(buffer.contiguous_range(buffer.begin() + index), range.size());
infra::Copy(from, infra::Head(range, from.size()));
range.pop_front(from.size());
index += from.size();

// Perhaps the deque just wrapped around, try once more
from = infra::Head(buffer.contiguous_range(buffer.begin() + index), range.size());
infra::Copy(from, infra::Head(range, from.size()));
range.pop_front(from.size());
index += from.size();
}

if (!range.empty())
{
auto dataIndex = index - buffer.size();
auto from = infra::Head(infra::DiscardHead(data, dataIndex), range.size());
infra::Copy(from, infra::Head(range, from.size()));
range.pop_front(from.size());
index += from.size();
}

errorPolicy.ReportResult(range.empty());
}

uint8_t BufferingStreamReader::Peek(infra::StreamErrorPolicy& errorPolicy)
{
auto range = PeekContiguousRange(0);

errorPolicy.ReportResult(!range.empty());

if (range.empty())
return 0;
else
return range.front();
}

infra::ConstByteRange BufferingStreamReader::ExtractContiguousRange(std::size_t max)
{
if (index < buffer.size())
{
auto from = infra::Head(buffer.contiguous_range(buffer.begin() + index), max);
index += from.size();
return from;
}

auto dataIndex = index - buffer.size();
auto from = infra::Head(infra::DiscardHead(data, dataIndex), max);
index += from.size();
return from;
}

infra::ConstByteRange BufferingStreamReader::PeekContiguousRange(std::size_t start)
{
if (index + start < buffer.size())
{
auto from = buffer.contiguous_range(buffer.begin() + index + start);
return from;
}

auto dataIndex = index + start - buffer.size();
auto from = infra::DiscardHead(data, dataIndex);
return from;
}

bool BufferingStreamReader::Empty() const
{
return Available() == 0;
}

std::size_t BufferingStreamReader::Available() const
{
return buffer.size() + data.size() - index;
}
}
82 changes: 82 additions & 0 deletions protobuf/echo/ProtoMessageBuilder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#ifndef PROTOBUF_PROTO_MESSAGE_BUILDER_HPP
#define PROTOBUF_PROTO_MESSAGE_BUILDER_HPP

#include "infra/stream/ByteInputStream.hpp"
#include "infra/syntax/ProtoParser.hpp"
#include "infra/util/BoundedDeque.hpp"

namespace services
{
class BufferingStreamReader
: public infra::StreamReader
{
public:
BufferingStreamReader(infra::BoundedDeque<uint8_t>& buffer, infra::ConstByteRange data);

void ConsumeCurrent();
void StoreRemainder();

// Implementation of StreamReader
void Extract(infra::ByteRange range, infra::StreamErrorPolicy& errorPolicy) override;
uint8_t Peek(infra::StreamErrorPolicy& errorPolicy) override;
infra::ConstByteRange ExtractContiguousRange(std::size_t max) override;
infra::ConstByteRange PeekContiguousRange(std::size_t start) override;
bool Empty() const override;
std::size_t Available() const override;

private:
infra::BoundedDeque<uint8_t>& buffer;
infra::ConstByteRange data;
std::size_t index = 0;
};

template<class Message>
class ProtoMessageBuilder
{
public:
void Feed(infra::ConstByteRange data);

public:
Message message;

private:
infra::BoundedDeque<uint8_t>::WithMaxSize<16> buffer;
};
}

//// Implementation ////

namespace services
{
template<class Message>
void ProtoMessageBuilder<Message>::Feed(infra::ConstByteRange data)
{
BufferingStreamReader reader{ buffer, data };
infra::DataInputStream::WithErrorPolicy stream{ reader, infra::softFail };
infra::ProtoParser parser{ stream };

while (true)
{
auto field = parser.GetField();
switch (field.second)
{
case Message::template fieldNumber<0>:
DeserializeField(Message::template ProtoType<0>(), parser, field, message.value);
break;
// default:
// if (field.first.Is<infra::ProtoLengthDelimited>())
// field.first.Get<infra::ProtoLengthDelimited>().SkipEverything();
// break;
richardapeters marked this conversation as resolved.
Show resolved Hide resolved
}

if (stream.Failed())
break;

reader.ConsumeCurrent();
}

reader.StoreRemainder();
}
}

#endif
3 changes: 3 additions & 0 deletions protobuf/echo/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ add_executable(protobuf.echo_test)
emil_build_for(protobuf.echo_test BOOL EMIL_BUILD_TESTS)
emil_add_test(protobuf.echo_test)

protocol_buffer_echo_cpp(protobuf.echo_test TestMessages.proto)

target_sources(protobuf.echo_test PRIVATE
TestEchoServiceResponseQueue.cpp
TestProtoMessageBuilder.cpp
TestServiceForwarder.cpp
)

Expand Down
170 changes: 170 additions & 0 deletions protobuf/echo/test/TestMessages.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
syntax = "proto3";

import "EchoAttributes.proto";

package test_messages;
option java_package = "com.philips.emil.protobufEcho";
option java_outer_classname = "TestMessagesProto";

enum Enumeration {
val0 = 0;
val1 = 1;
}

message TestEnum {
Enumeration e = 1;
}

message TestInt32 {
int32 value = 1;
}

message TestInt64 {
int64 value = 1;
}

message TestUInt32 {
uint32 value = 1;
}

message TestUInt64 {
uint64 value = 1;
}

message TestFixed32 {
fixed32 value = 1;
}

message TestFixed64 {
sfixed64 value = 1;
}

message TestSFixed64 {
fixed64 value = 1;
}

message TestSFixed32 {
sfixed32 value = 1;
}

message TestBool {
bool value = 1;
}

message TestString {
string value = 1 [(string_size) = 20];
}

message TestStdString {
string value = 1;
}

message TestRepeatedString {
repeated string value = 1 [(string_size) = 20, (array_size) = 10];
}

message TestBytes {
bytes value = 1 [(bytes_size) = 10];
}

message TestUnboundedBytes {
bytes value = 1;
}

message TestRepeatedUInt32 {
repeated uint32 value = 1 [(array_size) = 10];
}

message TestMessageWithMessageField {
TestUInt32 message = 1;
}

message TestRepeatedEverything {
repeated Enumeration v1 = 1 [(array_size) = 10];
repeated int32 v2 = 2 [(array_size) = 10];
repeated int64 v3 = 3 [(array_size) = 10];
repeated uint32 v4 = 4 [(array_size) = 10];
repeated uint64 v5 = 5 [(array_size) = 10];
repeated fixed32 v6 = 6 [(array_size) = 10];
repeated sfixed64 v7 = 7 [(array_size) = 10];
repeated fixed64 v8 = 8 [(array_size) = 10];
repeated sfixed32 v9 = 9 [(array_size) = 10];
repeated bool v10 = 10 [(array_size) = 10];
repeated string v11 = 11 [(string_size) = 20, (array_size) = 10];
repeated string v12 = 12 [(array_size) = 10];
repeated TestUInt32 v13 = 13 [(array_size) = 10];
repeated bytes v14 = 14 [(bytes_size) = 10, (array_size) = 10];
repeated bytes v15 = 15 [(array_size) = 10];
}

message TestUnboundedRepeatedEverything {
repeated Enumeration v1 = 1;
repeated int32 v2 = 2;
repeated int64 v3 = 3;
repeated uint32 v4 = 4;
repeated uint64 v5 = 5;
repeated fixed32 v6 = 6;
repeated sfixed64 v7 = 7;
repeated fixed64 v8 = 8;
repeated sfixed32 v9 = 9;
repeated bool v10 = 10;
repeated string v11 = 11 [(string_size) = 20];
repeated string v12 = 12;
repeated TestUInt32 v13 = 13;
repeated bytes v14 = 14 [(bytes_size) = 10];
repeated bytes v15 = 15;
}

message TestNestedMessage
{
message NestedMessage
{
uint32 value = 1;
}

NestedMessage message = 1;
}

message TestMoreNestedMessage
{
message NestedMessage1
{
uint32 value = 1;
}

message NestedMessage2
{
uint32 value = 2;
}

NestedMessage1 message1 = 1;
NestedMessage2 message2 = 2;
}

message TestNestedRepeatedMessage
{
message NestedMessage
{
uint32 value = 1;
}

repeated NestedMessage message = 1 [(array_size) = 10];
}

message TestEmptyMessage
{
}

service TestService1
{
option (service_id) = 1;

rpc Method(TestUInt32) returns (Nothing) { option (method_id) = 1; }
}

service TestService2
{
option (service_id) = 2;

rpc Search (TestString) returns (Nothing) { option (method_id) = 1; }
}
Loading
Loading