rusty_bind_parser/
extern_module_translator.rs

1//
2// Wildland Project
3//
4// Copyright © 2022 Golem Foundation,
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License version 3 as published by
8// the Free Software Foundation.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18use std::collections::hash_map::Entry;
19use std::collections::{HashMap, HashSet};
20use std::ops::Deref;
21
22use anyhow::{anyhow, Context};
23use proc_macro2::{Ident, Span};
24use quote::ToTokens;
25use syn::punctuated::Punctuated;
26use syn::{
27    parse_quote,
28    FnArg,
29    ForeignItem,
30    ForeignItemFn,
31    ForeignItemType,
32    GenericArgument,
33    ItemEnum,
34    ItemForeignMod,
35    Pat,
36    PatIdent,
37    PathArguments,
38    PathSegment,
39    Receiver,
40    ReturnType,
41    Token,
42    TraitBound,
43    Type,
44    TypeParamBound,
45    TypeReference,
46    TypeTraitObject,
47};
48
49pub use crate::binding_types::*;
50use crate::cpp::exception_class_name;
51use crate::cpp::templates::TargetLanguageTypeName;
52use crate::enum_helpers::is_primitive_enum;
53use crate::ordered_hash_set::OrderedHashSet;
54use crate::utils::{is_primitive, BuildContext};
55
56/// The structure keeps the Rust types wrappers,
57/// methods of the structures and global functions
58/// signatures. `user_custom_types` is a subset
59/// of `rust_types_wrappers`, since the latter collection
60/// keeps all the wrappers that will be handled, and the
61/// first one keeps only a user defined types wrappers
62/// along with their methods.
63///
64
65pub struct ExternModuleTranslator {
66    pub shared_enums: HashSet<ItemEnum>,
67    pub exception_names: HashSet<String>,
68    pub rust_types_wrappers: OrderedHashSet<WrapperType>,
69    pub user_custom_types: HashMap<WrapperType, Vec<Function>>,
70    pub user_traits: HashMap<WrapperType, Vec<Function>>,
71    pub global_functions: Vec<Function>,
72    pub exception_trait_methods: HashSet<Function>,
73    pub declared_impls: HashMap<String, Vec<String>>,
74}
75
76impl ExternModuleTranslator {
77    pub fn new(shared_enums: HashSet<ItemEnum>) -> Self {
78        let mut rust_types_wrappers = OrderedHashSet::default();
79        shared_enums
80            .iter()
81            .for_each(|enum_item| rust_types_wrappers.insert(parse_enum_wrapper(enum_item)));
82
83        Self {
84            shared_enums,
85            rust_types_wrappers,
86            exception_names: Default::default(),
87            user_custom_types: Default::default(),
88            user_traits: Default::default(),
89            global_functions: Default::default(),
90            exception_trait_methods: Default::default(),
91            declared_impls: Default::default(),
92        }
93    }
94
95    /// Takes extern "Rust" module and translates its functions.
96    /// It also stores information about the functions signatures
97    /// for a further processing.
98    ///
99    pub fn parse_items_in_extern_rust_module(
100        &mut self,
101        extern_module: &ItemForeignMod,
102        context: &BuildContext,
103    ) -> anyhow::Result<()> {
104        extern_module
105            .items
106            .iter()
107            .filter(|extern_item| match extern_item {
108                ForeignItem::Fn(function) => context.check_cfg_attrs(&function.attrs),
109                ForeignItem::Type(type_) => context.check_cfg_attrs(&type_.attrs),
110                _ => true,
111            })
112            .try_for_each(|extern_item| match extern_item {
113                ForeignItem::Fn(function) => self.register_new_rust_function(function),
114                ForeignItem::Type(ForeignItemType { ident, .. }) => {
115                    self.register_custom_type(ident);
116                    Ok(())
117                }
118                ForeignItem::Verbatim(ts) => {
119                    if let Some(token) = ts
120                        .clone()
121                        .into_iter()
122                        .skip_while(|token| token.to_string().to_lowercase() != "type")
123                        .skip(1)
124                        .take(1)
125                        .next()
126                    {
127                        let type_name = token.to_string();
128                        struct FoldedTokens {
129                            tokens: Vec<String>,
130                            curr: String,
131                        }
132                        let traits = ts
133                            .clone()
134                            .into_iter()
135                            .skip_while(|token| token.to_string() != ":")
136                            .skip(1)
137                            .fold(
138                                FoldedTokens {
139                                    tokens: vec![],
140                                    curr: String::new(),
141                                },
142                                |mut tn, token| match token {
143                                    proc_macro2::TokenTree::Ident(ident) => {
144                                        tn.curr.push_str(ident.to_string().as_str());
145                                        tn
146                                    }
147                                    proc_macro2::TokenTree::Punct(punct) => match punct.as_char() {
148                                        '>' => {
149                                            tn.curr.push('>');
150                                            tn.tokens.push(tn.curr);
151                                            tn.curr = String::new();
152                                            tn
153                                        }
154                                        '+' => {
155                                            tn.tokens.push(tn.curr);
156                                            tn.curr = String::new();
157                                            tn
158                                        }
159                                        ';' | '=' => {
160                                            tn.tokens.push(tn.curr.to_owned());
161                                            tn.curr = String::new();
162                                            tn
163                                        }
164                                        c => {
165                                            tn.curr.push(c);
166                                            tn
167                                        }
168                                    },
169                                    _ => tn,
170                                },
171                            );
172                        self.declared_impls.insert(
173                            type_name.to_owned(),
174                            traits
175                                .tokens
176                                .into_iter()
177                                .filter(|t| !t.is_empty())
178                                .collect::<Vec<String>>(),
179                        );
180                        self.register_custom_type(&Ident::new(&type_name, Span::call_site()));
181                    }
182                    Ok(())
183                }
184
185                _ => Ok(()),
186            })
187    }
188
189    /// Takes extern "Traits" module and translates its functions.
190    /// It also stores information about the functions signatures
191    /// for a further processing.
192    ///
193    pub fn translate_trait_external_modules(
194        &mut self,
195        extern_module: &ItemForeignMod,
196        context: &BuildContext,
197    ) -> anyhow::Result<()> {
198        extern_module
199            .items
200            .iter()
201            .filter(|extern_item| match extern_item {
202                ForeignItem::Fn(function) => context.check_cfg_attrs(&function.attrs),
203                _ => true,
204            })
205            .try_for_each(|extern_item| match extern_item {
206                ForeignItem::Fn(original_function) => {
207                    let (associated_structure, function) =
208                        self.translate_function(original_function)?;
209                    if let Some(custom_trait) = associated_structure {
210                        self.user_traits
211                            .entry(custom_trait)
212                            .or_default()
213                            .push(function);
214                        Ok(())
215                    } else {
216                        Err(anyhow!(
217                            "Global functions are not supported in extern \"Traits\"."
218                        ))
219                    }
220                }
221                _ => Ok(()),
222            })
223    }
224
225    /// Takes extern "ExceptionTrait" module and translates its methods.
226    /// It also stores information about the functions signatures
227    /// for a further processing.
228    ///
229    pub fn translate_exception_trait_external_module(
230        &mut self,
231        extern_module: &ItemForeignMod,
232        context: &BuildContext,
233    ) -> anyhow::Result<()> {
234        extern_module
235            .items
236            .iter()
237            .filter(|extern_item| match extern_item {
238                ForeignItem::Fn(function) => context.check_cfg_attrs(&function.attrs),
239                _ => true,
240            })
241            .try_for_each(|extern_item| match extern_item {
242                ForeignItem::Fn(function) => {
243                    let method = self.translate_exception_trait_function(function)?;
244                    self.exception_trait_methods.insert(method);
245                    Ok(())
246                }
247                _ => Err(anyhow!(
248                    "Only functions are acceptable in `ExceptionsTrait`"
249                )),
250            })
251    }
252
253    /// Method stores a wrapper to a custom user's type.
254    /// Can be used while parsing `type SomeUserType;`
255    /// to register a new type `RustUserType` in
256    /// the collection of intermediate-form wrappers.
257    ///
258    fn register_custom_type(&mut self, original_type_name: &Ident) -> WrapperType {
259        let new_wrapper_type = WrapperType {
260            original_type_name: parse_quote!( #original_type_name ),
261            wrapper_name: original_type_name.to_string(),
262            rust_type: RustWrapperType::Custom,
263            reference_parameters: None,
264            impl_traits: vec![],
265        };
266        self.rust_types_wrappers.insert(new_wrapper_type.clone());
267
268        if let Entry::Vacant(entry) = self.user_custom_types.entry(new_wrapper_type.clone()) {
269            entry.insert(vec![]);
270        };
271        new_wrapper_type
272    }
273
274    /// Example:
275    /// `fn foo(self: &SomeType) -> Result<AnotherType>` ==>
276    ///     `fn foo(self: &SomeType) -> ResultAnotherType`.
277    ///
278    /// The method takes the Rust function signature and
279    /// registers every type as a `WrapperType` as well as
280    /// translates it into inner function form `Function`.
281    /// If the type has a `self` argument it returns its
282    /// WrapperType in the result.
283    ///
284    /// Example:
285    /// ```rust
286    /// use syn::{ForeignItemFn, parse_quote};
287    /// use rusty_bind_parser::extern_module_translator::*;
288    ///
289    ///
290    /// let mut local_module_translator = ExternModuleTranslator::new(Default::default());
291    /// let function: ForeignItemFn = parse_quote! { fn foo(self: &SomeType, a: u32) -> Option<u32>; };
292    /// if let (Some(associated_type), Function {
293    ///     arguments,
294    ///     return_type: Some(return_type),
295    ///     name,
296    /// }) = local_module_translator.translate_function(&function).unwrap() {
297    ///     assert!(name == "foo");
298    ///     assert!(arguments.len() == 2);
299    ///     assert!(arguments[0] == Arg {arg_name: "self".to_owned(), typ: WrapperType {
300    ///         original_type_name: parse_quote! { SomeType },
301    ///         wrapper_name: "SomeType".to_owned(),
302    ///         rust_type: RustWrapperType::Custom,
303    ///         reference_parameters: Some(ReferenceParameters::shared()),
304    ///         impl_traits: vec![]
305    ///     }});
306    ///     assert!(arguments[1] == Arg {arg_name: "a".to_owned(), typ: WrapperType {
307    ///         original_type_name: parse_quote! { u32 },
308    ///         wrapper_name: "u32".to_owned(),
309    ///         rust_type: RustWrapperType::Primitive,
310    ///         reference_parameters: None,
311    ///         impl_traits: vec![]
312    ///     }});
313    ///     assert!(associated_type == WrapperType {
314    ///         original_type_name: parse_quote! { SomeType },
315    ///         wrapper_name: "SomeType".to_owned(),
316    ///         rust_type: RustWrapperType::Custom  ,
317    ///         reference_parameters: Some(ReferenceParameters::shared()),
318    ///         impl_traits: vec![]
319    ///     });
320    ///     println!("{return_type:?}");
321    ///     assert!(return_type == WrapperType {
322    ///         original_type_name: parse_quote! { Option<u32> },
323    ///         wrapper_name: "Optionalu32".to_owned(),
324    ///         rust_type: RustWrapperType::Option(
325    ///             WrapperType {
326    ///                 original_type_name: parse_quote! { u32 },
327    ///                 wrapper_name: "u32".to_owned(),
328    ///                 rust_type: RustWrapperType::Primitive,
329    ///                 reference_parameters: None,
330    ///                 impl_traits: vec![]
331    ///             }.boxed()
332    ///         ),
333    ///         reference_parameters: None,
334    ///         impl_traits: vec![]
335    ///     });
336    /// } else {
337    ///     panic!("Translated function doesn't match.");
338    /// }
339    /// ```
340    ///
341    pub fn translate_function(
342        &mut self,
343        function: &ForeignItemFn,
344    ) -> anyhow::Result<(Option<WrapperType>, Function)> {
345        let mut arguments = vec![];
346        let mut associated_structure = None;
347
348        function
349            .sig
350            .inputs
351            .iter()
352            .try_for_each(|argument| match argument {
353                FnArg::Typed(argument) => {
354                    let new_wrapper_type = self
355                        .parse_and_register_rust_type(&argument.ty)
356                        .with_context(|| {
357                            format!(
358                                "Unsupported type in function signature: {}",
359                                function.sig.ident
360                            )
361                        })?;
362                    // TODO WILX-184
363                    if new_wrapper_type.rust_type == RustWrapperType::DataEnum {
364                        return Err(anyhow!(
365                            "Data carrying enums as functions arguments are not supported yet!"
366                        ));
367                    };
368                    if let Pat::Ident(PatIdent { ident, .. }) = argument.pat.as_ref() {
369                        arguments.push(Arg {
370                            arg_name: ident.to_string(),
371                            typ: new_wrapper_type,
372                        });
373                    }
374                    Ok(())
375                }
376                FnArg::Receiver(argument) => {
377                    let new_wrapper_type = self
378                        .parse_and_register_rust_type(&argument.ty)
379                        .with_context(|| {
380                            format!(
381                                "Unsupported type in function signature: {}",
382                                function.sig.ident
383                            )
384                        })?;
385                    // TODO WILX-184
386                    if new_wrapper_type.rust_type == RustWrapperType::DataEnum {
387                        return Err(anyhow!(
388                            "Data carrying enums as functions arguments are not supported yet!"
389                        ));
390                    };
391
392                    arguments.push(Arg {
393                        arg_name: "self".to_string(),
394                        typ: new_wrapper_type.clone(),
395                    });
396                    associated_structure = Some(new_wrapper_type);
397
398                    Ok(())
399                }
400            })?;
401        let return_type = self.translate_return_type(function)?;
402        let function_name = function.sig.ident.clone();
403        Ok((
404            associated_structure,
405            Function {
406                arguments,
407                return_type,
408                name: function_name.to_string(),
409            },
410        ))
411    }
412
413    fn translate_exception_trait_function(
414        &mut self,
415        function: &ForeignItemFn,
416    ) -> anyhow::Result<Function> {
417        if function.sig.inputs.len() != 1 {
418            Err(anyhow!(
419                "Methods of ExceptionTrait must have only one argument: &self"
420            ))
421        } else if let FnArg::Receiver(Receiver {
422            reference: Some((_, None)),
423            ..
424        }) = function.sig.inputs.first().unwrap()
425        {
426            let return_type = self.translate_return_type(function)?;
427            let associated_structure = WrapperType {
428                original_type_name: parse_quote! {ExceptionTrait},
429                wrapper_name: "ExceptionTrait".to_string(),
430                rust_type: RustWrapperType::ExceptionTrait,
431                reference_parameters: Some(ReferenceParameters::shared()),
432                impl_traits: vec![],
433            };
434            self.rust_types_wrappers
435                .insert(associated_structure.clone());
436            Ok(Function {
437                arguments: vec![Arg {
438                    arg_name: "self".to_owned(),
439                    typ: associated_structure,
440                }],
441                return_type,
442                name: function.sig.ident.to_string(),
443            })
444        } else {
445            Err(anyhow!(
446                "Methods of ExceptionTrait must have argument &self"
447            ))
448        }
449    }
450
451    fn translate_return_type(
452        &mut self,
453        function: &ForeignItemFn,
454    ) -> anyhow::Result<Option<WrapperType>> {
455        Ok(if let ReturnType::Type(_, typ) = &function.sig.output {
456            let new_wrapper_type = self.parse_and_register_rust_type(typ).with_context(|| {
457                format!(
458                    "Unsupported return type in function `{}`",
459                    function.sig.ident.clone(),
460                )
461            })?;
462            Some(new_wrapper_type)
463        } else {
464            None
465        })
466    }
467
468    /// Method registers the function in the local state of ExternModuleTranslator:
469    ///  * function signature
470    ///  * every type used in arguments and return statement
471    ///
472    fn register_new_rust_function(&mut self, function: &ForeignItemFn) -> anyhow::Result<()> {
473        let (associated_structure, result_function) = self.translate_function(function)?;
474        if let Some(custom_type) = associated_structure {
475            self.user_custom_types
476                .entry(custom_type)
477                .or_default()
478                .push(result_function);
479        } else {
480            self.global_functions.push(result_function)
481        }
482        Ok(())
483    }
484
485    /// Translates <T> into T.
486    /// Example:
487    ///  * <Result<u8>> --> Result<u8>
488    ///
489    fn get_inner_generic_type(path_segment: &PathSegment) -> anyhow::Result<&Type> {
490        match &path_segment.arguments {
491            PathArguments::AngleBracketed(args) => args
492                .args
493                .first()
494                .with_context(|| format!("Unsupported generic definition: `{path_segment:?}`"))
495                .and_then(|generic_argument| match generic_argument {
496                    GenericArgument::Type(typ) => Ok(typ),
497                    _ => Err(anyhow!(
498                        "Unsupported generic definition: `{path_segment:?}`"
499                    )),
500                }),
501            _ => Err(anyhow!(
502                "Expected inner generic type specification: `{path_segment:?}`"
503            )),
504        }
505    }
506
507    /// Extracts inner generic types.
508    /// Example:
509    ///  * Result<u8, i32> --> vec[u8, i32]
510    ///
511    fn get_inner_generic_types(path_segment: &PathSegment) -> anyhow::Result<Vec<&Type>> {
512        match &path_segment.arguments {
513            PathArguments::AngleBracketed(args) => args
514                .args
515                .iter()
516                .map(|generic_argument| match generic_argument {
517                    GenericArgument::Type(typ) => Ok(typ),
518                    _ => Err(anyhow!("Unsupported generic type")),
519                })
520                .collect(),
521            _ => panic!("get_inner_generic_types called in bad context"),
522        }
523    }
524
525    /// Checks if the type is `&dyn Trait` and returns a proper WrapperType in
526    /// such a case.
527    ///
528    fn translate_trait_wrapper_type(
529        &self,
530        bounds: &Punctuated<TypeParamBound, Token![+]>,
531        reference_parameters: Option<ReferenceParameters>,
532    ) -> anyhow::Result<WrapperType> {
533        bounds
534            .first()
535            .and_then(|trait_token| {
536                if let TypeParamBound::Trait(TraitBound { path, .. }) = trait_token {
537                    path.segments.first().map(|path_segment| {
538                        let new_wrapper_type = WrapperType {
539                            original_type_name: parse_quote!( #path ),
540                            wrapper_name: path_segment.ident.to_string(),
541                            rust_type: RustWrapperType::Trait,
542                            reference_parameters,
543                            impl_traits: vec![],
544                        };
545                        Ok(new_wrapper_type)
546                    })
547                } else {
548                    Some(Err(anyhow!(
549                        "Lifetimes in TraitObject `{bounds:?}` are not supported"
550                    )))
551                }
552            })
553            .unwrap_or_else(|| {
554                Err(anyhow!(
555                    "Problem occurred during parsing the &dyn type: Empty type `{bounds:?}`"
556                ))
557            })
558    }
559
560    fn parse_rust_exceptions_type(&mut self, typ: &Type) -> anyhow::Result<WrapperType> {
561        match typ {
562            Type::Path(path) => path
563                .path
564                .segments
565                .first()
566                .context("Invalid enum indicating possible exceptions")
567                .and_then(|path_segment| {
568                    let enum_ident = &path_segment.ident;
569                    let enum_item = self
570                        .get_enum(enum_ident.to_string().as_str())
571                        .context("Result's 2nd argument must be an enum's ident.")?;
572                    let exc_variants = enum_item
573                        .variants
574                        .iter()
575                        .map(|v| v.ident.clone())
576                        .collect::<Vec<_>>();
577
578                    let exception_wrapper = WrapperType {
579                        original_type_name: typ.clone(),
580                        wrapper_name: enum_ident.to_string(),
581                        rust_type: if is_primitive_enum(enum_item) {
582                            RustWrapperType::Exceptions(Exceptions::Primitive(exc_variants.clone()))
583                        } else {
584                            RustWrapperType::Exceptions(Exceptions::NonPrimitive(
585                                exc_variants.clone(),
586                            ))
587                        },
588                        reference_parameters: None,
589                        impl_traits: vec![],
590                    };
591
592                    self.exception_names.extend(
593                        exc_variants
594                            .iter()
595                            .map(|variant_ident| exception_class_name(enum_ident, variant_ident)),
596                    );
597                    self.rust_types_wrappers.insert(exception_wrapper.clone());
598
599                    Ok(exception_wrapper)
600                }),
601            _ => Err(anyhow!("Could not parse exception type")),
602        }
603    }
604
605    /// Method takes a type (for instance `Arc<Mutex<dyn SomeCustomType>>`)
606    /// and creates one or more intermediate-form wrappers which are remembered in ExternModuleTranslator.
607    /// Example:
608    /// The following wrappers are created out of Result<Arc<Mutex<dyn SomeCustomType>>>:
609    ///  * ResultSharedMutexSomeCustomType - Result<Arc<Mutex<dyn SomeCustomType>>>
610    ///  * SharedMutexSomeCustomType - Arc<Mutex<dyn SomeCustomType>>
611    ///
612    /// Note: This method is called recursively for Results, Options and Vectors,
613    ///       but for `Arc<T>` and `Rc<T>` the `T` is transparent for the parser.
614    ///
615    fn parse_and_register_rust_type(&mut self, typ: &Type) -> anyhow::Result<WrapperType> {
616        match typ {
617            Type::Ptr(type_ptr) => match type_ptr.elem.deref() {
618                elem @ Type::Path(_) => {
619                    let inner_wrapper = self.parse_and_register_rust_type(elem)?;
620
621                    Ok(WrapperType {
622                        original_type_name: typ.clone(),
623                        wrapper_name: format!("{}Ptr", inner_wrapper.get_name()),
624                        rust_type: RustWrapperType::Ptr(Box::new(inner_wrapper)),
625                        reference_parameters: None,
626                        impl_traits: vec![],
627                    })
628                }
629                _ => Err(anyhow!("Pointer not supported: {type_ptr:?}")),
630            },
631            Type::Path(path) => {
632                path.path
633                    .segments
634                    .first()
635                    .with_context(|| format!("Unsupported type `{typ:?}`"))
636                    .and_then(|path_segment| {
637                        let ident_str = path_segment.ident.to_string();
638                        let new_wrapper_type = if let Some(enum_item) = self.get_enum(&ident_str) {
639                            parse_enum_wrapper(enum_item)
640                        } else if is_primitive(&ident_str) {
641                            parse_primitive_wrapper(typ.clone(), &ident_str)
642                        } else {
643                            match ident_str.as_ref() {
644                                "Result" => self.parse_result_wrapper(typ.clone(), path_segment)?,
645                                "Option" => self.parse_option_wrapper(typ.clone(), path_segment)?,
646                                "Box" => self.parse_box_wrapper(path_segment)?,
647                                "Vec" => self.parse_vec_wrapper(typ.clone(), path_segment)?,
648                                "Arc" => parse_arc_wrapper(typ.clone(), path_segment)?,
649                                "String" => parse_string_wrapper(typ.clone()),
650                                _ => parse_custom_wrapper(typ.clone(), path_segment),
651                            }
652                        };
653
654                        // The following additional `Option<T>` type is used by
655                        // the `Vec<T>::get(..) -> Option<T>;` function:
656                        if let RustWrapperType::Vector(inner_type) = &new_wrapper_type.rust_type {
657                            let inner_type_original = &inner_type.original_type_name;
658                            let option_wrapper = WrapperType {
659                                original_type_name: parse_quote! { Option<#inner_type_original> },
660                                wrapper_name: format!("Optional{}", &inner_type.wrapper_name),
661                                rust_type: RustWrapperType::Option(inner_type.clone().boxed()),
662                                reference_parameters: None,
663                                impl_traits: vec![],
664                            };
665                            self.rust_types_wrappers.insert(option_wrapper);
666                        }
667
668                        self.rust_types_wrappers.insert(new_wrapper_type.clone());
669                        Ok(new_wrapper_type)
670                    })
671            }
672            Type::Reference(TypeReference {
673                elem,
674                mutability,
675                lifetime,
676                ..
677            }) => {
678                let reference_parameters = Some(ReferenceParameters {
679                    is_mut: mutability.is_some(),
680                    is_static: lifetime
681                        .as_ref()
682                        .map_or(false, |lifetime| lifetime.ident == "static"),
683                    boxed: false,
684                });
685                if let Type::TraitObject(TypeTraitObject { bounds, .. }) = elem.as_ref() {
686                    let new_wrapper_type =
687                        self.translate_trait_wrapper_type(bounds, reference_parameters)?;
688                    self.rust_types_wrappers.insert(new_wrapper_type.clone());
689                    Ok(new_wrapper_type)
690                } else {
691                    let wrapper = self.parse_and_register_rust_type(elem.as_ref());
692                    wrapper.map(|wrapper| WrapperType {
693                        reference_parameters,
694                        ..wrapper
695                    })
696                }
697            }
698            _ => Err(anyhow!("Unsupported type `{typ:?}`")),
699        }
700    }
701
702    fn parse_result_wrapper(
703        &mut self,
704        original_type: Type,
705        path_segment: &PathSegment,
706    ) -> anyhow::Result<WrapperType> {
707        ExternModuleTranslator::get_inner_generic_types(path_segment).and_then(|generic_types| {
708            let ok_type = self.parse_and_register_rust_type(
709                generic_types
710                    .get(0)
711                    .context("Result should have 2 generic types")?,
712            )?;
713            let exceptions_type = self.parse_rust_exceptions_type(
714                generic_types
715                    .get(1)
716                    .context("Result should have 2 generic types")?,
717            )?;
718            Ok(WrapperType {
719                original_type_name: original_type,
720                wrapper_name: format!(
721                    "{}ResultWith{}",
722                    &ok_type.wrapper_name, &exceptions_type.wrapper_name
723                ),
724                rust_type: RustWrapperType::Result(ok_type.boxed(), exceptions_type.boxed()),
725                reference_parameters: None,
726                impl_traits: vec![],
727            })
728        })
729    }
730
731    fn parse_option_wrapper(
732        &mut self,
733        original_type: Type,
734        path_segment: &PathSegment,
735    ) -> anyhow::Result<WrapperType> {
736        ExternModuleTranslator::get_inner_generic_type(path_segment)
737            .and_then(|inner_path| self.parse_and_register_rust_type(inner_path))
738            .map(|inner_type_name| WrapperType {
739                original_type_name: original_type,
740                wrapper_name: format!("Optional{}", &inner_type_name.wrapper_name),
741                rust_type: RustWrapperType::Option(inner_type_name.boxed()),
742                reference_parameters: None,
743                impl_traits: vec![],
744            })
745    }
746
747    fn parse_box_wrapper(&self, path_segment: &PathSegment) -> anyhow::Result<WrapperType> {
748        ExternModuleTranslator::get_inner_generic_type(path_segment).and_then(|inner_path| {
749            if let Type::TraitObject(TypeTraitObject { bounds, .. }) = inner_path {
750                self.translate_trait_wrapper_type(bounds, None)
751            } else {
752                Err(anyhow!("invalid Box inner type"))
753            }
754        })
755    }
756
757    fn parse_vec_wrapper(
758        &mut self,
759        original_type: Type,
760        path_segment: &PathSegment,
761    ) -> anyhow::Result<WrapperType> {
762        ExternModuleTranslator::get_inner_generic_type(path_segment)
763            .and_then(|inner_path| self.parse_and_register_rust_type(inner_path))
764            .map(|inner_type_name| WrapperType {
765                original_type_name: original_type,
766                wrapper_name: format!("Vec{}", &inner_type_name.wrapper_name),
767                rust_type: RustWrapperType::Vector(inner_type_name.boxed()),
768                reference_parameters: None,
769                impl_traits: vec![],
770            })
771    }
772
773    pub fn get_enum(&self, ident_str: &str) -> Option<&ItemEnum> {
774        self.shared_enums
775            .iter()
776            .find(|enum_item| enum_item.ident == ident_str)
777    }
778}
779
780fn parse_arc_wrapper(
781    original_type: Type,
782    path_segment: &PathSegment,
783) -> anyhow::Result<WrapperType> {
784    ExternModuleTranslator::get_inner_generic_type(path_segment).map(|inner_path| {
785        let generated_inner_type_name = inner_path
786            .to_token_stream()
787            .to_string()
788            .replace("dyn", "")
789            .replace(['<', '>', ' '], "");
790        WrapperType {
791            original_type_name: original_type,
792            wrapper_name: format!("Shared{}", &generated_inner_type_name),
793            rust_type: if generated_inner_type_name.starts_with("Mutex") {
794                RustWrapperType::ArcMutex
795            } else {
796                RustWrapperType::Arc
797            },
798            reference_parameters: None,
799            impl_traits: vec![],
800        }
801    })
802}
803
804fn parse_string_wrapper(original_type: Type) -> WrapperType {
805    WrapperType {
806        original_type_name: original_type,
807        wrapper_name: "RustString".to_string(),
808        rust_type: RustWrapperType::String,
809        reference_parameters: None,
810        impl_traits: vec![],
811    }
812}
813
814fn parse_primitive_wrapper(original_type: Type, primitive: &str) -> WrapperType {
815    WrapperType {
816        original_type_name: original_type,
817        wrapper_name: primitive.to_owned(),
818        rust_type: RustWrapperType::Primitive,
819        reference_parameters: None,
820        impl_traits: vec![],
821    }
822}
823
824fn parse_custom_wrapper(original_type: Type, path_segment: &PathSegment) -> WrapperType {
825    WrapperType {
826        original_type_name: original_type,
827        wrapper_name: path_segment.ident.to_string(),
828        rust_type: RustWrapperType::Custom,
829        reference_parameters: None,
830        impl_traits: vec![],
831    }
832}
833
834fn parse_enum_wrapper(enum_item: &ItemEnum) -> WrapperType {
835    let ident = &enum_item.ident;
836    WrapperType {
837        original_type_name: parse_quote! {#ident},
838        wrapper_name: ident.to_string(),
839        rust_type: if is_primitive_enum(enum_item) {
840            RustWrapperType::FieldlessEnum
841        } else {
842            RustWrapperType::DataEnum
843        },
844        reference_parameters: None,
845        impl_traits: vec![],
846    }
847}
848
849pub fn exception_wrapper_name(enum_ident: &str) -> String {
850    format!("{}Exceptions", &enum_ident)
851}