Skip to main content

EmbeddedServiceClient

Struct EmbeddedServiceClient 

Source
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>

Source

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.

Source

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.

Source

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).

Source

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.

Source

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).

Auto Trait Implementations§

§

impl<Svc, const REQ_BUF: usize = { crate::config::DEFAULT_RX_BUF_SIZE }, const REPLY_BUF: usize = { crate::config::DEFAULT_RX_BUF_SIZE }> !Send for EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>

§

impl<Svc, const REQ_BUF: usize = { crate::config::DEFAULT_RX_BUF_SIZE }, const REPLY_BUF: usize = { crate::config::DEFAULT_RX_BUF_SIZE }> !Sync for EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>

§

impl<Svc, const REQ_BUF: usize, const REPLY_BUF: usize> Freeze for EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>

§

impl<Svc, const REQ_BUF: usize, const REPLY_BUF: usize> RefUnwindSafe for EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>
where Svc: RefUnwindSafe,

§

impl<Svc, const REQ_BUF: usize, const REPLY_BUF: usize> Unpin for EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>
where Svc: Unpin,

§

impl<Svc, const REQ_BUF: usize, const REPLY_BUF: usize> UnsafeUnpin for EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>

§

impl<Svc, const REQ_BUF: usize, const REPLY_BUF: usize> UnwindSafe for EmbeddedServiceClient<Svc, REQ_BUF, REPLY_BUF>
where Svc: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.