ros2_client/service/mod.rs
1//! Implementation of ROS 2 [Services](https://docs.ros.org/en/rolling/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Services/Understanding-ROS2-Services.html)
2use std::marker::PhantomData;
3
4#[allow(unused_imports)]
5use log::{debug, error, info, warn};
6
7use crate::message::Message;
8
9pub mod client;
10pub mod request_id;
11pub mod server;
12pub(super) mod wrappers;
13
14pub use request_id::*;
15use wrappers::*;
16pub use server::*;
17pub use client::*;
18
19// --------------------------------------------
20// --------------------------------------------
21
22/// Service trait pairs the Request and Response types together.
23/// Additionally, it ensures that Response and Request are Messages
24/// (Serializable), and we have a means to name the types.
25pub trait Service {
26 type Request: Message;
27 type Response: Message;
28 fn request_type_name(&self) -> &str;
29 fn response_type_name(&self) -> &str;
30}
31
32// --------------------------------------------
33// --------------------------------------------
34
35/// AService is a means of constructing a descriptor for a Service on the fly.
36/// This allows generic code to construct a Service from the types of
37/// request and response.
38pub struct AService<Q, S>
39where
40 Q: Message,
41 S: Message,
42{
43 q: PhantomData<Q>,
44 s: PhantomData<S>,
45 req_type_name: String,
46 resp_type_name: String,
47}
48
49impl<Q, S> AService<Q, S>
50where
51 Q: Message,
52 S: Message,
53{
54 pub fn new(req_type_name: String, resp_type_name: String) -> Self {
55 Self {
56 req_type_name,
57 resp_type_name,
58 q: PhantomData,
59 s: PhantomData,
60 }
61 }
62}
63
64impl<Q, S> Service for AService<Q, S>
65where
66 Q: Message,
67 S: Message,
68{
69 type Request = Q;
70 type Response = S;
71
72 fn request_type_name(&self) -> &str {
73 &self.req_type_name
74 }
75
76 fn response_type_name(&self) -> &str {
77 &self.resp_type_name
78 }
79}
80
81// --------------------------------------------
82// --------------------------------------------
83
84/// Selects how Service Requests and Responses are to be mapped to DDS.
85///
86/// There are different and incompatible ways to map Services onto DDS Topics.
87/// In order to interoperate with ROS 2, you have to select the same mapping it
88/// uses. The mapping used by ROS2 depends on the DDS implementation used and
89/// its configuration.
90///
91/// For details, see OMG Specification
92/// [RPC over DDS](https://www.omg.org/spec/DDS-RPC/1.0/About-DDS-RPC/)
93/// Section "7.2.4 Basic and Enhanced Service Mapping for RPC over DDS",
94/// which defines Service Mappings "Basic" and "Enhanced".
95///
96/// ServiceMapping::Cyclone represents a third mapping used by RMW for
97/// CycloneDDS.
98#[derive(Clone, Copy, Debug, Eq, PartialEq)]
99pub enum ServiceMapping {
100 /// "Basic" service mapping from RPC over DDS specification.
101 /// * RTI Connext with `RMW_CONNEXT_REQUEST_REPLY_MAPPING=basic`, but this is
102 /// not tested, so may not work.
103 Basic,
104
105 /// "Enhanced" service mapping from RPC over DDS specification.
106 /// * ROS2 Foxy with eProsima DDS,
107 /// * ROS2 Galactic with RTI Connext (rmw_connextdds, not rmw_connext_cpp) -
108 /// set environment variable `RMW_CONNEXT_REQUEST_REPLY_MAPPING=extended`
109 /// before running ROS2 executable.
110 Enhanced,
111
112 /// CycloneDDS-specific service mapping.
113 /// Specification for this mapping is unknown, technical details are
114 /// reverse-engineered from ROS2 sources.
115 /// * ROS2 Galactic with CycloneDDS - Seems to work on the same host only, not
116 /// over actual network.
117 Cyclone,
118}