flapigen/cpp/
map_class_self_type.rs

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    // *const c_void -> &"class"
135    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    // *mut c_void -> &mut "class"
155    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    // *const c_void -> "class", two steps to make it more expensive
175    // for type graph path search
176    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    //"class" -> *mut void
206    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    //&"class" -> *const void
223    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}