1#![allow(dead_code)]
2#![allow(non_upper_case_globals)]
3#![allow(non_camel_case_types)]
4#![allow(deref_nullptr)]
5#![allow(non_snake_case)]
6#![allow(improper_ctypes)]
7#![allow(unused_imports)]
8#![allow(clippy::upper_case_acronyms)]
9#![allow(clippy::too_many_arguments)]
10#![allow(clippy::manual_c_str_literals)]
11#![allow(clippy::useless_conversion)]
12
13#[cfg(feature = "rcl")]
22pub mod rcl {
23 pub use crate::runtime_c::*;
25}
26
27pub mod primitives;
28pub mod strings;
29
30#[cfg(feature = "rcl")]
32mod runtime_c {
33 include!(concat!(env!("OUT_DIR"), "/runtime_c.rs"));
34}
35
36#[cfg(feature = "rcl")]
38pub use runtime_c::*;
39
40pub mod msg {
42 pub use crate::primitives::{
43 BoolSeq, ByteSeq, F32Seq, F64Seq, I8Seq, I16Seq, I32Seq, I64Seq, U8Seq, U16Seq, U32Seq,
44 U64Seq,
45 };
46 pub use crate::strings::{RosString, RosStringSeq, RosWString, RosWStringSeq};
47 pub use oxidros_core::TypeSupport;
48}
49
50pub mod builtin_interfaces {
52 pub use oxidros_core::{UnsafeDuration, UnsafeTime};
53}
54
55pub use ros2_types::{
57 Ros2Msg, SequenceRaw, ServiceMsg, TryClone, TypeSupport, ros2_action, ros2_service,
58};
59
60#[rustfmt::skip]
63pub mod common_interfaces {
64 include!(concat!(env!("OUT_DIR"), "/generated/common_interfaces/mod.rs"));
66}
67
68#[rustfmt::skip]
69pub mod interfaces {
70 include!(concat!(env!("OUT_DIR"), "/generated/interfaces/mod.rs"));
72}
73
74#[rustfmt::skip]
75pub mod ros2msg {
76 include!(concat!(env!("OUT_DIR"), "/generated/ros2msg/mod.rs"));
78}
79
80pub use ros2msg::*;
82
83pub use oxidros_core;
85
86pub use oxidros_core::{
88 ActionGoal, ActionMsg, ActionResult, GetUUID, GoalResponse, ResultResponse,
89};
90
91pub use oxidros_core::{UnsafeDuration, UnsafeTime};
93
94use crate::interfaces::rcl_interfaces::msg::ParameterValue;
95use crate::msg::{BoolSeq, ByteSeq, F64Seq, I64Seq, RosString, RosStringSeq};
96use oxidros_core::Value;
97
98impl From<&oxidros_core::parameter::IntegerRange>
99 for interfaces::rcl_interfaces::msg::IntegerRange
100{
101 fn from(range: &oxidros_core::parameter::IntegerRange) -> Self {
102 interfaces::rcl_interfaces::msg::IntegerRange {
103 from_value: range.min,
104 to_value: range.max,
105 step: range.step as u64,
106 }
107 }
108}
109
110impl From<&oxidros_core::parameter::FloatingPointRange>
111 for interfaces::rcl_interfaces::msg::FloatingPointRange
112{
113 fn from(range: &oxidros_core::parameter::FloatingPointRange) -> Self {
114 interfaces::rcl_interfaces::msg::FloatingPointRange {
115 from_value: range.min,
116 to_value: range.max,
117 step: range.step,
118 }
119 }
120}
121
122impl From<&ParameterValue> for Value {
123 fn from(var: &ParameterValue) -> Self {
124 match var.r#type {
125 1 => Value::Bool(var.bool_value),
126 2 => Value::I64(var.integer_value),
127 3 => Value::F64(var.double_value),
128 4 => Value::String(var.string_value.to_string()),
129 5 => {
130 let mut v = Vec::new();
131 var.byte_array_value.iter().for_each(|x| v.push(*x));
132 Value::VecU8(v)
133 }
134 6 => {
135 let mut v = Vec::new();
136 var.bool_array_value.iter().for_each(|x| v.push(*x));
137 Value::VecBool(v)
138 }
139 7 => {
140 let mut v = Vec::new();
141 var.integer_array_value.iter().for_each(|x| v.push(*x));
142 Value::VecI64(v)
143 }
144 8 => {
145 let mut v = Vec::new();
146 var.double_array_value.iter().for_each(|x| v.push(*x));
147 Value::VecF64(v)
148 }
149 9 => {
150 let mut v = Vec::new();
151 var.string_array_value
152 .iter()
153 .for_each(|x| v.push(x.to_string()));
154 Value::VecString(v)
155 }
156 _ => Value::NotSet,
157 }
158 }
159}
160
161impl From<&Value> for ParameterValue {
162 fn from(var: &Value) -> Self {
163 let mut result = ParameterValue::new().unwrap();
164 match var {
165 Value::NotSet => result.r#type = 0,
166 Value::Bool(val) => {
167 result.r#type = 1;
168 result.bool_value = *val;
169 }
170 Value::I64(val) => {
171 result.r#type = 2;
172 result.integer_value = *val;
173 }
174 Value::F64(val) => {
175 result.r#type = 3;
176 result.double_value = *val;
177 }
178 Value::String(val) => {
179 result.r#type = 4;
180 result.string_value = RosString::new(val).unwrap_or_else(|| {
181 log::error!("{}:{}: failed allocation", file!(), line!());
182 RosString::null()
183 });
184 }
185 Value::VecU8(val) => {
186 result.r#type = 5;
187 result.byte_array_value = ByteSeq::new(val.len()).unwrap_or_else(|| {
188 log::error!("{}:{}: failed allocation", file!(), line!());
189 ByteSeq::null()
190 });
191 result
192 .byte_array_value
193 .iter_mut()
194 .zip(val.iter())
195 .for_each(|(dst, src)| *dst = *src);
196 }
197 Value::VecBool(val) => {
198 result.r#type = 6;
199 result.bool_array_value = BoolSeq::new(val.len()).unwrap_or_else(|| {
200 log::error!("{}:{}: failed allocation", file!(), line!());
201 BoolSeq::null()
202 });
203 result
204 .bool_array_value
205 .iter_mut()
206 .zip(val.iter())
207 .for_each(|(dst, src)| *dst = *src);
208 }
209 Value::VecI64(val) => {
210 result.r#type = 7;
211 result.integer_array_value = I64Seq::new(val.len()).unwrap_or_else(|| {
212 log::error!("{}:{}: failed allocation", file!(), line!());
213 I64Seq::null()
214 });
215 result
216 .integer_array_value
217 .iter_mut()
218 .zip(val.iter())
219 .for_each(|(dst, src)| *dst = *src);
220 }
221 Value::VecF64(val) => {
222 result.r#type = 8;
223 result.double_array_value = F64Seq::new(val.len()).unwrap_or_else(|| {
224 log::error!("{}:{}: failed allocation", file!(), line!());
225 F64Seq::null()
226 });
227 result
228 .double_array_value
229 .iter_mut()
230 .zip(val.iter())
231 .for_each(|(dst, src)| *dst = *src);
232 }
233 Value::VecString(val) => {
234 result.r#type = 9;
235 result.string_array_value = RosStringSeq::new(val.len()).unwrap_or_else(|| {
236 log::error!("{}:{}: failed allocation", file!(), line!());
237 RosStringSeq::null()
238 });
239 result
240 .string_array_value
241 .iter_mut()
242 .zip(val.iter())
243 .for_each(|(dst, src)| {
244 dst.assign(src);
245 });
246 }
247 }
248 result
249 }
250}
251
252#[cfg(not(feature = "rcl"))]
253#[cfg(test)]
254mod tests {
255 use oxidros_core::ServiceTypeDescription;
256
257 const EXPECTED_HASHES: &[(&str, &str)] = &[
260 (
261 "rcl_interfaces/srv/ListParameters",
262 "RIHS01_3e6062bfbb27bfb8730d4cef2558221f51a11646d78e7bb30a1e83afac3aad9d",
263 ),
264 (
265 "rcl_interfaces/srv/GetParameters",
266 "RIHS01_bf9803d5c74cf989a5de3e0c2e99444599a627c7ff75f97b8c05b01003675cbc",
267 ),
268 (
269 "rcl_interfaces/srv/SetParameters",
270 "RIHS01_56eed9a67e169f9cb6c1f987bc88f868c14a8fc9f743a263bc734c154015d7e0",
271 ),
272 (
273 "rcl_interfaces/srv/SetParametersAtomically",
274 "RIHS01_0e192ef259c07fc3c07a13191d27002222e65e00ccec653ca05e856f79285fcd",
275 ),
276 (
277 "rcl_interfaces/srv/DescribeParameters",
278 "RIHS01_845b484d71eb0673dae682f2e3ba3c4851a65a3dcfb97bddd82c5b57e91e4cff",
279 ),
280 (
281 "rcl_interfaces/srv/GetParameterTypes",
282 "RIHS01_da199c878688b3e530bdfe3ca8f74cb9fa0c303101e980a9e8f260e25e1c80ca",
283 ),
284 ];
285
286 #[test]
287 fn test_list_parameters_type_hash() {
288 use super::interfaces::rcl_interfaces::srv::ListParameters;
289 let hash = ListParameters::compute_hash().expect("failed to compute hash");
290 assert_eq!(
291 hash, EXPECTED_HASHES[0].1,
292 "ListParameters type hash mismatch - interop with ros2 param will fail"
293 );
294 }
295
296 #[test]
297 fn test_get_parameters_type_hash() {
298 use super::interfaces::rcl_interfaces::srv::GetParameters;
299 let td = GetParameters::type_description();
300 println!("GetParameters type description: {:?}", td);
301 let hash = GetParameters::compute_hash().expect("failed to compute hash");
302 assert_eq!(
303 hash, EXPECTED_HASHES[1].1,
304 "GetParameters type hash mismatch - interop with ros2 param will fail"
305 );
306 }
307
308 #[test]
309 fn test_set_parameters_type_hash() {
310 use super::interfaces::rcl_interfaces::srv::SetParameters;
311 let hash = SetParameters::compute_hash().expect("failed to compute hash");
312 assert_eq!(
313 hash, EXPECTED_HASHES[2].1,
314 "SetParameters type hash mismatch - interop with ros2 param will fail"
315 );
316 }
317
318 #[test]
319 fn test_set_parameters_atomically_type_hash() {
320 use super::interfaces::rcl_interfaces::srv::SetParametersAtomically;
321 let hash = SetParametersAtomically::compute_hash().expect("failed to compute hash");
322 assert_eq!(
323 hash, EXPECTED_HASHES[3].1,
324 "SetParametersAtomically type hash mismatch - interop with ros2 param will fail"
325 );
326 }
327
328 #[test]
329 fn test_describe_parameters_type_hash() {
330 use super::interfaces::rcl_interfaces::srv::DescribeParameters;
331 let hash = DescribeParameters::compute_hash().expect("failed to compute hash");
332 assert_eq!(
333 hash, EXPECTED_HASHES[4].1,
334 "DescribeParameters type hash mismatch - interop with ros2 param will fail"
335 );
336 }
337
338 #[test]
339 fn test_get_parameter_types_type_hash() {
340 use super::interfaces::rcl_interfaces::srv::GetParameterTypes;
341 let hash = GetParameterTypes::compute_hash().expect("failed to compute hash");
342 assert_eq!(
343 hash, EXPECTED_HASHES[5].1,
344 "GetParameterTypes type hash mismatch - interop with ros2 param will fail"
345 );
346 }
347
348 #[test]
349 fn test_all_parameter_service_hashes() {
350 use super::interfaces::rcl_interfaces::srv::{
352 DescribeParameters, GetParameterTypes, GetParameters, ListParameters, SetParameters,
353 SetParametersAtomically,
354 };
355
356 let services: Vec<(&str, String)> = vec![
357 (
358 "ListParameters",
359 ListParameters::compute_hash().expect("hash"),
360 ),
361 (
362 "GetParameters",
363 GetParameters::compute_hash().expect("hash"),
364 ),
365 (
366 "SetParameters",
367 SetParameters::compute_hash().expect("hash"),
368 ),
369 (
370 "SetParametersAtomically",
371 SetParametersAtomically::compute_hash().expect("hash"),
372 ),
373 (
374 "DescribeParameters",
375 DescribeParameters::compute_hash().expect("hash"),
376 ),
377 (
378 "GetParameterTypes",
379 GetParameterTypes::compute_hash().expect("hash"),
380 ),
381 ];
382
383 let mut all_match = true;
384 for (i, (name, hash)) in services.iter().enumerate() {
385 let expected = EXPECTED_HASHES[i].1;
386 if hash != expected {
387 eprintln!("MISMATCH: {} - got {} expected {}", name, hash, expected);
388 all_match = false;
389 }
390 }
391
392 assert!(
393 all_match,
394 "One or more parameter service type hashes do not match ROS2 expectations"
395 );
396 }
397}