pub struct EmbeddedServiceClient<Svc, const REQ_BUF: usize = nros_node::::executor::handles::EmbeddedServiceClient::{constant#0}, const REPLY_BUF: usize = nros_node::::executor::handles::EmbeddedServiceClient::{constant#1}>where
Svc: RosService,{ /* private fields */ }Expand description
Typed service client handle with internal buffers.
Implementations§
Source§impl<Svc, const REQ_BUF: usize, const REPLY_BUF: usize> EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>where
Svc: RosService,
impl<Svc, const REQ_BUF: usize, const REPLY_BUF: usize> EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>where
Svc: RosService,
Sourcepub fn call(
&mut self,
request: &<Svc as RosService>::Request,
) -> Result<Promise<'_, <Svc as RosService>::Reply>, NodeError>
pub fn call( &mut self, request: &<Svc as RosService>::Request, ) -> Result<Promise<'_, <Svc as RosService>::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.
On the Zenoh backend this issues a z_liveliness_get against the
matching server’s wildcarded liveliness keyexpr; the executor is
spun cooperatively while the query is in flight so other
subscribers / timers continue to make progress. Backends without
liveliness discovery answer Ok(true) immediately (default trait
impl in nros-rmw), so the call is a no-op cost when discovery
isn’t supported.
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)?;Once the server is observed, the result is latched: subsequent
service_is_ready checks return true without another round
trip. This matches rclcpp’s snapshot semantic — discovery isn’t
re-proven on every call.
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.