Skip to content

Commit

Permalink
pw_rpc: Publicly expose pwpb method serde
Browse files Browse the repository at this point in the history
These functions are useful for reading the contents of packets without
going through full pw_rpc packet processing.

Change-Id: Icf0294a69455f70de102ea382b5c65fa1b3789a5
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/112711
Reviewed-by: Wyatt Hepler <[email protected]>
Commit-Queue: Taylor Cramer <[email protected]>
  • Loading branch information
cramertj authored and CQ Bot Account committed Sep 30, 2022
1 parent 7bc5058 commit 2b3de52
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 105 deletions.
5 changes: 5 additions & 0 deletions pw_rpc/public/pw_rpc/method_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ using MethodRequestType = typename internal::MethodInfo<kMethod>::Request;
template <auto kMethod>
using MethodResponseType = typename internal::MethodInfo<kMethod>::Response;

// Function which returns a serializer for given kMethod.
// For e.g. `pwpb` methods, this returns a `const PwpbMethodSerde&`.
template <auto kMethod>
using MethodSerde = typename internal::MethodInfo<kMethod>::serde;

} // namespace pw::rpc
1 change: 1 addition & 0 deletions pw_rpc/pwpb/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pw_cc_library(
name = "common",
hdrs = [
"public/pw_rpc/pwpb/internal/common.h",
"public/pw_rpc/pwpb/serde.h",
"public/pw_rpc/pwpb/server_reader_writer.h",
],
includes = ["public"],
Expand Down
5 changes: 4 additions & 1 deletion pw_rpc/pwpb/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ pw_source_set("common") {
dir_pw_log,
dir_pw_stream,
]
public = [ "public/pw_rpc/pwpb/internal/common.h" ]
public = [
"public/pw_rpc/pwpb/internal/common.h",
"public/pw_rpc/pwpb/serde.h",
]
}

pw_source_set("test_method_context") {
Expand Down
8 changes: 4 additions & 4 deletions pw_rpc/pwpb/public/pw_rpc/pwpb/client_reader_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ class PwpbClientReaderWriter
uint32_t channel_id_v,
uint32_t service_id,
uint32_t method_id,
const internal::PwpbMethodSerde& serde)
const PwpbMethodSerde& serde)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
: internal::PwpbStreamResponseClientCall<Response>(
client,
Expand Down Expand Up @@ -372,7 +372,7 @@ class PwpbClientReader
uint32_t channel_id_v,
uint32_t service_id,
uint32_t method_id,
const internal::PwpbMethodSerde& serde)
const PwpbMethodSerde& serde)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
: internal::PwpbStreamResponseClientCall<Response>(
client,
Expand Down Expand Up @@ -429,7 +429,7 @@ class PwpbClientWriter
uint32_t channel_id_v,
uint32_t service_id,
uint32_t method_id,
const internal::PwpbMethodSerde& serde)
const PwpbMethodSerde& serde)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())

