1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
// Silence "`extern` fn uses type `u128`, which is not FFI-safe"
// As of rustc 1.78, this has been fixed.
// It could be good to still warn if building with an older rust version.
#![allow(improper_ctypes)]
#![allow(improper_ctypes_definitions)]
include!(concat!(env!("OUT_DIR"), "/rcl_bindings.rs"));

use std::ffi::{CStr, CString};

impl Default for rmw_message_info_t {
    fn default() -> Self {
        unsafe { rmw_get_zero_initialized_message_info() }
    }
}

// special treatment to convert to/from rust strings.
// ros strings are owned by ros, assignment is a copy
impl rosidl_runtime_c__String {
    pub fn to_str(&self) -> &str {
        let s = unsafe { CStr::from_ptr(self.data) };
        s.to_str().unwrap_or("")
    }

    pub fn assign(&mut self, other: &str) {
        let q = CString::new(other).unwrap();
        unsafe {
            rosidl_runtime_c__String__assign(self as *mut _, q.as_ptr());
        }
    }
}

use widestring::U16String;
impl rosidl_runtime_c__U16String {
    pub fn to_str(&self) -> String {
        let s = unsafe { U16String::from_ptr(self.data, self.size) };
        // U16Str = U16String::from_ptr(buffer, strlen as usize);
        // let s = unsafe { CStr::from_ptr(self.data as *mut i8) };
        //s.to_str().unwrap_or("")
        s.to_string_lossy()
    }

    pub fn assign(&mut self, other: &str) {
        let wstr = U16String::from_str(other);
        let to_send_ptr = wstr.as_ptr() as *const uint_least16_t;
        unsafe {
            rosidl_runtime_c__U16String__assignn(self as *mut _, to_send_ptr, wstr.len());
        }
    }
}

impl rosidl_runtime_c__U16String__Sequence {
    pub fn update(&mut self, values: &[String]) {
        unsafe {
            rosidl_runtime_c__U16String__Sequence__fini(self as *mut _);
        }
        unsafe {
            rosidl_runtime_c__U16String__Sequence__init(self as *mut _, values.len());
        }
        if self.data != std::ptr::null_mut() {
            let strs = unsafe { std::slice::from_raw_parts_mut(self.data, values.len()) };
            for (target, source) in strs.iter_mut().zip(values) {
                target.assign(source);
            }
        }
    }

    pub fn to_vec(&self) -> Vec<String> {
        if self.data == std::ptr::null_mut() {
            return Vec::new();
        }
        let mut target = Vec::with_capacity(self.size);
        let strs = unsafe { std::slice::from_raw_parts(self.data, self.size) };
        for s in strs {
            target.push(s.to_str().to_owned());
        }
        target
    }
}

impl rosidl_runtime_c__String__Sequence {
    pub fn update(&mut self, values: &[String]) {
        unsafe {
            rosidl_runtime_c__String__Sequence__fini(self as *mut _);
        }
        unsafe {
            rosidl_runtime_c__String__Sequence__init(self as *mut _, values.len());
        }
        if self.data != std::ptr::null_mut() {
            let strs = unsafe { std::slice::from_raw_parts_mut(self.data, values.len()) };
            for (target, source) in strs.iter_mut().zip(values) {
                target.assign(source);
            }
        }
    }

    pub fn to_vec(&self) -> Vec<String> {
        if self.data == std::ptr::null_mut() {
            return Vec::new();
        }
        let mut target = Vec::with_capacity(self.size);
        let strs = unsafe { std::slice::from_raw_parts(self.data, self.size) };
        for s in strs {
            target.push(s.to_str().to_owned());
        }
        target
    }
}

// conversions from/to vectors of built in types

macro_rules! primitive_sequence {
    ($ctype:ident, $element_type:ident) => {
        paste::item! {
            impl [<$ctype __Sequence>] {
                pub fn update(&mut self, values: &[$element_type]) {
                    unsafe { [<$ctype __Sequence__fini>] (self as *mut _); }
                    unsafe { [<$ctype __Sequence__init>] (self as *mut _, values.len()); }
                    if self.data != std::ptr::null_mut() {
                        unsafe { std::ptr::copy_nonoverlapping(values.as_ptr(), self.data, values.len()); }
                    }
                }

                pub fn to_vec(&self) -> Vec<$element_type> {
                    if self.data == std::ptr::null_mut() {
                        return Vec::new();
                    }
                    let mut target = Vec::with_capacity(self.size);
                    unsafe {
                        std::ptr::copy_nonoverlapping(self.data, target.as_mut_ptr(), self.size);
                        target.set_len(self.size);
                    }
                    target
                }
            }
        }
    };
}

primitive_sequence!(rosidl_runtime_c__float32, f32);
primitive_sequence!(rosidl_runtime_c__float64, f64);

#[cfg(any(
    all(target_os = "macos", target_arch = "aarch64"),
    target_arch = "arm",
    target_os = "windows"
))]
primitive_sequence!(rosidl_runtime_c__long_double, f64);

#[cfg(not(any(
    all(target_os = "macos", target_arch = "aarch64"),
    target_arch = "arm",
    target_os = "windows"
)))]
primitive_sequence!(rosidl_runtime_c__long_double, u128);

primitive_sequence!(rosidl_runtime_c__char, i8);
primitive_sequence!(rosidl_runtime_c__wchar, u16);
primitive_sequence!(rosidl_runtime_c__boolean, bool);
primitive_sequence!(rosidl_runtime_c__octet, u8);
primitive_sequence!(rosidl_runtime_c__uint8, u8);
primitive_sequence!(rosidl_runtime_c__int8, i8);
primitive_sequence!(rosidl_runtime_c__uint16, u16);
primitive_sequence!(rosidl_runtime_c__int16, i16);
primitive_sequence!(rosidl_runtime_c__uint32, u32);
primitive_sequence!(rosidl_runtime_c__int32, i32);
primitive_sequence!(rosidl_runtime_c__uint64, u64);
primitive_sequence!(rosidl_runtime_c__int64, i64);