pub struct EmbeddedServiceClient<Svc: RosService, const REQ_BUF: usize = { crate::config::DEFAULT_RX_BUF_SIZE }, const REPLY_BUF: usize = { crate::config::DEFAULT_RX_BUF_SIZE }> { /* private fields */ }Expand description
Typed service client handle with internal buffers.
Implementations§
Source§impl<Svc: RosService, const REQ_BUF: usize, const REPLY_BUF: usize> EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>
impl<Svc: RosService, const REQ_BUF: usize, const REPLY_BUF: usize> EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>
Sourcepub fn call(
&mut self,
request: &Svc::Request,
) -> Result<Promise<'_, Svc::Reply>, NodeError>
pub fn call( &mut self, request: &Svc::Request, ) -> Result<Promise<'_, Svc::Reply>, NodeError>
Call the service (non-blocking). Returns a Promise that can be polled.
Use with Executor::spin_once() to drive I/O while waiting:
let mut promise = client.call(&request)?;
loop {
executor.spin_once(core::time::Duration::from_millis(10));
if let Some(reply) = promise.take()? {
break;
}
}§Errors
Returns NodeError::RequestInFlight if a previous call’s reply
has not been received. This prevents the old hazard where dropping
a Promise without awaiting its reply left the stale reply
queued to land on the next call. Resolve by
polling the existing promise to completion or calling
reset_in_flight.
Sourcepub fn reset_in_flight(&mut self)
pub fn reset_in_flight(&mut self)
Explicitly clear the in-flight flag (Phase 84.D3).
Call this if a previous Promise was dropped without completing
and you want to abandon the pending reply. The next
call will proceed but may still observe the stale
reply if one is in the transport’s queue — callers that need strict
correctness should drain / ignore one extra take first.
Sourcepub fn wait_for_service(
&mut self,
executor: &mut Executor<'_>,
timeout: Duration,
) -> Result<bool, NodeError>
pub fn wait_for_service( &mut self, executor: &mut Executor<'_>, timeout: Duration, ) -> Result<bool, NodeError>
Block until at least one matching service server is discoverable on
the network, or timeout elapses.
Returns Ok(true) if a matching server reported back inside the
budget; Ok(false) on timeout (no server visible). Mirrors
rclcpp::ClientBase::wait_for_service and
rclpy.client.Client.wait_for_service.
A spin on service_is_ready: the executor
is spun cooperatively between checks so other subscribers / timers
continue to make progress, and the check itself is a synchronous read
of the discovery state the backend maintains (on zenoh, the
matched-server set fed by liveliness PUT/DELETE — phase-428 W13). No
query is issued at call time, which is also how upstream answers.
issue 1087 — a backend that cannot answer (Err, e.g. XRCE) is
“cannot say”, NOT “yes”. It used to be yes, so this returned
immediately on cyclone, XRCE and uORB without probing anything.
issue 1686 — and “cannot say” is not “no” either: such a backend
returns Err(NodeError::Transport(TransportError::Unsupported)) at
once, rather than waiting out a budget no answer can arrive in and
reporting Ok(false). See ServerVisibility. A caller that may send
blind (the request’s own timeout is then the probe) matches that
error and proceeds.
Recommended usage — gate the first call() on this:
let mut client = node.create_client::<AddTwoInts>("/add_two_ints")?;
if !client.wait_for_service(&mut executor, Duration::from_secs(5))? {
return Err(NodeError::Timeout);
}
let mut promise = client.call(&request)?;Nothing is latched. service_is_ready reads the CURRENT state, so a
server that goes away after this returned true reads unavailable
again — which is what rclcpp does too (ClientBase::service_is_ready
calls rcl_service_server_is_available on every invocation; there is
no snapshot semantic, whatever an earlier comment here claimed).
Sourcepub fn service_is_ready(&self) -> Result<bool, NodeError>
pub fn service_is_ready(&self) -> Result<bool, NodeError>
Phase 124.C.3 — graph-aware server-availability probe.
Returns Ok(true) / Ok(false) when the backend can answer
(zenoh queryable interest, DDS built-in topic reader), or
Err(NodeError::Transport(Unsupported)) when it can’t (XRCE
agent without participant enumeration). Distinct from
rclcpp collapses this to a bare bool and throws on error;
RFC-0018 forbids exceptions, so the Result carries what the
exception would have (phase-379 W6).
Used to gate the first request so a startup-ordering race (client opens before server’s discovery announcement lands) doesn’t surface as a request-side timeout.
Sourcepub fn service_name(&self) -> &str
pub fn service_name(&self) -> &str
The service this client was created on — rclrs’s
ClientState::service_name, C’s rcl_client_get_service_name,
C++’s Client::get_service_name. See
EmbeddedPublisher::topic_name for the contract and for why the
accessor is here rather than on the RMW trait. phase-444.
Bounded against rclrs: the name is a &str BORROWED from this handle where
rclrs returns an owned String (no allocator), and the receiver is this live
handle — no type here is called Client (the declared entity is
ServiceClient, the RMW seam ClientTrait).