1use crate::{
2 rosidl_message_type_support_t as CTypeSupport,
3 rosidl_typesupport_introspection_c__MessageMember as CMessageMember,
4 rosidl_typesupport_introspection_c__MessageMembers as CMessageMembers, rust_mangle,
5};
6use quote::quote;
7use std::{
8 borrow::Cow,
9 ffi::{c_char, CStr},
10 mem, slice,
11};
12
13pub struct Introspection<'a> {
14 pub module: &'a str,
15 pub prefix: &'a str,
16 pub name: &'a str,
17 pub members: &'a [MessageMember],
18}
19
20impl<'a> Introspection<'a> {
21 pub fn c_struct_name(&self) -> String {
22 let Self {
23 module,
24 prefix,
25 name,
26 ..
27 } = *self;
28 format!("{module}__{prefix}__{name}")
29 }
30}
31
32#[repr(transparent)]
33pub struct TypeSupport(CTypeSupport);
34
35impl TypeSupport {
36 pub unsafe fn introspection(&self) -> Introspection<'_> {
37 let members = (self.0.data as *const MessageMembers).as_ref().unwrap();
38 let namespace = members.message_namespace();
39 let name = members.message_name();
40 let members = members.members();
41
42 let (module, remain) = namespace.split_once("__").unwrap();
43 let (prefix, _) = remain.split_once("__").unwrap();
44
45 Introspection {
46 module,
47 prefix,
48 name,
49 members,
50 }
51 }
52}
53
54#[repr(transparent)]
55pub struct MessageMember(CMessageMember);
56
57impl MessageMember {
58 pub fn name(&self) -> &str {
59 unsafe { ptr_to_str(self.0.name_) }
60 }
61
62 pub fn rust_name(&self) -> Cow<'_, str> {
63 rust_mangle(self.name())
64 }
65
66 pub fn type_id(&self) -> MemberType {
67 MemberType::from_type_id(self.0.type_id_).unwrap()
68 }
69
70 pub fn string_upper_bound(&self) -> Option<usize> {
71 if self.type_id() == MemberType::String {
72 Some(self.0.string_upper_bound_ as usize)
73 } else {
74 None
75 }
76 }
77
78 pub fn members(&self) -> Option<&TypeSupport> {
79 if self.type_id() != MemberType::Message {
80 return None;
81 }
82
83 unsafe {
84 let ptr = self.0.members_ as *const TypeSupport;
85 let ref_ = ptr.as_ref().unwrap();
86 Some(ref_)
87 }
88 }
89
90 pub fn is_array(&self) -> bool {
91 self.0.is_array_
92 }
93
94 pub fn array_size(&self) -> Option<usize> {
95 if self.is_array() {
96 Some(self.0.array_size_)
97 } else {
98 None
99 }
100 }
101
102 pub fn is_upper_bound(&self) -> Option<bool> {
103 if self.is_array() {
104 Some(self.0.is_upper_bound_)
105 } else {
106 None
107 }
108 }
109
110 pub fn array_info(&self) -> Option<ArrayInfo> {
111 self.0.is_array_.then(|| ArrayInfo {
112 size: self.0.array_size_,
113 is_upper_bound: self.0.is_upper_bound_,
114 })
115 }
116
117 pub fn offset(&self) -> usize {
118 self.0.offset_ as usize
119 }
120}
121
122#[repr(transparent)]
123pub struct MessageMembers(CMessageMembers);
124
125impl MessageMembers {
126 pub fn message_namespace(&self) -> &str {
127 unsafe { ptr_to_str(self.0.message_namespace_) }
128 }
129
130 pub fn message_name(&self) -> &str {
131 unsafe { ptr_to_str(self.0.message_name_) }
132 }
133
134 pub fn member_count(&self) -> usize {
135 self.0.member_count_ as usize
136 }
137
138 pub fn size_of(&self) -> usize {
139 self.0.size_of_ as usize
140 }
141
142 pub fn members(&self) -> &[MessageMember] {
143 unsafe {
144 let members: &[CMessageMember] =
145 slice::from_raw_parts(self.0.members_, self.member_count());
146 mem::transmute(members)
147 }
148 }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub enum MemberType {
153 Bool,
154 I8,
155 I16,
156 I32,
157 I64,
158 U8,
159 U16,
160 U32,
161 U64,
162 U128,
163 F32,
164 F64,
165 Char,
166 WChar,
167 String,
168 WString,
169 Message,
170}
171
172impl MemberType {
173 pub fn from_type_id(id: u8) -> Option<Self> {
200 Some(match id {
201 1 => Self::F32,
202 2 => Self::F64,
203 3 => Self::U128,
204 4 => Self::Char,
205 5 => Self::WChar,
206 6 => Self::Bool,
207 7 | 8 => Self::U8,
208 9 => Self::I8,
209 10 => Self::U16,
210 11 => Self::I16,
211 12 => Self::U32,
212 13 => Self::I32,
213 14 => Self::U64,
214 15 => Self::I64,
215 16 => Self::String,
216 17 => Self::WString,
217 18 => Self::Message,
218 _ => return None,
219 })
220 }
221
222 pub fn to_rust_type(&self) -> proc_macro2::TokenStream {
223 match self {
224 MemberType::Bool => quote! { bool },
225 MemberType::I8 => quote! { i8 },
226 MemberType::I16 => quote! { i16 },
227 MemberType::I32 => quote! { i32 },
228 MemberType::I64 => quote! { i64 },
229 MemberType::U8 => quote! { u8 },
230 MemberType::U16 => quote! { u16 },
231 MemberType::U32 => quote! { u32 },
232 MemberType::U64 => quote! { u64 },
233 MemberType::U128 => quote! { u128 },
234 MemberType::F32 => quote! { f32 },
235 MemberType::F64 => quote! { f64 },
236 MemberType::Char => quote! { std::ffi::c_char },
237 MemberType::WChar => quote! { u16 },
238 MemberType::String => quote! { std::string::String },
239 MemberType::WString => quote! { std::string::String },
240 MemberType::Message => quote! { message },
241 }
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq)]
246pub struct ArrayInfo {
247 pub size: usize,
248 pub is_upper_bound: bool,
249}
250
251unsafe fn ptr_to_str(ptr: *const c_char) -> &'static str {
252 CStr::from_ptr(ptr).to_str().unwrap()
253}