Skip to content

Commit

Permalink
pw_rpc: Reduce duplication in synchronous call wrappers
Browse files Browse the repository at this point in the history
Update the struct-based synchronous call wrappers to share their
implementations with the raw wrappers.

Change-Id: I94750e9fc7c733a42f5b231d9856ca42878920c7
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/136731
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
  • Loading branch information
255 authored and CQ Bot Account committed Apr 14, 2023
1 parent da440ea commit a51901f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 114 deletions.
41 changes: 34 additions & 7 deletions pw_rpc/public/pw_rpc/internal/synchronous_call_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,27 @@ inline bool AcquireNotification(sync::TimedThreadNotification& notification,
return notification.try_acquire_until(timeout);
}

template <auto kRpcMethod, typename DoCall, typename... TimeoutArg>
SynchronousCallResult<typename MethodInfo<kRpcMethod>::Response>
StructSynchronousCall(DoCall&& do_call, TimeoutArg... timeout_arg) {
static_assert(MethodInfo<kRpcMethod>::kType == MethodType::kUnary,
"Only unary methods can be used with synchronous calls");
using Response = typename MethodInfo<kRpcMethod>::Response;

SynchronousCallState<Response> call_state;

auto call = std::forward<DoCall>(do_call)(call_state);

// Wait for the notification based on the type of the timeout argument.
if constexpr (sizeof...(TimeoutArg) == 0) {
call_state.notify.acquire(); // Wait forever, since no timeout was given.
} else if (!AcquireNotification(call_state.notify, timeout_arg...)) {
return SynchronousCallResult<Response>::Timeout();
}

return std::move(call_state.result);
}

// Template for a raw synchronous call. Used for SynchronousCall,
// SynchronousCallFor, and SynchronousCallUntil. The type of the timeout
// argument is used to determine the behavior.
Expand All @@ -104,13 +125,19 @@ Status RawSynchronousCall(Function<void(ConstByteSpan, Status)>&& on_completed,
return call_state.error;
}

// Invokes the RPC method free function using a call_state.
// Choose which call state object to use (raw or struct).
template <auto kRpcMethod>
using CallState = std::conditional_t<
std::is_same_v<typename MethodInfo<kRpcMethod>::Request, void>,
RawSynchronousCallState,
SynchronousCallState<typename MethodInfo<kRpcMethod>::Response>>;

