diff --git a/pw_rpc/public/pw_rpc/method_info.h b/pw_rpc/public/pw_rpc/method_info.h index 4caddf2051..714c7d3ccf 100644 --- a/pw_rpc/public/pw_rpc/method_info.h +++ b/pw_rpc/public/pw_rpc/method_info.h @@ -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 diff --git a/pw_rpc/pwpb/BUILD.bazel b/pw_rpc/pwpb/BUILD.bazel index ae13ccb203..786b03cd0f 100644 --- a/pw_rpc/pwpb/BUILD.bazel +++ b/pw_rpc/pwpb/BUILD.bazel @@ -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"], diff --git a/pw_rpc/pwpb/BUILD.gn b/pw_rpc/pwpb/BUILD.gn index 8a4342b698..0f862a55d6 100644 --- a/pw_rpc/pwpb/BUILD.gn +++ b/pw_rpc/pwpb/BUILD.gn @@ -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") { diff --git a/pw_rpc/pwpb/public/pw_rpc/pwpb/client_reader_writer.h b/pw_rpc/pwpb/public/pw_rpc/pwpb/client_reader_writer.h index ec590446fd..2071e5975d 100644 --- a/pw_rpc/pwpb/public/pw_rpc/pwpb/client_reader_writer.h +++ b/pw_rpc/pwpb/public/pw_rpc/pwpb/client_reader_writer.h @@ -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, @@ -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, @@ -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>( @@ -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, diff --git a/pw_rpc/pwpb/public/pw_rpc/pwpb/fake_channel_output.h b/pw_rpc/pwpb/public/pw_rpc/pwpb/fake_channel_output.h index 27e0ca4a66..d26994198c 100644 --- a/pw_rpc/pwpb/public/pw_rpc/pwpb/fake_channel_output.h +++ b/pw_rpc/pwpb/public/pw_rpc/pwpb/fake_channel_output.h @@ -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 { @@ -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. @@ -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, diff --git a/pw_rpc/pwpb/public/pw_rpc/pwpb/internal/common.h b/pw_rpc/pwpb/public/pw_rpc/pwpb/internal/common.h index 16f284743b..18a0052a3f 100644 --- a/pw_rpc/pwpb/public/pw_rpc/pwpb/internal/common.h +++ b/pw_rpc/pwpb/public/pw_rpc/pwpb/internal/common.h @@ -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); diff --git a/pw_rpc/pwpb/public/pw_rpc/pwpb/serde.h b/pw_rpc/pwpb/public/pw_rpc/pwpb/serde.h new file mode 100644 index 0000000000..74ed63d8b8 --- /dev/null +++ b/pw_rpc/pwpb/public/pw_rpc/pwpb/serde.h @@ -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 diff --git a/pw_rpc/py/pw_rpc/codegen_pwpb.py b/pw_rpc/py/pw_rpc/codegen_pwpb.py index df17090b06..0dc753bcf2 100644 --- a/pw_rpc/py/pw_rpc/codegen_pwpb.py +++ b/pw_rpc/py/pw_rpc/codegen_pwpb.py @@ -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)};')