blob: abceb3554b79542da1ec188dd3330a4d34be194c [file] [log] [blame]
// Copyright 2020 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 "pb_common.h"
#include "pw_bytes/span.h"
#include "pw_rpc/internal/lock.h"
#include "pw_status/status_with_size.h"
namespace pw::rpc::internal {
// Nanopb 0.3 uses pb_field_t, but Nanopb 4 uses pb_msgdesc_t. Determine which
// type to use by deducing it from the pb_field_iter_begin function.
template <typename PbFieldIterBeginFunction>
struct NanopbDescriptorTraits;
template <typename T>
struct NanopbDescriptorTraits<bool(pb_field_iter_t*, T, void*)> {
using Type = T;
};
using NanopbMessageDescriptor =
NanopbDescriptorTraits<decltype(pb_field_iter_begin)>::Type;
// Serializer/deserializer for a Nanopb protobuf message.
class NanopbSerde {
public:
explicit constexpr NanopbSerde(NanopbMessageDescriptor fields)
: fields_(fields) {}
NanopbSerde(const NanopbSerde&) = default;
NanopbSerde& operator=(const NanopbSerde&) = default;
// Encodes a Nanopb protobuf struct to the serialized wire format.
StatusWithSize Encode(const void* proto_struct, ByteSpan buffer) const;
// Decodes a serialized protobuf to a Nanopb struct.
bool Decode(ConstByteSpan buffer, void* proto_struct) const;
private:
NanopbMessageDescriptor fields_;
};
// Serializer/deserializer for Nanopb message request and response structs in an
// RPC method.
class NanopbMethodSerde {
public:
constexpr NanopbMethodSerde(NanopbMessageDescriptor request_fields,
NanopbMessageDescriptor response_fields)
: request_fields_(request_fields), response_fields_(response_fields) {}
NanopbMethodSerde(const NanopbMethodSerde&) = delete;
NanopbMethodSerde& operator=(const NanopbMethodSerde&) = delete;
StatusWithSize EncodeRequest(const void* proto_struct,
ByteSpan buffer) const {
return request_fields_.Encode(proto_struct, buffer);
}
StatusWithSize EncodeResponse(const void* proto_struct,
ByteSpan buffer) const {
return response_fields_.Encode(proto_struct, buffer);
}
bool DecodeRequest(ConstByteSpan buffer, void* proto_struct) const {
return request_fields_.Decode(buffer, proto_struct);
}
bool DecodeResponse(ConstByteSpan buffer, void* proto_struct) const {
return response_fields_.Decode(buffer, proto_struct);
}
const NanopbSerde& request() const { return request_fields_; }
const NanopbSerde& response() const { return response_fields_; }
private:
NanopbSerde request_fields_;
NanopbSerde response_fields_;
};
template <NanopbMessageDescriptor kRequest, NanopbMessageDescriptor kResponse>
inline constexpr NanopbMethodSerde kNanopbMethodSerde(kRequest, kResponse);
class Call;
class ClientCall;
class NanopbServerCall;
// [Client] Encodes and sends the initial request message for the call.
// active() must be true.
void NanopbSendInitialRequest(ClientCall& call,
NanopbSerde serde,
const void* payload)
PW_UNLOCK_FUNCTION(rpc_lock());
// [Client/Server] Encodes and sends a client or server stream message.
// active() must be true.
Status NanopbSendStream(Call& call, const void* payload, NanopbSerde serde)
PW_LOCKS_EXCLUDED(rpc_lock());
// [Server] Encodes and sends the final response message.
// Returns Status::FailedPrecondition if active() is false.
Status SendFinalResponse(NanopbServerCall& call,
const void* payload,
Status status) PW_LOCKS_EXCLUDED(rpc_lock());
} // namespace pw::rpc::internal