blob: e0a514ff78d0b45adbd690d8b283af6cbdd82d93 [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 "pw_bytes/span.h"
#include "pw_rpc/internal/base_server_writer.h"
#include "pw_rpc/internal/method.h"
#include "pw_rpc/internal/method_type.h"
#include "pw_status/status_with_size.h"
namespace pw::rpc {
class RawServerWriter : public internal::BaseServerWriter {
public:
RawServerWriter() = default;
// Returns a buffer in which a response payload can be built.
ByteSpan PayloadBuffer() { return AcquirePayloadBuffer(); }
// Sends a response packet with the given raw payload. The payload can either
// be in the buffer previously acquired from PayloadBuffer(), or an arbitrary
// external buffer.
Status Write(ConstByteSpan response);
};
namespace internal {
// A RawMethod is a method invoker which does not perform any automatic protobuf
// serialization or deserialization. The implementer is given the raw binary
// payload of incoming requests, and is responsible for encoding responses to a
// provided buffer. This is intended for use in methods which would have large
// protobuf data structure overhead to lower stack usage, or in methods packing
// responses up to a channel's MTU.
class RawMethod : public Method {
public:
template <auto method>
constexpr static RawMethod Unary(uint32_t id) {
return RawMethod(
id,
UnaryInvoker,
{.unary = [](ServerCall& call, ConstByteSpan req, ByteSpan res) {
return method(call, req, res);
}});
}
template <auto method>
constexpr static RawMethod ServerStreaming(uint32_t id) {
return RawMethod(id,
ServerStreamingInvoker,
Function{.server_streaming = [](ServerCall& call,
ConstByteSpan req,
BaseServerWriter& writer) {
method(call, req, static_cast<RawServerWriter&>(writer));
}});
}
private:
using UnaryFunction = StatusWithSize (*)(ServerCall&,
ConstByteSpan,
ByteSpan);
using ServerStreamingFunction = void (*)(ServerCall&,
ConstByteSpan,
BaseServerWriter&);
union Function {
UnaryFunction unary;
ServerStreamingFunction server_streaming;
// TODO(frolv): Support client and bidirectional streaming.
};
constexpr RawMethod(uint32_t id, Invoker invoker, Function function)
: Method(id, invoker), function_(function) {}
static void UnaryInvoker(const Method& method,
ServerCall& call,
const Packet& request) {
static_cast<const RawMethod&>(method).CallUnary(call, request);
}
static void ServerStreamingInvoker(const Method& method,
ServerCall& call,
const Packet& request) {
static_cast<const RawMethod&>(method).CallServerStreaming(call, request);
}
void CallUnary(ServerCall& call, const Packet& request) const;
void CallServerStreaming(ServerCall& call, const Packet& request) const;
// Stores the user-defined RPC in a generic wrapper.
Function function_;
};
} // namespace internal
} // namespace pw::rpc