rclrs/service/
worker_service_callback.rs

1use rosidl_runtime_rs::Service;
2
3use crate::{RclrsError, RclrsErrorFilter, RequestId, ServiceHandle, ServiceInfo};
4
5use std::{any::Any, sync::Arc};
6
7/// An enum capturing the various possible function signatures for service
8/// callbacks that can be used by a [`Worker`][crate::Worker].
9///
10/// The correct enum variant is deduced by the [`IntoWorkerServiceCallback`][1] trait.
11///
12/// [1]: crate::IntoWorkerServiceCallback
13pub enum WorkerServiceCallback<T, Payload>
14where
15    T: Service,
16    Payload: 'static + Send,
17{
18    /// A callback that only takes in the request value
19    OnlyRequest(Box<dyn FnMut(&mut Payload, T::Request) -> T::Response + Send>),
20    /// A callback that takes in the request value and the ID of the request
21    WithId(Box<dyn FnMut(&mut Payload, T::Request, RequestId) -> T::Response + Send>),
22    /// A callback that takes in the request value and all available
23    WithInfo(Box<dyn FnMut(&mut Payload, T::Request, ServiceInfo) -> T::Response + Send>),
24}
25
26impl<T, Payload> WorkerServiceCallback<T, Payload>
27where
28    T: Service,
29    Payload: 'static + Send,
30{
31    pub(super) fn execute(
32        &mut self,
33        handle: &Arc<ServiceHandle>,
34        any_payload: &mut dyn Any,
35    ) -> Result<(), RclrsError> {
36        let Some(payload) = any_payload.downcast_mut::<Payload>() else {
37            return Err(RclrsError::InvalidPayload {
38                expected: std::any::TypeId::of::<Payload>(),
39                received: (*any_payload).type_id(),
40            });
41        };
42
43        let mut evaluate = || {
44            match self {
45                WorkerServiceCallback::OnlyRequest(cb) => {
46                    let (msg, mut rmw_request_id) = handle.take_request::<T>()?;
47                    let response = cb(payload, msg);
48                    handle.send_response::<T>(&mut rmw_request_id, response)?;
49                }
50                WorkerServiceCallback::WithId(cb) => {
51                    let (msg, mut rmw_request_id) = handle.take_request::<T>()?;
52                    let request_id = RequestId::from_rmw_request_id(&rmw_request_id);
53                    let response = cb(payload, msg, request_id);
54                    handle.send_response::<T>(&mut rmw_request_id, response)?;
55                }
56                WorkerServiceCallback::WithInfo(cb) => {
57                    let (msg, rmw_service_info) = handle.take_request_with_info::<T>()?;
58                    let mut rmw_request_id = rmw_service_info.rmw_request_id();
59                    let service_info = ServiceInfo::from_rmw_service_info(&rmw_service_info);
60                    let response = cb(payload, msg, service_info);
61                    handle.send_response::<T>(&mut rmw_request_id, response)?;
62                }
63            }
64
65            Ok(())
66        };
67
68        evaluate().take_failed_ok()
69    }
70}