pub trait ServiceTrait {
type Error;
// Required methods
fn take_request<'a>(
&mut self,
buf: &'a mut [u8],
) -> Result<Option<ServiceRequest<'a>>, Self::Error>;
fn send_response(
&mut self,
sequence_number: i64,
data: &[u8],
) -> Result<(), Self::Error>;
// Provided methods
fn has_request(&self) -> bool { ... }
fn register_waker(&self, _waker: &Waker) { ... }
fn handle_request<S>(
&mut self,
req_buf: &mut [u8],
reply_buf: &mut [u8],
handler: impl FnOnce(&<S as RosService>::Request) -> <S as RosService>::Reply,
) -> Result<bool, Self::Error>
where S: RosService,
Self::Error: From<TransportError> { ... }
fn handle_request_boxed<S>(
&mut self,
req_buf: &mut [u8],
reply_buf: &mut [u8],
handler: impl FnOnce(&<S as RosService>::Request) -> Box<<S as RosService>::Reply>,
) -> Result<bool, Self::Error>
where S: RosService,
Self::Error: From<TransportError> { ... }
fn handle_request_raw(
&mut self,
req_buf: &mut [u8],
reply_buf: &mut [u8],
handler: impl FnOnce(&mut CdrReader<'_>, &mut CdrWriter<'_>) -> Result<(), TransportError>,
) -> Result<bool, Self::Error>
where Self::Error: From<TransportError> { ... }
}Expand description
Service server trait for handling requests.
§Threading
&mut self on take_request and send_response — the executor
owns the server while a request is being handled. Handler bodies
run synchronously on the executor thread; long handlers should
dispatch work to a worker queue and reply later via the recorded
sequence_number.
§Calling pattern
- Executor calls
take_request(buf). - If
Some(req)returned, decode, run handler, encode reply. send_response(req.sequence_number, &reply_buf).
sequence_number is the canonical request → reply correlation
token; backends derive it from the wire-level metadata (zenoh
query id, DDS sample identity).
Required Associated Types§
Required Methods§
Sourcefn take_request<'a>(
&mut self,
buf: &'a mut [u8],
) -> Result<Option<ServiceRequest<'a>>, Self::Error>
fn take_request<'a>( &mut self, buf: &'a mut [u8], ) -> Result<Option<ServiceRequest<'a>>, Self::Error>
Try to receive a service request into buf (non-blocking).
On success returns a ServiceRequest that borrows from
buf. The borrow is released when the returned struct is
dropped — typically before send_response is called, since
send_response takes &mut self.
Provided Methods§
Sourcefn has_request(&self) -> bool
fn has_request(&self) -> bool
Check if a request is available without consuming it.
Non-destructive. Default returns true (always assume one
may be available); backends should override with a real
check.
Sourcefn register_waker(&self, _waker: &Waker)
fn register_waker(&self, _waker: &Waker)
Phase 122.3.c.6.e — register a Waker for event-driven
service servers. Mirrors the matching method on
SubscriberTrait / ClientTrait. Backends that
surface incoming-request notifications wake waker when
has_request() flips true. Default: no-op (backends without
wake support ignore — caller falls back to polling).
Sourcefn handle_request<S>(
&mut self,
req_buf: &mut [u8],
reply_buf: &mut [u8],
handler: impl FnOnce(&<S as RosService>::Request) -> <S as RosService>::Reply,
) -> Result<bool, Self::Error>
fn handle_request<S>( &mut self, req_buf: &mut [u8], reply_buf: &mut [u8], handler: impl FnOnce(&<S as RosService>::Request) -> <S as RosService>::Reply, ) -> Result<bool, Self::Error>
Handle a service request with typed messages
Sourcefn handle_request_boxed<S>(
&mut self,
req_buf: &mut [u8],
reply_buf: &mut [u8],
handler: impl FnOnce(&<S as RosService>::Request) -> Box<<S as RosService>::Reply>,
) -> Result<bool, Self::Error>
fn handle_request_boxed<S>( &mut self, req_buf: &mut [u8], reply_buf: &mut [u8], handler: impl FnOnce(&<S as RosService>::Request) -> Box<<S as RosService>::Reply>, ) -> Result<bool, Self::Error>
Handle a service request where the handler returns Box<S::Reply>
Identical to handle_request but the handler returns a heap-allocated reply.
This is needed for services with large response types (e.g., parameter services
where Vec<ParameterValue, 64> is ~1MB+) that would overflow the stack.
Sourcefn handle_request_raw(
&mut self,
req_buf: &mut [u8],
reply_buf: &mut [u8],
handler: impl FnOnce(&mut CdrReader<'_>, &mut CdrWriter<'_>) -> Result<(), TransportError>,
) -> Result<bool, Self::Error>
fn handle_request_raw( &mut self, req_buf: &mut [u8], reply_buf: &mut [u8], handler: impl FnOnce(&mut CdrReader<'_>, &mut CdrWriter<'_>) -> Result<(), TransportError>, ) -> Result<bool, Self::Error>
Handle one request by STREAMING: the handler reads fields off the wire and writes the reply’s fields straight back, so neither the request nor the reply is ever materialised as a value.
phase-382 W1’. handle_request_boxed above boxes the REPLY because the
parameter responses are enormous — GetParametersResponse measures
1,176,072 bytes. It does not box the REQUEST, which is deserialized by
value into a stack local one line above the handler, and
SetParametersRequest measures 1,192,968 bytes. So every
ros2 param set against a node put a 1.19 MB local on the calling
task’s stack — larger than the reply the boxing exists for, on every
platform, with param-services live on Zephyr.
Streaming removes both, and removes the alloc requirement with them:
the whole value is never needed, because serialisation happens on the
line after construction. Three things make it safe rather than clever:
- No
rcl_interfacesmessage uses a DHEADER — everySerializeimpl is plain sequential CDR, so hand-written field writes are byte-identical to the generated ones. (If a future message gains XCDR2 extensibility this stops being true for THAT message; see RFC-0055.) req_bufandreply_bufare disjoint, so a handler can hold the reader and the writer at once.CdrReader::read_stringborrows out ofreq_bufrather than copying, so a handler can look a name up without a buffer of its own.
The cost is that the hand-written writes can drift from the generated
Serialize. Guard it with a round-trip test that deserialises the
streamed bytes back into the generated type — the by-value handler makes
a good test-only oracle.
No alloc, deliberately: this is the seam that lets param-services and
lifecycle-services build without it.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".