1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
use crate::cpp_data::CppClassField;
use crate::cpp_data::CppPath;
use crate::cpp_function::{CppFunction, ReturnValueAllocationPlace};
use crate::cpp_type::{CppFunctionPointerType, CppType};
use ritual_common::errors::Result;
use serde_derive::{Deserialize, Serialize};
/// Variation of a field accessor method
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub enum CppFieldAccessorType {
/// Returns copy of the field
CopyGetter,
/// Returns const reference to the field
ConstRefGetter,
/// Returns mutable reference to the field
MutRefGetter,
/// Copies value from its argument to the field
Setter,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum CppCast {
Static {
/// If true, this is an unsafe (from base to derived) `static_cast` wrapper.
is_unsafe: bool,
/// If Some, this is a wrapper of `static_cast` between a class and its
/// direct base. Contains index of the base (e.g. 0 for the first base; always
/// 0 if the class only has one base).
direct_base_index: Option<usize>,
},
Dynamic,
#[allow(unused)]
QObject,
}
impl CppCast {
pub fn cpp_method_name(&self) -> &'static str {
match *self {
CppCast::Static { .. } => "static_cast",
CppCast::Dynamic => "dynamic_cast",
CppCast::QObject => "qobject_cast",
}
}
pub fn is_unsafe_static_cast(&self) -> bool {
match *self {
CppCast::Static { ref is_unsafe, .. } => *is_unsafe,
_ => false,
}
}
pub fn is_first_direct_static_cast(&self) -> bool {
match *self {
CppCast::Static {
ref direct_base_index,
..
} => direct_base_index == &Some(0),
_ => false,
}
}
}
/// Information about real nature of a C++ FFI method.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum CppFfiFunctionKind {
/// This is a real C++ function.
Function {
cpp_function: CppFunction,
/// If `Some`, the method is derived from another method by omitting arguments,
/// and this field contains the number of omitted arguments.
omitted_arguments: Option<usize>,
/// If Some, this is an instance of `static_cast`, `dynamic_cast` or
/// `qobject_cast` function call.
cast: Option<CppCast>,
},
/// This is a field accessor, i.e. a non-existing getter or setter
/// method for a public field.
FieldAccessor {
/// Type of the accessor
accessor_type: CppFieldAccessorType,
// /// Name of the C++ field
field: CppClassField,
},
}
impl CppFfiFunctionKind {
pub fn cpp_function(&self) -> Option<&CppFunction> {
if let CppFfiFunctionKind::Function {
ref cpp_function, ..
} = *self
{
Some(cpp_function)
} else {
None
}
}
pub fn cpp_field(&self) -> Option<&CppClassField> {
if let CppFfiFunctionKind::FieldAccessor { ref field, .. } = *self {
Some(field)
} else {
None
}
}
}
/// Relation between original C++ method's argument value
/// and corresponding FFI function's argument value
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum CppTypeConversionToFfi {
/// Argument types are identical
NoChange,
/// C++ argument is a class value (like QPoint)
/// and FFI argument is a pointer (like QPoint*)
ValueToPointer,
/// C++ argument is a reference (like QPoint&)
/// and FFI argument is a pointer (like QPoint*)
ReferenceToPointer,
/// C++ argument is QFlags<T>
/// and FFI argument is uint
QFlagsToUInt,
}
/// Information that indicates how an FFI function argument
/// should be interpreted
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub enum CppFfiArgumentMeaning {
/// This argument contains value for "this" pointer
/// used to call C++ class member functions
This,
/// Value of this argument should be passed as an argument to
/// the original C++ method. Associated value is index of the
/// C++ method's argument (counting from 0).
Argument(i8),
/// This argument receives pointer to the buffer where
/// the return value should be transferred to using placement new.
ReturnValue,
}
impl CppFfiArgumentMeaning {
/// Checks if this argument corresponds to an original
/// C++ method's argument
pub fn is_argument(&self) -> bool {
match *self {
CppFfiArgumentMeaning::Argument(..) => true,
_ => false,
}
}
}
/// Representation of an argument of a FFI function
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct CppFfiFunctionArgument {
/// Identifier
pub name: String,
/// Type
pub argument_type: CppFfiType,
/// C++ equivalent
pub meaning: CppFfiArgumentMeaning,
}
impl CppFfiFunctionArgument {
/// Generates C++ code for the part of FFI function signature
/// corresponding to this argument
pub fn to_cpp_code(&self) -> Result<String> {
if let CppType::FunctionPointer(..) = self.argument_type.ffi_type {
Ok(self.argument_type.ffi_type.to_cpp_code(Some(&self.name))?)
} else {
Ok(format!(
"{} {}",
self.argument_type.ffi_type.to_cpp_code(None)?,
self.name
))
}
}
}
/// Information about arguments and return type of a FFI function
/// with no final function name
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct CppFfiFunction {
/// List of arguments
pub arguments: Vec<CppFfiFunctionArgument>,
/// Return type
pub return_type: CppFfiType,
/// Allocation place method used for converting
/// the return type of the method
/// or used to determine implementation of the destructor
pub allocation_place: ReturnValueAllocationPlace,
/// Final name of FFI method
pub path: CppPath,
pub kind: CppFfiFunctionKind,
}
impl CppFfiFunction {
/// Returns true if this signature has const this_ptr argument,
/// indicating that original C++ method has const attribute.
/// Returns false if there is no this argument or it's not const.
pub fn has_const_this(&self) -> bool {
self.arguments.iter().any(|arg| {
arg.meaning == CppFfiArgumentMeaning::This
&& match arg.argument_type.ffi_type {
CppType::PointerLike { is_const, .. } => is_const,
_ => false,
}
})
}
pub fn short_text(&self) -> String {
match self.kind {
CppFfiFunctionKind::Function {
ref cpp_function,
ref omitted_arguments,
..
} => {
let omitted_args_text = if let Some(args) = omitted_arguments {
format!(" (omitted arguments: {}", args)
} else {
String::new()
};
format!(
"FFI function call{}: {}",
omitted_args_text,
cpp_function.short_text()
)
}
CppFfiFunctionKind::FieldAccessor {
ref field,
ref accessor_type,
} => format!("FFI field {:?}: {}", accessor_type, field.short_text()),
}
}
}
/// FFI function type with attached information about
/// corresponding original C++ type and their relation
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct CppFfiType {
/// Original C++ type
pub original_type: CppType,
/// FFI function type
pub ffi_type: CppType,
/// Relation
pub conversion: CppTypeConversionToFfi,
}
impl CppFfiType {
/// Generates an object representing the void type
pub fn void() -> Self {
CppFfiType {
original_type: CppType::Void,
ffi_type: CppType::Void,
conversion: CppTypeConversionToFfi::NoChange,
}
}
}
/// Information about a Qt slot wrapper with
/// certain slot arguments
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QtSlotWrapper {
/// Generated name of the wrapper class
pub class_path: CppPath,
/// Arguments of the slot.
pub arguments: Vec<CppFfiType>,
/// The function pointer type accepted by this wrapper
pub function_type: CppFunctionPointerType,
/// String identifier passed to `QObject::connect` function to
/// specify the object's slot.
pub receiver_id: String,
}