// Invokes the RPC method free function using a call_state.
template <auto kRpcMethod, typename Request>
constexpr auto CallFreeFunction(Client& client,
uint32_t channel_id,
const ConstByteSpan& request) {
return [&client, channel_id, &request](
internal::RawSynchronousCallState& call_state) {
const Request& request) {
return [&client, channel_id, &request](CallState<kRpcMethod>& call_state) {
return kRpcMethod(client,
channel_id,
request,
Expand All @@ -120,11 +147,11 @@ constexpr auto CallFreeFunction(Client& client,
}

// Invokes the RPC function on the generated service client using a call_state.
template <auto kRpcMethod>
template <auto kRpcMethod, typename Request>
constexpr auto CallGeneratedClient(
const typename MethodInfo<kRpcMethod>::GeneratedClient& client,
const ConstByteSpan& request) {
return [&client, &request](internal::RawSynchronousCallState& call_state) {
const Request& request) {
return [&client, &request](CallState<kRpcMethod>& call_state) {
constexpr auto kMemberFunction = MethodInfo<kRpcMethod>::template Function<
typename MethodInfo<kRpcMethod>::GeneratedClient>();
return (client.*kMemberFunction)(request,
Expand Down
121 changes: 14 additions & 107 deletions pw_rpc/public/pw_rpc/synchronous_call.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,8 @@ SynchronousCall(
Client& client,
uint32_t channel_id,
const typename internal::MethodInfo<kRpcMethod>::Request& request) {
using Info = internal::MethodInfo<kRpcMethod>;
using Response = typename Info::Response;
static_assert(Info::kType == MethodType::kUnary,
"Only unary methods can be used with synchronous calls");

internal::SynchronousCallState<Response> call_state;

auto call = kRpcMethod(client,
channel_id,
request,
call_state.OnCompletedCallback(),
call_state.OnRpcErrorCallback());

call_state.notify.acquire();

return std::move(call_state.result);
return internal::StructSynchronousCall<kRpcMethod>(
internal::CallFreeFunction<kRpcMethod>(client, channel_id, request));
}

/// Invokes a unary RPC synchronously using Nanopb or pwpb. Blocks indefinitely
Expand All @@ -134,23 +120,8 @@ SynchronousCallResult<typename internal::MethodInfo<kRpcMethod>::Response>
SynchronousCall(
const typename internal::MethodInfo<kRpcMethod>::GeneratedClient& client,
const typename internal::MethodInfo<kRpcMethod>::Request& request) {
using Info = internal::MethodInfo<kRpcMethod>;
using Response = typename Info::Response;
static_assert(Info::kType == MethodType::kUnary,
"Only unary methods can be used with synchronous calls");

constexpr auto Function =
Info::template Function<typename Info::GeneratedClient>();

internal::SynchronousCallState<Response> call_state;

auto call = (client.*Function)(request,
call_state.OnCompletedCallback(),
call_state.OnRpcErrorCallback());

call_state.notify.acquire();

return std::move(call_state.result);
return internal::StructSynchronousCall<kRpcMethod>(
internal::CallGeneratedClient<kRpcMethod>(client, request));
}

/// Invokes a unary RPC synchronously using the raw API. Blocks until a
Expand Down Expand Up @@ -191,24 +162,9 @@ SynchronousCallFor(
uint32_t channel_id,
const typename internal::MethodInfo<kRpcMethod>::Request& request,
chrono::SystemClock::duration timeout) {
using Info = internal::MethodInfo<kRpcMethod>;
using Response = typename Info::Response;
static_assert(Info::kType == MethodType::kUnary,
"Only unary methods can be used with synchronous calls");

internal::SynchronousCallState<Response> call_state;

auto call = kRpcMethod(client,
channel_id,
request,
call_state.OnCompletedCallback(),
call_state.OnRpcErrorCallback());

if (!call_state.notify.try_acquire_for(timeout)) {
return SynchronousCallResult<Response>::Timeout();
}

return std::move(call_state.result);
return internal::StructSynchronousCall<kRpcMethod>(
internal::CallFreeFunction<kRpcMethod>(client, channel_id, request),
timeout);
}

/// Invokes a unary RPC synchronously using Nanopb or pwpb. Blocks until a
Expand All @@ -223,25 +179,8 @@ SynchronousCallFor(
const typename internal::MethodInfo<kRpcMethod>::GeneratedClient& client,
const typename internal::MethodInfo<kRpcMethod>::Request& request,
chrono::SystemClock::duration timeout) {
using Info = internal::MethodInfo<kRpcMethod>;
using Response = typename Info::Response;
static_assert(Info::kType == MethodType::kUnary,
"Only unary methods can be used with synchronous calls");

constexpr auto Function =
Info::template Function<typename Info::GeneratedClient>();

internal::SynchronousCallState<Response> call_state;

auto call = (client.*Function)(request,
call_state.OnCompletedCallback(),
call_state.OnRpcErrorCallback());

if (!call_state.notify.try_acquire_for(timeout)) {
return SynchronousCallResult<Response>::Timeout();
}

return std::move(call_state.result);
return internal::StructSynchronousCall<kRpcMethod>(
internal::CallGeneratedClient<kRpcMethod>(client, request), timeout);
}

/// Invokes a unary RPC synchronously using the raw API. Blocks until a
Expand Down Expand Up @@ -287,24 +226,9 @@ SynchronousCallUntil(
uint32_t channel_id,
const typename internal::MethodInfo<kRpcMethod>::Request& request,
chrono::SystemClock::time_point deadline) {
using Info = internal::MethodInfo<kRpcMethod>;
using Response = typename Info::Response;
static_assert(Info::kType == MethodType::kUnary,
"Only unary methods can be used with synchronous calls");

internal::SynchronousCallState<Response> call_state;

auto call = kRpcMethod(client,
channel_id,
request,
call_state.OnCompletedCallback(),
call_state.OnRpcErrorCallback());

if (!call_state.notify.try_acquire_until(deadline)) {
return SynchronousCallResult<Response>::Timeout();
}

return std::move(call_state.result);
return internal::StructSynchronousCall<kRpcMethod>(
internal::CallFreeFunction<kRpcMethod>(client, channel_id, request),
deadline);
}

/// Invokes a unary RPC synchronously using Nanopb or pwpb. Blocks until a
Expand All @@ -319,25 +243,8 @@ SynchronousCallUntil(
const typename internal::MethodInfo<kRpcMethod>::GeneratedClient& client,
const typename internal::MethodInfo<kRpcMethod>::Request& request,
chrono::SystemClock::time_point deadline) {
using Info = internal::MethodInfo<kRpcMethod>;
using Response = typename Info::Response;
static_assert(Info::kType == MethodType::kUnary,
"Only unary methods can be used with synchronous calls");

constexpr auto Function =
Info::template Function<typename Info::GeneratedClient>();

internal::SynchronousCallState<Response> call_state;

auto call = (client.*Function)(request,
call_state.OnCompletedCallback(),
call_state.OnRpcErrorCallback());

if (!call_state.notify.try_acquire_until(deadline)) {
return SynchronousCallResult<Response>::Timeout();
}

return std::move(call_state.result);
return internal::StructSynchronousCall<kRpcMethod>(
internal::CallGeneratedClient<kRpcMethod>(client, request), deadline);
}

/// Invokes a unary RPC synchronously using the raw API. Blocks until a
Expand Down

0 comments on commit a51901f

Please sign in to comment.