rusty_bind_parser/cpp/
function_virtual_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 crate::binding_types::{Function, RustWrapperType, WrapperType};
19use crate::cpp::templates::TargetLanguageTypeName;
20use crate::EXPORTED_SYMBOLS_PREFIX;
21
22pub struct FunctionVirtualTranslator {
23    pub function_name: String,
24    pub generated_args: String,
25    pub generated_function_body: Vec<String>,
26    pub generated_virtual_function_signature: String,
27    pub return_type: Option<WrapperType>,
28    pub arg_names: Vec<String>,
29    class_name: String,
30}
31
32impl FunctionVirtualTranslator {
33    fn create_list_of_arguments_translated_to_cpp(function: &Function) -> Vec<String> {
34        let mut generated_args = function
35            .arguments
36            .iter()
37            .skip(1)
38            .map(|arg| match &arg.typ {
39                WrapperType {
40                    rust_type: RustWrapperType::Primitive | RustWrapperType::FieldlessEnum,
41                    ..
42                } => format!("{} {}", arg.typ.wrapper_name, arg.arg_name),
43                _ => format!("void* {}", arg.arg_name),
44            })
45            .collect::<Vec<String>>();
46        generated_args.insert(0, "void* self".to_owned());
47        generated_args
48    }
49
50    fn create_function_signature(function: &Function) -> String {
51        function
52            .arguments
53            .iter()
54            .skip(1)
55            .map(|arg| format!("{} {}", arg.typ.get_name(), arg.arg_name))
56            .collect::<Vec<String>>()
57            .join(", ")
58    }
59
60    fn create_function_body(function: &Function) -> Vec<String> {
61        function
62            .arguments
63            .iter()
64            .skip(1)
65            .map(|arg| {
66                let inner_type_name = arg.typ.get_name();
67                let arg_name = &arg.arg_name;
68                format!("{inner_type_name}({arg_name})")
69            })
70            .collect()
71    }
72
73    /// Translates the intermediate form of a parsed function into
74    /// the elements ready-to-use in the C++ code generation process.
75    /// It prepares code for a C++ virtual method declaration and
76    /// extern "C" function that calls the virtual method. Due to this,
77    /// Rust code can call virtual C++ methods like trait functions.
78    ///
79    /// Pseudocode:
80    ///
81    /// Rust Trait {
82    ///     method_a();
83    /// }
84    ///
85    /// C++ Class {
86    ///     virtual method_a();
87    /// }
88    ///
89    /// extern "C" __method_a(C++Class* obj) {
90    ///     obj->method_a();
91    /// }
92    ///
93    pub fn from_virtual_function(function: &Function, class_name: &str) -> Self {
94        let generated_args =
95            FunctionVirtualTranslator::create_list_of_arguments_translated_to_cpp(function);
96        let generated_args = generated_args.join(", ");
97        let generated_virtual_function_signature =
98            FunctionVirtualTranslator::create_function_signature(function);
99        let generated_function_body: Vec<String> =
100            FunctionVirtualTranslator::create_function_body(function);
101        let function_name = function.name.to_string();
102        let arg_names = function
103            .arguments
104            .iter()
105            .map(|arg| arg.arg_name.to_string())
106            .collect();
107        FunctionVirtualTranslator {
108            function_name,
109            generated_args,
110            generated_function_body,
111            generated_virtual_function_signature,
112            return_type: function.return_type.clone(),
113            arg_names,
114            class_name: class_name.to_owned(),
115        }
116    }
117
118    /// Generates a virtual function declaration that can be used
119    /// within a class declaration.
120    ///
121    pub fn generate_virtual_declaration(self) -> String {
122        let FunctionVirtualTranslator {
123            function_name,
124            generated_args: _,
125            generated_function_body: _,
126            generated_virtual_function_signature,
127            return_type,
128            ..
129        } = self;
130        let return_type_string = return_type
131            .as_ref()
132            .map(|w| w.get_name_for_abstract_method())
133            .unwrap_or_else(|| "void".to_string());
134        format!("    virtual {return_type_string} {function_name}({generated_virtual_function_signature}) = 0;\n")
135    }
136
137    /// Generates an extern function that calls the virtual
138    /// method on a dynamic C++ object that can be mapped to
139    /// some Rust trait object.
140    ///
141    pub fn generate_virtual_definition(self) -> String {
142        let FunctionVirtualTranslator {
143            function_name,
144            generated_args,
145            generated_function_body,
146            generated_virtual_function_signature: _,
147            return_type,
148            arg_names: _,
149            class_name,
150        } = self;
151        let class_function_name = format!("{class_name}$");
152        let generated_function_body = generated_function_body.join(", ");
153        match return_type {
154                Some(WrapperType {
155                    rust_type: RustWrapperType::Primitive | RustWrapperType::FieldlessEnum,
156                    wrapper_name,
157                    ..
158                }) =>
159                format!(
160                    "extern \"C\" {wrapper_name} {EXPORTED_SYMBOLS_PREFIX}${class_function_name}{function_name}({generated_args}) {{
161        return (({class_name}*)self)->{function_name}({generated_function_body});\n}}\n"),
162                None => format!(
163                    "extern \"C\" void {EXPORTED_SYMBOLS_PREFIX}${class_function_name}{function_name}({generated_args}) {{
164        (({class_name}*)self)->{function_name}({generated_function_body});\n}}\n"),
165                _ =>
166                    format!(
167                    "extern \"C\" void* {EXPORTED_SYMBOLS_PREFIX}${class_function_name}{function_name}({generated_args}) {{
168        return ((({class_name}*)self)->{function_name}({generated_function_body}));\n}}\n"),
169            }
170    }
171}