1use log::debug;
2use std::rc::Rc;
3use syn::spanned::Spanned;
4
5use super::{cpp_code, fclass::need_plain_class};
6use crate::{
7 error::{invalid_src_id_span, Result},
8 typemap::{
9 ast::ForeignTypeName,
10 ty::{ForeignConversionIntermediate, ForeignConversionRule, ForeignTypeS, RustType},
11 utils::{boxed_type, unpack_from_heap_pointer},
12 RustTypeIdx, TypeConvCode, FROM_VAR_TEMPLATE, TO_VAR_TEMPLATE,
13 },
14 types::{ForeignClassInfo, SelfTypeDesc},
15 TypeMap,
16};
17
18pub(in crate::cpp) fn register_typemap_for_self_type(
19 conv_map: &mut TypeMap,
20 class: &ForeignClassInfo,
21 this_type: RustType,
22 self_desc: &SelfTypeDesc,
23) -> Result<()> {
24 let span = this_type.ty.span();
25
26 let void_ptr_ty = parse_type_spanned_checked!(span, *mut ::std::os::raw::c_void);
27 let void_ptr_rust_ty = conv_map.find_or_alloc_rust_type_with_suffix(
28 &void_ptr_ty,
29 &this_type.normalized_name,
30 class.src_id,
31 );
32
33 let const_void_ptr_ty = parse_type_spanned_checked!(span, *const ::std::os::raw::c_void);
34 let const_void_ptr_rust_ty = conv_map.find_or_alloc_rust_type_with_suffix(
35 &const_void_ptr_ty,
36 &this_type.normalized_name,
37 class.src_id,
38 );
39
40 let this_type_inner = boxed_type(conv_map, &this_type);
41
42 let span = this_type_inner.ty.span();
43 let ty = this_type_inner.to_type_without_lifetimes();
44 let gen_ty = parse_type_spanned_checked!(span, & #ty);
45 let this_type_ref = conv_map.find_or_alloc_rust_type(&gen_ty, class.src_id);
46
47 let gen_ty = parse_type_spanned_checked!(span, &mut #ty);
48 let this_type_mut_ref = conv_map.find_or_alloc_rust_type(&gen_ty, class.src_id);
49
50 register_intermediate_pointer_types(
51 conv_map,
52 class,
53 void_ptr_rust_ty.to_idx(),
54 const_void_ptr_rust_ty.to_idx(),
55 )?;
56 register_rust_ty_conversion_rules(
57 conv_map,
58 class,
59 this_type.clone(),
60 this_type_inner.to_idx(),
61 void_ptr_rust_ty.to_idx(),
62 const_void_ptr_rust_ty.to_idx(),
63 this_type_ref.to_idx(),
64 this_type_mut_ref.to_idx(),
65 )?;
66
67 let self_type = conv_map.find_or_alloc_rust_type(&self_desc.self_type, class.src_id);
68
69 register_main_foreign_types(
70 conv_map,
71 class,
72 this_type.to_idx(),
73 self_type.to_idx(),
74 void_ptr_rust_ty.to_idx(),
75 const_void_ptr_rust_ty.to_idx(),
76 this_type_ref.to_idx(),
77 this_type_mut_ref.to_idx(),
78 )?;
79 Ok(())
80}
81
82fn register_intermediate_pointer_types(
83 conv_map: &mut TypeMap,
84 class: &ForeignClassInfo,
85 void_ptr_rust_ty: RustTypeIdx,
86 const_void_ptr_rust_ty: RustTypeIdx,
87) -> Result<()> {
88 let c_ftype = ForeignTypeS {
89 name: ForeignTypeName::new(
90 format!("{} *", cpp_code::c_class_type(class)),
91 (class.src_id, class.name.span()),
92 ),
93 provided_by_module: vec![format!("\"{}\"", cpp_code::c_header_name(class)).into()],
94 into_from_rust: Some(ForeignConversionRule {
95 rust_ty: void_ptr_rust_ty,
96 intermediate: None,
97 }),
98 from_into_rust: Some(ForeignConversionRule {
99 rust_ty: void_ptr_rust_ty,
100 intermediate: None,
101 }),
102 };
103 conv_map.alloc_foreign_type(c_ftype)?;
104
105 let c_const_ftype = ForeignTypeS {
106 name: ForeignTypeName::new(
107 format!("const {} *", cpp_code::c_class_type(class)),
108 (class.src_id, class.name.span()),
109 ),
110 provided_by_module: vec![format!("\"{}\"", cpp_code::c_header_name(class)).into()],
111 into_from_rust: Some(ForeignConversionRule {
112 rust_ty: const_void_ptr_rust_ty,
113 intermediate: None,
114 }),
115 from_into_rust: Some(ForeignConversionRule {
116 rust_ty: const_void_ptr_rust_ty,
117 intermediate: None,
118 }),
119 };
120 conv_map.alloc_foreign_type(c_const_ftype)?;
121 Ok(())
122}
123
124fn register_rust_ty_conversion_rules(
125 conv_map: &mut TypeMap,
126 class: &ForeignClassInfo,
127 this_type: RustType,
128 this_type_inner: RustTypeIdx,
129 void_ptr_rust_ty: RustTypeIdx,
130 const_void_ptr_rust_ty: RustTypeIdx,
131 this_type_ref: RustTypeIdx,
132 this_type_mut_ref: RustTypeIdx,
133) -> Result<()> {
134 conv_map.add_conversion_rule(
136 const_void_ptr_rust_ty,
137 this_type_ref,
138 TypeConvCode::new2(
139 format!(
140 r#"
141 assert!(!{from_var}.is_null());
142 let {to_var}: {this_type_ref} = unsafe {{ &*({from_var} as *const {this_type_inner}) }};
143"#,
144 to_var = TO_VAR_TEMPLATE,
145 from_var = FROM_VAR_TEMPLATE,
146 this_type_ref = conv_map[this_type_ref],
147 this_type_inner = conv_map[this_type_inner],
148 ),
149 invalid_src_id_span(),
150 )
151 .into(),
152 );
153
154 conv_map.add_conversion_rule(
156 void_ptr_rust_ty,
157 this_type_mut_ref,
158 TypeConvCode::new2(
159 format!(
160 r#"
161 assert!(!{from_var}.is_null());
162 let {to_var}: {this_type_mut_ref} = unsafe {{ &mut *({from_var} as *mut {this_type_inner}) }};
163"#,
164 to_var = TO_VAR_TEMPLATE,
165 from_var = FROM_VAR_TEMPLATE,
166 this_type_mut_ref = conv_map[this_type_mut_ref],
167 this_type_inner = conv_map[this_type_inner],
168 ),
169 invalid_src_id_span(),
170 )
171 .into(),
172 );
173
174 let ty = conv_map[this_type_inner].to_type_without_lifetimes();
177 let span = ty.span();
178 let gen_ty = parse_type_spanned_checked!(span, *mut #ty);
179 let this_type_mut_ptr = conv_map.find_or_alloc_rust_type(&gen_ty, class.src_id);
180
181 conv_map.add_conversion_rule(
182 void_ptr_rust_ty,
183 this_type_mut_ptr.to_idx(),
184 TypeConvCode::new2(
185 format!(
186 r#"
187 assert!(!{from_var}.is_null());
188 let {to_var}: {this_type_mut_ptr} = {from_var} as {this_type_mut_ptr};
189 "#,
190 to_var = TO_VAR_TEMPLATE,
191 from_var = FROM_VAR_TEMPLATE,
192 ),
193 invalid_src_id_span(),
194 )
195 .into(),
196 );
197
198 let unpack_code = unpack_from_heap_pointer(&this_type, TO_VAR_TEMPLATE, true);
199 conv_map.add_conversion_rule(
200 this_type_mut_ptr.to_idx(),
201 this_type.to_idx(),
202 TypeConvCode::new(format!("\n{unpack_code}\n"), invalid_src_id_span()).into(),
203 );
204
205 conv_map.add_conversion_rule(
207 this_type.to_idx(),
208 void_ptr_rust_ty,
209 TypeConvCode::new(
210 format!(
211 "let {to_var}: {ptr_type} = <{this_type}>::box_object({from_var});",
212 to_var = TO_VAR_TEMPLATE,
213 ptr_type = conv_map[void_ptr_rust_ty].typename(),
214 this_type = this_type,
215 from_var = FROM_VAR_TEMPLATE
216 ),
217 invalid_src_id_span(),
218 )
219 .into(),
220 );
221
222 conv_map.add_conversion_rule(
224 this_type_ref,
225 const_void_ptr_rust_ty,
226 TypeConvCode::new(
227 format!(
228 "let {to_var}: {ptr_type} = ({from_var} as *const {this_type}) as {ptr_type};",
229 to_var = TO_VAR_TEMPLATE,
230 ptr_type = conv_map[const_void_ptr_rust_ty].typename(),
231 this_type = conv_map[this_type_inner],
232 from_var = FROM_VAR_TEMPLATE,
233 ),
234 invalid_src_id_span(),
235 )
236 .into(),
237 );
238
239 Ok(())
240}
241
242fn register_main_foreign_types(
243 conv_map: &mut TypeMap,
244 class: &ForeignClassInfo,
245 this_type: RustTypeIdx,
246 self_type: RustTypeIdx,
247 void_ptr_rust_ty: RustTypeIdx,
248 const_void_ptr_rust_ty: RustTypeIdx,
249 this_type_ref: RustTypeIdx,
250 this_type_mut_ref: RustTypeIdx,
251) -> Result<()> {
252 debug!(
253 "register_main_foreign_types: this {}, self {}",
254 conv_map[this_type], conv_map[self_type]
255 );
256 let class_ftype = ForeignTypeS {
257 name: ForeignTypeName::new(class.name.to_string(), (class.src_id, class.name.span())),
258 provided_by_module: vec![format!("\"{}\"", cpp_code::cpp_header_name(class)).into()],
259 into_from_rust: Some(ForeignConversionRule {
260 rust_ty: this_type,
261 intermediate: Some(ForeignConversionIntermediate {
262 input_to_output: false,
263 intermediate_ty: void_ptr_rust_ty,
264 conv_code: Rc::new(TypeConvCode::new(
265 format!(
266 "{class_name}(static_cast<{c_type} *>({var}))",
267 class_name = class.name,
268 c_type = cpp_code::c_class_type(class),
269 var = FROM_VAR_TEMPLATE
270 ),
271 invalid_src_id_span(),
272 )),
273 }),
274 }),
275 from_into_rust: Some(ForeignConversionRule {
276 rust_ty: this_type,
277 intermediate: Some(ForeignConversionIntermediate {
278 input_to_output: false,
279 intermediate_ty: void_ptr_rust_ty,
280 conv_code: Rc::new(TypeConvCode::new(
281 format!("{FROM_VAR_TEMPLATE}.release()"),
282 invalid_src_id_span(),
283 )),
284 }),
285 }),
286 };
287 conv_map.alloc_foreign_type(class_ftype)?;
288
289 let class_ftype_ref_in = ForeignTypeS {
290 name: ForeignTypeName::new(
291 format!("const {} &", class.name),
292 (class.src_id, class.name.span()),
293 ),
294 provided_by_module: vec![format!("\"{}\"", cpp_code::cpp_header_name(class)).into()],
295 from_into_rust: Some(ForeignConversionRule {
296 rust_ty: this_type_ref,
297 intermediate: Some(ForeignConversionIntermediate {
298 input_to_output: false,
299 intermediate_ty: const_void_ptr_rust_ty,
300 conv_code: Rc::new(TypeConvCode::new(
301 format!(
302 "static_cast<const {} *>({})",
303 cpp_code::c_class_type(class),
304 FROM_VAR_TEMPLATE
305 ),
306 invalid_src_id_span(),
307 )),
308 }),
309 }),
310 into_from_rust: None,
311 };
312 conv_map.alloc_foreign_type(class_ftype_ref_in)?;
313
314 let is_plain_class = need_plain_class(class);
315
316 if !is_plain_class {
317 let class_ftype_ref_out = ForeignTypeS {
318 name: ForeignTypeName::new(
319 format!("{}Ref", class.name),
320 (class.src_id, class.name.span()),
321 ),
322 provided_by_module: vec![format!("\"{}\"", cpp_code::cpp_header_name(class)).into()],
323 into_from_rust: Some(ForeignConversionRule {
324 rust_ty: this_type_ref,
325 intermediate: Some(ForeignConversionIntermediate {
326 input_to_output: false,
327 intermediate_ty: const_void_ptr_rust_ty,
328 conv_code: Rc::new(TypeConvCode::new(
329 format!(
330 "{class}Ref{{ static_cast<const {c_type} *>({var}) }}",
331 class = class.name,
332 c_type = cpp_code::c_class_type(class),
333 var = FROM_VAR_TEMPLATE
334 ),
335 invalid_src_id_span(),
336 )),
337 }),
338 }),
339 from_into_rust: None,
340 };
341 conv_map.alloc_foreign_type(class_ftype_ref_out)?;
342 }
343
344 let class_ftype_mut_ref_in = ForeignTypeS {
345 name: ForeignTypeName::new(
346 format!("{} &", class.name),
347 (class.src_id, class.name.span()),
348 ),
349 provided_by_module: vec![format!("\"{}\"", cpp_code::cpp_header_name(class)).into()],
350 from_into_rust: Some(ForeignConversionRule {
351 rust_ty: this_type_mut_ref,
352 intermediate: Some(ForeignConversionIntermediate {
353 input_to_output: false,
354 intermediate_ty: void_ptr_rust_ty,
355 conv_code: Rc::new(TypeConvCode::new(
356 format!(
357 "static_cast<{} *>({})",
358 cpp_code::c_class_type(class),
359 FROM_VAR_TEMPLATE
360 ),
361 invalid_src_id_span(),
362 )),
363 }),
364 }),
365 into_from_rust: None,
366 };
367 conv_map.alloc_foreign_type(class_ftype_mut_ref_in)?;
368
369 if self_type != this_type {
370 let self_type = conv_map[self_type].clone();
371 {
372 let span = self_type.ty.span();
373 let self_type_ty = self_type.to_type_without_lifetimes();
374 let gen_ty = parse_type_spanned_checked!(span, &mut #self_type_ty);
375 let self_type_mut_ref = conv_map.find_or_alloc_rust_type(&gen_ty, class.src_id);
376
377 let class_ftype_mut_ref_in = ForeignTypeS {
378 name: ForeignTypeName::new_with_unique_prefix(
379 format!("/**/{} &", class.name),
380 "/**/",
381 (class.src_id, class.name.span()),
382 ),
383 provided_by_module: vec![format!("\"{}\"", cpp_code::cpp_header_name(class)).into()],
384 from_into_rust: Some(ForeignConversionRule {
385 rust_ty: self_type_mut_ref.to_idx(),
386 intermediate: Some(ForeignConversionIntermediate {
387 input_to_output: false,
388 intermediate_ty: void_ptr_rust_ty,
389 conv_code: Rc::new(TypeConvCode::new(
390 format!(
391 "static_cast<{} *>({})",
392 cpp_code::c_class_type(class),
393 FROM_VAR_TEMPLATE
394 ),
395 invalid_src_id_span(),
396 )),
397 }),
398 }),
399 into_from_rust: None,
400 };
401 conv_map.alloc_foreign_type(class_ftype_mut_ref_in)?;
402 }
403 {
404 let self_type_ty = self_type.to_type_without_lifetimes();
405 let span = self_type.ty.span();
406 let gen_ty = parse_type_spanned_checked!(span, & #self_type_ty);
407 let self_type_ref = conv_map.find_or_alloc_rust_type(&gen_ty, class.src_id);
408
409 let class_ftype_ref_in = ForeignTypeS {
410 name: ForeignTypeName::new_with_unique_prefix(
411 format!("/**/const {} &", class.name),
412 "/**/",
413 (class.src_id, class.name.span()),
414 ),
415 provided_by_module: vec![format!("\"{}\"", cpp_code::cpp_header_name(class)).into()],
416 from_into_rust: Some(ForeignConversionRule {
417 rust_ty: self_type_ref.to_idx(),
418 intermediate: Some(ForeignConversionIntermediate {
419 input_to_output: false,
420 intermediate_ty: const_void_ptr_rust_ty,
421 conv_code: Rc::new(TypeConvCode::new(
422 format!(
423 "static_cast<const {} *>({})",
424 cpp_code::c_class_type(class),
425 FROM_VAR_TEMPLATE
426 ),
427 invalid_src_id_span(),
428 )),
429 }),
430 }),
431 into_from_rust: None,
432 };
433 conv_map.alloc_foreign_type(class_ftype_ref_in)?;
434 }
435 }
436
437 Ok(())
438}