1use std::collections::{btree_map::Entry, BTreeMap};
4
5use serde::{Deserialize, Serialize};
6
7use crate::record::type_name::{truc_dynamic_type_name, truc_type_name};
8
9#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
11pub struct TypeInfo {
12 pub name: String,
14 pub size: usize,
16 pub align: usize,
18}
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
22pub struct DynamicTypeInfo {
23 pub info: TypeInfo,
25 pub allow_uninit: bool,
28}
29
30pub trait TypeResolver {
32 fn type_info<T>(&self) -> TypeInfo;
34
35 fn dynamic_type_info(&self, type_name: &str) -> DynamicTypeInfo;
37}
38
39impl<R> TypeResolver for &R
40where
41 R: TypeResolver,
42{
43 fn type_info<T>(&self) -> TypeInfo {
44 R::type_info::<T>(self)
45 }
46
47 fn dynamic_type_info(&self, type_name: &str) -> DynamicTypeInfo {
48 R::dynamic_type_info(self, type_name)
49 }
50}
51
52pub struct HostTypeResolver;
55
56impl TypeResolver for HostTypeResolver {
57 fn type_info<T>(&self) -> TypeInfo {
59 TypeInfo {
60 name: truc_type_name::<T>(),
61 size: std::mem::size_of::<T>(),
62 align: std::mem::align_of::<T>(),
63 }
64 }
65
66 fn dynamic_type_info(&self, _type_name: &str) -> DynamicTypeInfo {
68 unimplemented!("HostTypeResolver cannot resolve dynamic types")
69 }
70}
71
72macro_rules! add_type {
73 ($resolver:ident, $type:ty) => {
74 $resolver.add_type::<$type>();
75 $resolver.add_type::<Option<$type>>();
76 };
77 ($resolver:ident, $type:ty, allow_uninit) => {
78 $resolver.add_type_allow_uninit::<$type>();
79 $resolver.add_type_allow_uninit::<Option<$type>>();
80 };
81}
82macro_rules! add_type_and_arrays {
83 ($resolver:ident, $type:ty) => {
84 add_type!($resolver, $type);
85 add_type!($resolver, [$type; 1]);
86 add_type!($resolver, [$type; 2]);
87 add_type!($resolver, [$type; 3]);
88 add_type!($resolver, [$type; 4]);
89 add_type!($resolver, [$type; 5]);
90 add_type!($resolver, [$type; 6]);
91 add_type!($resolver, [$type; 7]);
92 add_type!($resolver, [$type; 8]);
93 add_type!($resolver, [$type; 9]);
94 add_type!($resolver, [$type; 10]);
95 };
96 ($resolver:ident, $type:ty, allow_uninit) => {
97 add_type!($resolver, $type, allow_uninit);
98 add_type!($resolver, [$type; 1], allow_uninit);
99 add_type!($resolver, [$type; 2], allow_uninit);
100 add_type!($resolver, [$type; 3], allow_uninit);
101 add_type!($resolver, [$type; 4], allow_uninit);
102 add_type!($resolver, [$type; 5], allow_uninit);
103 add_type!($resolver, [$type; 6], allow_uninit);
104 add_type!($resolver, [$type; 7], allow_uninit);
105 add_type!($resolver, [$type; 8], allow_uninit);
106 add_type!($resolver, [$type; 9], allow_uninit);
107 add_type!($resolver, [$type; 10], allow_uninit);
108 };
109}
110
111#[derive(Debug, From, Serialize, Deserialize)]
120pub struct StaticTypeResolver {
121 types: BTreeMap<String, DynamicTypeInfo>,
122}
123
124impl StaticTypeResolver {
125 pub fn new() -> Self {
127 Self {
128 types: BTreeMap::new(),
129 }
130 }
131
132 pub fn add_type<T>(&mut self) {
134 let type_name = truc_type_name::<T>();
135 match self.types.entry(type_name.clone()) {
136 Entry::Vacant(vacant) => {
137 vacant.insert(DynamicTypeInfo {
138 info: TypeInfo {
139 name: type_name,
140 size: std::mem::size_of::<T>(),
141 align: std::mem::align_of::<T>(),
142 },
143 allow_uninit: false,
144 });
145 }
146 Entry::Occupied(occupied) => {
147 panic!(
148 "Type {} is already defined with {:?}",
149 type_name,
150 occupied.get()
151 );
152 }
153 }
154 }
155
156 pub fn add_type_allow_uninit<T>(&mut self)
158 where
159 T: Copy,
160 {
161 let type_name = truc_type_name::<T>();
162 match self.types.entry(type_name.clone()) {
163 Entry::Vacant(vacant) => {
164 vacant.insert(DynamicTypeInfo {
165 info: TypeInfo {
166 name: type_name,
167 size: std::mem::size_of::<T>(),
168 align: std::mem::align_of::<T>(),
169 },
170 allow_uninit: true,
171 });
172 }
173 Entry::Occupied(occupied) => {
174 panic!(
175 "Type {} is already defined with {:?}",
176 type_name,
177 occupied.get()
178 );
179 }
180 }
181 }
182
183 pub fn add_std_types(&mut self) {
192 add_type_and_arrays!(self, u8, allow_uninit);
193 add_type_and_arrays!(self, u16, allow_uninit);
194 add_type_and_arrays!(self, u32, allow_uninit);
195 add_type_and_arrays!(self, u64, allow_uninit);
196 add_type_and_arrays!(self, u128, allow_uninit);
197 add_type_and_arrays!(self, usize, allow_uninit);
198
199 add_type_and_arrays!(self, i8, allow_uninit);
200 add_type_and_arrays!(self, i16, allow_uninit);
201 add_type_and_arrays!(self, i32, allow_uninit);
202 add_type_and_arrays!(self, i64, allow_uninit);
203 add_type_and_arrays!(self, i128, allow_uninit);
204 add_type_and_arrays!(self, isize, allow_uninit);
205
206 add_type_and_arrays!(self, f32, allow_uninit);
207 add_type_and_arrays!(self, f64, allow_uninit);
208
209 add_type_and_arrays!(self, char, allow_uninit);
210
211 add_type_and_arrays!(self, bool, allow_uninit);
212
213 add_type_and_arrays!(self, String);
214 add_type_and_arrays!(self, Box<str>);
215
216 add_type_and_arrays!(self, Vec<()>);
217 }
218
219 #[cfg(feature = "uuid")]
221 pub fn add_uuid_types(&mut self) {
222 add_type_and_arrays!(self, uuid::Uuid, allow_uninit);
223 }
224
225 pub fn add_all_types(&mut self) {
229 self.add_std_types();
230 #[cfg(feature = "uuid")]
231 self.add_uuid_types();
232 }
233
234 pub fn to_json_value(&self) -> Result<serde_json::Value, serde_json::Error> {
236 serde_json::to_value(&self.types)
237 }
238
239 pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
241 serde_json::to_string(&self.types)
242 }
243
244 pub fn to_json_string_pretty(&self) -> Result<String, serde_json::Error> {
246 serde_json::to_string_pretty(&self.types)
247 }
248}
249
250impl Default for StaticTypeResolver {
251 fn default() -> Self {
253 Self::new()
254 }
255}
256
257impl TypeResolver for StaticTypeResolver {
258 fn type_info<T>(&self) -> TypeInfo {
260 let type_name = truc_type_name::<T>();
261 self.types
262 .get(&type_name)
263 .unwrap_or_else(|| panic!("Could not resolve type {}", type_name))
264 .info
265 .clone()
266 }
267
268 fn dynamic_type_info(&self, type_name: &str) -> DynamicTypeInfo {
270 let type_name = truc_dynamic_type_name(type_name);
271 self.types
272 .get(&type_name)
273 .unwrap_or_else(|| panic!("Could not resolve type {}", type_name))
274 .clone()
275 }
276}
277
278#[cfg(test)]
279#[cfg_attr(coverage_nightly, coverage(off))]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn test_static_type_resolver() {
285 let mut type_infos = StaticTypeResolver::default();
286
287 type_infos.add_all_types();
288
289 let json = type_infos.to_json_value().unwrap();
290 type_infos.to_json_string().unwrap();
291 type_infos.to_json_string_pretty().unwrap();
292
293 let types = json.as_object().unwrap();
294
295 for t in [
296 "usize",
297 "isize",
298 "f32",
299 "f64",
300 "char",
301 "bool",
302 "String",
303 "Box < str >",
304 "Vec < () >",
305 ] {
306 assert!(types.contains_key(&t.to_owned()), "{}", t);
307 assert!(types.contains_key(&format!("[{} ; 2]", t)), "[{} ; 2]", t);
308 assert!(types.contains_key(&format!("[{} ; 10]", t)), "[{} ; 10]", t);
309 }
310
311 let name = assert_matches!(
312 type_infos.type_info::<usize>(),
313 TypeInfo {
314 name,
315 size: _,
316 align: _
317 } => name
318 );
319 assert_eq!(name, "usize");
320
321 let name = assert_matches!(
322 type_infos.dynamic_type_info("isize"),
323 DynamicTypeInfo {
324 info: TypeInfo {
325 name,
326 size: _,
327 align: _
328 },
329 allow_uninit: true,
330 } => name
331 );
332 assert_eq!(name, "isize");
333
334 let name = assert_matches!(
335 type_infos.dynamic_type_info("String"),
336 DynamicTypeInfo {
337 info: TypeInfo {
338 name,
339 size: _,
340 align: _
341 },
342 allow_uninit: false,
343 } => name
344 );
345 assert_eq!(name, "String");
346 }
347
348 #[test]
349 fn test_type_added_twice() {
350 let mut type_infos = StaticTypeResolver::default();
351
352 type_infos.add_type::<usize>();
353
354 let result = std::panic::catch_unwind(move || type_infos.add_type::<usize>());
355 assert!(result.is_err());
356 }
357
358 #[test]
359 fn test_type_added_twice_allow_uninit() {
360 let mut type_infos = StaticTypeResolver::default();
361
362 type_infos.add_type_allow_uninit::<usize>();
363
364 let result = std::panic::catch_unwind(move || type_infos.add_type_allow_uninit::<usize>());
365 assert!(result.is_err());
366 }
367}