: internal::PwpbUnaryResponseClientCall<Response>(
Expand Down Expand Up @@ -473,7 +473,7 @@ class PwpbUnaryReceiver
uint32_t channel_id_v,
uint32_t service_id,
uint32_t method_id,
const internal::PwpbMethodSerde& serde)
const PwpbMethodSerde& serde)
PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
: internal::PwpbUnaryResponseClientCall<Response>(client,
channel_id_v,
Expand Down
11 changes: 5 additions & 6 deletions pw_rpc/pwpb/public/pw_rpc/pwpb/fake_channel_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,12 @@ class PwpbPayloadsView {
private:
friend class PwpbPayloadsView;

constexpr iterator(const PayloadsView::iterator& it,
const internal::PwpbSerde& serde)
constexpr iterator(const PayloadsView::iterator& it, const PwpbSerde& serde)
: containers::
WrappedIterator<iterator, PayloadsView::iterator, Payload>(it),
serde_(serde) {}

internal::PwpbSerde serde_;
PwpbSerde serde_;
};

Payload operator[](size_t index) const {
Expand All @@ -94,11 +93,11 @@ class PwpbPayloadsView {
friend class PwpbFakeChannelOutput;

template <typename... Args>
PwpbPayloadsView(const internal::PwpbSerde& serde, Args&&... args)
PwpbPayloadsView(const PwpbSerde& serde, Args&&... args)
: view_(args...), serde_(serde) {}

PayloadsView view_;
internal::PwpbSerde serde_;
PwpbSerde serde_;
};

// A ChannelOutput implementation that stores the outgoing payloads and status.
Expand Down Expand Up @@ -191,7 +190,7 @@ class PwpbFakeChannelOutput final
// synchronized! The PwpbPayloadsView is immediately invalidated if any
// thread accesses the FakeChannelOutput.
template <typename T>
PwpbPayloadsView<T> payload_structs(const internal::PwpbSerde& serde,
PwpbPayloadsView<T> payload_structs(const PwpbSerde& serde,
MethodType type,
uint32_t channel_id,
uint32_t service_id,
Expand Down
94 changes: 1 addition & 93 deletions pw_rpc/pwpb/public/pw_rpc/pwpb/internal/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,105 +20,13 @@
#include "pw_protobuf/stream_decoder.h"
#include "pw_rpc/internal/client_call.h"
#include "pw_rpc/internal/server_call.h"
#include "pw_rpc/pwpb/serde.h"
#include "pw_span/span.h"
#include "pw_status/status.h"
#include "pw_status/status_with_size.h"

namespace pw::rpc::internal {

using PwpbMessageDescriptor =
const span<const protobuf::internal::MessageField>*;

// Serializer/deserializer for a pw_protobuf message.
class PwpbSerde {
public:
explicit constexpr PwpbSerde(PwpbMessageDescriptor table) : table_(table) {}

PwpbSerde(const PwpbSerde&) = default;
PwpbSerde& operator=(const PwpbSerde&) = default;

// Encodes a pw_protobuf struct to the serialized wire format.
template <typename Message>
StatusWithSize Encode(const Message& message, ByteSpan buffer) const {
return Encoder(buffer).Write(as_bytes(span(&message, 1)), table_);
}

// Decodes a serialized protobuf into a pw_protobuf message struct.
template <typename Message>
Status Decode(ConstByteSpan buffer, Message& message) const {
return Decoder(buffer).Read(as_writable_bytes(span(&message, 1)), table_);
}

private:
class Encoder : public protobuf::MemoryEncoder {
public:
constexpr Encoder(ByteSpan buffer) : protobuf::MemoryEncoder(buffer) {}

StatusWithSize Write(ConstByteSpan message, PwpbMessageDescriptor table) {
const auto status = protobuf::MemoryEncoder::Write(message, *table);
return StatusWithSize(status, size());
}
};

class Decoder : public protobuf::StreamDecoder {
public:
constexpr Decoder(ConstByteSpan buffer)
: protobuf::StreamDecoder(reader_), reader_(buffer) {}

Status Read(ByteSpan message, PwpbMessageDescriptor table) {
return protobuf::StreamDecoder::Read(message, *table);
}

private:
stream::MemoryReader reader_;
};

PwpbMessageDescriptor table_;
};

// Serializer/deserializer for pw_protobuf request and response message structs
// within an RPC method.
class PwpbMethodSerde {
public:
constexpr PwpbMethodSerde(PwpbMessageDescriptor request_table,
PwpbMessageDescriptor response_table)
: request_serde_(request_table), response_serde_(response_table) {}

PwpbMethodSerde(const PwpbMethodSerde&) = delete;
PwpbMethodSerde& operator=(const PwpbMethodSerde&) = delete;

// Encodes the pw_protobuf request struct to the serialized wire format.
template <typename Request>
StatusWithSize EncodeRequest(const Request& request, ByteSpan buffer) const {
return request_serde_.Encode(request, buffer);
}

// Encodes the pw_protobuf response struct to the serialized wire format.
template <typename Response>
StatusWithSize EncodeResponse(const Response& response,
ByteSpan buffer) const {
return response_serde_.Encode(response, buffer);
}
// Decodes a serialized protobuf into the pw_protobuf request struct.
template <typename Request>
Status DecodeRequest(ConstByteSpan buffer, Request& request) const {
return request_serde_.Decode(buffer, request);
}

// Decodes a serialized protobuf into the pw_protobuf response struct.
template <typename Response>
Status DecodeResponse(ConstByteSpan buffer, Response& response) const {
return response_serde_.Decode(buffer, response);
}

const PwpbSerde& request() const { return request_serde_; }
const PwpbSerde& response() const { return response_serde_; }

private:
PwpbSerde request_serde_;
PwpbSerde response_serde_;
};

// Defines per-message struct type instance of the serializer/deserializer.
template <PwpbMessageDescriptor kRequest, PwpbMessageDescriptor kResponse>
constexpr PwpbMethodSerde kPwpbMethodSerde(kRequest, kResponse);
Expand Down
116 changes: 116 additions & 0 deletions pw_rpc/pwpb/public/pw_rpc/pwpb/serde.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2022 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once

#include "pw_protobuf/encoder.h"
#include "pw_protobuf/internal/codegen.h"
#include "pw_protobuf/stream_decoder.h"
#include "pw_span/span.h"

namespace pw::rpc {

using PwpbMessageDescriptor =
const span<const protobuf::internal::MessageField>*;

// Serializer/deserializer for a pw_protobuf message.
class PwpbSerde {
public:
explicit constexpr PwpbSerde(PwpbMessageDescriptor table) : table_(table) {}

PwpbSerde(const PwpbSerde&) = default;
PwpbSerde& operator=(const PwpbSerde&) = default;

// Encodes a pw_protobuf struct to the serialized wire format.
template <typename Message>
StatusWithSize Encode(const Message& message, ByteSpan buffer) const {
return Encoder(buffer).Write(as_bytes(span(&message, 1)), table_);
}

// Decodes a serialized protobuf into a pw_protobuf message struct.
template <typename Message>
Status Decode(ConstByteSpan buffer, Message& message) const {
return Decoder(buffer).Read(as_writable_bytes(span(&message, 1)), table_);
}

private:
class Encoder : public protobuf::MemoryEncoder {
public:
constexpr Encoder(ByteSpan buffer) : protobuf::MemoryEncoder(buffer) {}

StatusWithSize Write(ConstByteSpan message, PwpbMessageDescriptor table) {
const auto status = protobuf::MemoryEncoder::Write(message, *table);
return StatusWithSize(status, size());
}
};

class Decoder : public protobuf::StreamDecoder {
public:
constexpr Decoder(ConstByteSpan buffer)
: protobuf::StreamDecoder(reader_), reader_(buffer) {}

Status Read(ByteSpan message, PwpbMessageDescriptor table) {
return protobuf::StreamDecoder::Read(message, *table);
}

private:
stream::MemoryReader reader_;
};

PwpbMessageDescriptor table_;
};

// Serializer/deserializer for pw_protobuf request and response message structs
// within an RPC method.
class PwpbMethodSerde {
public:
constexpr PwpbMethodSerde(PwpbMessageDescriptor request_table,
PwpbMessageDescriptor response_table)
: request_serde_(request_table), response_serde_(response_table) {}

PwpbMethodSerde(const PwpbMethodSerde&) = delete;
PwpbMethodSerde& operator=(const PwpbMethodSerde&) = delete;

// Encodes the pw_protobuf request struct to the serialized wire format.
template <typename Request>
StatusWithSize EncodeRequest(const Request& request, ByteSpan buffer) const {
return request_serde_.Encode(request, buffer);
}

// Encodes the pw_protobuf response struct to the serialized wire format.
template <typename Response>
StatusWithSize EncodeResponse(const Response& response,
ByteSpan buffer) const {
return response_serde_.Encode(response, buffer);
}
// Decodes a serialized protobuf into the pw_protobuf request struct.
template <typename Request>
Status DecodeRequest(ConstByteSpan buffer, Request& request) const {
return request_serde_.Decode(buffer, request);
}

// Decodes a serialized protobuf into the pw_protobuf response struct.
template <typename Response>
Status DecodeResponse(ConstByteSpan buffer, Response& response) const {
return response_serde_.Decode(buffer, response);
}

const PwpbSerde& request() const { return request_serde_; }
const PwpbSerde& response() const { return response_serde_; }

private:
PwpbSerde request_serde_;
PwpbSerde response_serde_;
};

} // namespace pw::rpc
2 changes: 1 addition & 1 deletion pw_rpc/py/pw_rpc/codegen_pwpb.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def method_info_specialization(self, method: ProtoServiceMethod) -> None:
self.line(f'using Request = {method.request_type().pwpb_struct()};')
self.line(f'using Response = {method.response_type().pwpb_struct()};')
self.line()
self.line(f'static constexpr const {RPC_NAMESPACE}::internal::'
self.line(f'static constexpr const {RPC_NAMESPACE}::'
'PwpbMethodSerde& serde() {')
with self.indent():
self.line(f'return {_serde(method)};')
Expand Down

0 comments on commit 2b3de52

Please sign in to comment.