1use crate::serde_helpers;
15use serde::{Deserialize, Serialize};
16use std::ffi::{CStr, CString};
17#[cfg(unix)]
18use std::ffi::{OsStr, OsString};
19use syn::parse_quote;
20use tracers_core::argtypes::*;
21use tracers_core::{ProbeArgType, ProbeArgWrapper};
22
23macro_rules! maybe_type {
24 ($syn_t:expr, $rust_t:ty) => {
25 let rust_syn_t: syn::Type = parse_quote! { $rust_t };
26 if *$syn_t == rust_syn_t {
27 return Some(ArgTypeInfo::new::<$rust_t>());
28 }
29 };
30 (@naked $syn_t:expr, $rust_t:ty) => {
31 maybe_type!($syn_t, $rust_t);
32 };
33 (@ref $syn_t:expr, $rust_t:ty) => {
34 maybe_type!($syn_t, &$rust_t);
35 };
36 (@opt $syn_t:expr, $rust_t:ty) => {
37 maybe_type!($syn_t, &Option<$rust_t>);
38 };
39 (@opt_ref $syn_t:expr, $rust_t:ty) => {
40 maybe_type!($syn_t, &Option<&$rust_t>);
41 };
42 (@ptr $syn_t:expr, $rust_t:ty) => {
43 maybe_type!($syn_t, *const $rust_t);
44 };
45 (@primitive $syn_t:expr, $rust_t:ty) => {
46 maybe_type!(@naked $syn_t, $rust_t);
47 maybe_type!(@ref $syn_t, $rust_t);
48 maybe_type!(@opt $syn_t, $rust_t);
49 maybe_type!(@opt_ref $syn_t, $rust_t);
50 maybe_type!(@ptr $syn_t, $rust_t);
51 };
52 (@string $syn_t:expr, $rust_t:ty) => {
53 maybe_type!(@naked $syn_t, $rust_t);
54 maybe_type!(@opt $syn_t, $rust_t);
55 };
56}
57
58macro_rules! maybe_types {
59 ($syn_t:expr, $($rust_t:ty),+) => {
60 $(
61 maybe_type!($syn_t, $rust_t);
62 )*
63 };
64 (@$tag:ident $syn_t:expr, $($rust_t:ty),+) => {
65 $(
66 maybe_type!(@$tag $syn_t, $rust_t);
67 )*
68 };
69}
70
71#[allow(clippy::cognitive_complexity)]
77pub(crate) fn from_syn_type(ty: &syn::Type) -> Option<ArgTypeInfo> {
78 maybe_types!(@primitive ty, i8, u8, i16, u16, i32, u32, i64, u64, usize, isize);
81 maybe_types!(@string ty, &str, &String);
82
83 #[cfg(unix)] maybe_types!(@string ty, &OsStr, &OsString);
85 maybe_types!(@string ty, &CStr, &CString);
86
87 maybe_type!(@primitive ty, bool);
88
89 None
91}
92
93#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
94pub(crate) struct ArgTypeInfo {
95 #[serde(with = "serde_helpers::string")]
96 c_type: CType,
97 c_type_str: String,
98 rust_type_str: String,
99}
100
101#[allow(dead_code)] impl ArgTypeInfo {
103 pub fn new<T: ProbeArgType<T>>() -> ArgTypeInfo {
104 ArgTypeInfo {
105 c_type: <<<T as ProbeArgType<T>>::WrapperType as ProbeArgWrapper>::CType as ProbeArgNativeTypeInfo>::get_c_type(),
106 c_type_str: <<<T as ProbeArgType<T>>::WrapperType as ProbeArgWrapper>::CType as ProbeArgNativeTypeInfo>::get_c_type_str().to_owned(),
107 rust_type_str: <<<T as ProbeArgType<T>>::WrapperType as ProbeArgWrapper>::CType as ProbeArgNativeTypeInfo>::get_rust_type_str().to_owned()
108 }
109 }
110
111 pub fn get_c_type_enum(&self) -> CType {
114 self.c_type.clone()
115 }
116
117 pub fn get_c_type_str(&self) -> &str {
120 &self.c_type_str
121 }
122
123 pub fn get_rust_type_str(&self) -> &str {
135 &self.rust_type_str
136 }
137}
138
139#[cfg(test)]
140mod test {
141 use super::*;
142 use crate::testdata::*;
143
144 macro_rules! test_type {
145 ($rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
146 let syn_typ: syn::Type = parse_quote! { $rust_t };
147 assert_eq!(
148 Some(ArgTypeInfo {
149 c_type: $c_type,
150 c_type_str: $c_type.to_string(),
151 rust_type_str: $rust_type_str.to_string(),
152 }),
153 from_syn_type(&syn_typ),
154 "Got unexpected arg type info for type expression '{}'", stringify!($rust_t)
155 );
156 };
157 (@naked $rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
158 test_type!($rust_t, $c_type, $rust_type_str);
159 };
160 (@primitive_ref $rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
162 test_type!(&$rust_t, $c_type, $rust_type_str);
163 };
164 (@primitive_opt $rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
167 test_type!(&Option<$rust_t>, $c_type, $rust_type_str);
168 };
169 (@primitive_opt_ref $rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
171 test_type!(&Option<&$rust_t>, $c_type, $rust_type_str);
172 };
173 (@primitive_ptr $rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
175 test_type!(*const $rust_t, CType::VoidPtr, "*const std::os::raw::c_void");
176 };
177 (@primitive_ptr i8, $c_type:expr, $rust_type_str:expr) => {
178 test_type!(*const $rust_t, CType::CharPtr, "*const std::os::raw::c_char");
179 };
180 (@primitive_ptr u8, $c_type:expr, $rust_type_str:expr) => {
181 test_type!(*const $rust_t, CType::UCharPtr, "*const std::os::raw::c_uchar");
182 };
183 (@primitive $rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
184 test_type!(@naked $rust_t, $c_type, $rust_type_str);
185 test_type!(@primitive_ptr $rust_t, $c_type, $rust_type_str);
186 test_type!(@primitive_ref $rust_t, $c_type, $rust_type_str);
187 test_type!(@primitive_opt $rust_t, $c_type, $rust_type_str);
188 test_type!(@primitive_opt_ref $rust_t, $c_type, $rust_type_str);
189 };
190 (@string $rust_t:ty, $c_type:expr, $rust_type_str:expr) => {
191 test_type!(@naked $rust_t, $c_type, $rust_type_str);
192 test_type!(@primitive_opt $rust_t, $c_type, $rust_type_str);
193 };
194 }
195
196 #[test]
197 fn test_type_support() {
198 test_type!(@primitive i8, CType::Char, "std::os::raw::c_char");
199 test_type!(@primitive u8, CType::UChar, "std::os::raw::c_uchar");
200 test_type!(@primitive i16, CType::Short, "std::os::raw::c_short");
201 test_type!(@primitive u16, CType::UShort, "std::os::raw::c_ushort");
202 test_type!(@primitive i32, CType::Int, "std::os::raw::c_int");
203 test_type!(@primitive u32, CType::UInt, "std::os::raw::c_uint");
204 test_type!(@primitive i64, CType::LongLong, "std::os::raw::c_longlong");
205 test_type!(@primitive u64, CType::ULongLong, "std::os::raw::c_ulonglong");
206 test_type!(@primitive usize, CType::SizeT, "libc::size_t");
207 test_type!(@primitive isize, CType::SSizeT, "libc::ssize_t");
208 test_type!(@primitive bool, CType::Int, "std::os::raw::c_int");
209
210 test_type!(@string &str, CType::CharPtr, "*const std::os::raw::c_char");
211 test_type!(@string &String, CType::CharPtr, "*const std::os::raw::c_char");
212
213 #[cfg(unix)] test_type!(@string &OsStr, CType::CharPtr, "*const std::os::raw::c_char");
215 #[cfg(unix)] test_type!(@string &OsString, CType::CharPtr, "*const std::os::raw::c_char");
217
218 test_type!(@string &CStr, CType::CharPtr, "*const std::os::raw::c_char");
219 test_type!(@string &CString, CType::CharPtr, "*const std::os::raw::c_char");
220 }
221
222 #[test]
223 fn test_support_for_all_test_traits() {
224 for test_trait in
229 get_test_provider_traits(|t: &TestProviderTrait| t.expected_error.is_none()).into_iter()
230 {
231 for probe in test_trait.probes.unwrap().into_iter() {
237 for (name, rust_syn_type, c_type) in probe.args.into_iter() {
238 let arg_type_info = from_syn_type(&rust_syn_type);
239
240 assert_ne!(None, arg_type_info,
241 "test trait '{}' probe '{}' arg '{}' has a type which `from_syn_type` can't identify",
242 test_trait.description,
243 probe.name,
244 name);
245
246 let arg_type_info = arg_type_info.unwrap();
247 assert_eq!(c_type, arg_type_info.get_c_type_enum(),
248 "test trait '{}' probe '{}' arg '{}' has a type for which `from_syn_type` returned an incorrect `CType` (and, probably, other wrapper types also)",
249 test_trait.description,
250 probe.name,
251 name);
252 }
253 }
254 }
255 }
256}