qt 0.1.9 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/qt_ruby_bridge/extconf.rb +2 -0
- data/ext/qt_ruby_bridge/qt_ruby_runtime.hpp +14 -0
- data/ext/qt_ruby_bridge/runtime_events.cpp +8 -3
- data/ext/qt_ruby_bridge/runtime_value_types.cpp +22 -0
- data/ext/qt_ruby_bridge/runtime_virtual_methods.cpp +78 -0
- data/lib/qt/application_lifecycle.rb +1 -1
- data/lib/qt/event_runtime_dispatch.rb +2 -0
- data/lib/qt/generated_overload_runtime.rb +7 -0
- data/lib/qt/object_wrapper.rb +1 -0
- data/lib/qt/value_wrapper.rb +26 -0
- data/lib/qt/version.rb +1 -1
- data/lib/qt/virtual_method_runtime.rb +165 -0
- data/lib/qt.rb +4 -0
- data/scripts/generate_bridge/ast_introspection.rb +16 -3
- data/scripts/generate_bridge/auto_methods.rb +205 -24
- data/scripts/generate_bridge/cpp_method_return_emitter.rb +75 -24
- data/scripts/generate_bridge/ffi_api.rb +17 -1
- data/scripts/generate_bridge/free_function_specs.rb +0 -153
- data/scripts/generate_bridge/spec_discovery.rb +53 -13
- data/scripts/generate_bridge.rb +410 -31
- metadata +6 -1
|
@@ -4,12 +4,52 @@ def unsupported_cpp_type?(type_name)
|
|
|
4
4
|
type_name.include?('<') || type_name.include?('>') || type_name.include?('[') || type_name.include?('(')
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
def
|
|
7
|
+
def ast_nested_types_by_class(ast)
|
|
8
|
+
@ast_nested_types_cache ||= {}.compare_by_identity
|
|
9
|
+
@ast_nested_types_cache[ast] ||= begin
|
|
10
|
+
nested = Hash.new { |hash, key| hash[key] = Set.new }
|
|
11
|
+
walk = lambda do |node, record_stack|
|
|
12
|
+
next unless node.is_a?(Hash)
|
|
13
|
+
|
|
14
|
+
parent_record = record_stack.last
|
|
15
|
+
nested_type_kind = %w[CXXRecordDecl EnumDecl TypedefDecl TypeAliasDecl].include?(node['kind'])
|
|
16
|
+
if nested_type_kind && parent_record && node['name'] && node['name'] != parent_record['name'] &&
|
|
17
|
+
(node['parentDeclContextId'].nil? || node['parentDeclContextId'] == parent_record['id'])
|
|
18
|
+
nested[parent_record['name']] << node['name']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
child_stack = if node['kind'] == 'CXXRecordDecl' && node['name']
|
|
22
|
+
record_stack + [node]
|
|
23
|
+
else
|
|
24
|
+
record_stack
|
|
25
|
+
end
|
|
26
|
+
Array(node['inner']).each { |child| walk.call(child, child_stack) }
|
|
27
|
+
end
|
|
28
|
+
walk.call(ast, [])
|
|
29
|
+
nested
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def ast_nested_type_owner(ast, qt_class, nested_name, visited = {})
|
|
34
|
+
return nil if qt_class.nil? || visited[qt_class]
|
|
35
|
+
|
|
36
|
+
visited[qt_class] = true
|
|
37
|
+
return qt_class if ast_nested_types_by_class(ast)[qt_class].include?(nested_name)
|
|
38
|
+
|
|
39
|
+
collect_class_bases(ast, qt_class).each do |base_class|
|
|
40
|
+
owner = ast_nested_type_owner(ast, base_class, nested_name, visited)
|
|
41
|
+
return owner if owner
|
|
42
|
+
end
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def map_cpp_pointer_arg_type(type_name, qt_class, ast:)
|
|
8
47
|
return nil unless type_name.end_with?('*')
|
|
9
48
|
|
|
10
49
|
base = type_name.sub(/\s*\*\z/, '').strip
|
|
11
|
-
if qt_class && !base.include?('::') && base.match?(/\A[A-Z]\w*\z/)
|
|
12
|
-
|
|
50
|
+
if qt_class && !base.include?('::') && base.match?(/\A[A-Z]\w*\z/)
|
|
51
|
+
owner = ast_nested_type_owner(ast, qt_class, base)
|
|
52
|
+
base = "#{owner}::#{base}" if owner
|
|
13
53
|
end
|
|
14
54
|
{ ffi: :pointer, cast: "#{base}*" }
|
|
15
55
|
end
|
|
@@ -21,32 +61,52 @@ def map_builtin_intlike_arg_type(type_name)
|
|
|
21
61
|
nil
|
|
22
62
|
end
|
|
23
63
|
|
|
24
|
-
def
|
|
25
|
-
return nil
|
|
64
|
+
def inherited_intlike_type_name(type_name, qt_class, ast, int_cast_types, visited = {})
|
|
65
|
+
return nil if qt_class.nil? || visited[qt_class]
|
|
26
66
|
|
|
67
|
+
visited[qt_class] = true
|
|
27
68
|
qualified = "#{qt_class}::#{type_name}"
|
|
28
|
-
return
|
|
69
|
+
return qualified if int_cast_types&.include?(qualified)
|
|
70
|
+
|
|
71
|
+
collect_class_bases(ast, qt_class).each do |base_class|
|
|
72
|
+
inherited = inherited_intlike_type_name(type_name, base_class, ast, int_cast_types, visited)
|
|
73
|
+
return inherited if inherited
|
|
74
|
+
end
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def map_qualified_intlike_arg_type(type_name, qt_class, int_cast_types, ast:)
|
|
79
|
+
return nil unless qt_class && type_name.match?(/\A[A-Z]\w*\z/)
|
|
80
|
+
|
|
81
|
+
qualified = inherited_intlike_type_name(type_name, qt_class, ast, int_cast_types)
|
|
82
|
+
return { ffi: :int, cast: qualified } if qualified
|
|
29
83
|
|
|
30
84
|
nil
|
|
31
85
|
end
|
|
32
86
|
|
|
33
|
-
def map_cpp_intlike_arg_type(type_name, qt_class, int_cast_types)
|
|
87
|
+
def map_cpp_intlike_arg_type(type_name, qt_class, int_cast_types, ast:)
|
|
34
88
|
builtin = map_builtin_intlike_arg_type(type_name)
|
|
35
89
|
return builtin if builtin
|
|
36
90
|
return { ffi: :int, cast: type_name } if type_name.include?('::') && int_cast_types&.include?(type_name)
|
|
37
91
|
|
|
38
|
-
map_qualified_intlike_arg_type(type_name, qt_class, int_cast_types)
|
|
92
|
+
map_qualified_intlike_arg_type(type_name, qt_class, int_cast_types, ast: ast)
|
|
39
93
|
end
|
|
40
94
|
|
|
41
|
-
def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil)
|
|
95
|
+
def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil, ast: nil)
|
|
42
96
|
raw = type_name.to_s.strip
|
|
43
|
-
|
|
97
|
+
if raw.end_with?('&') && !raw.start_with?('const ')
|
|
98
|
+
mutable_reference_type = normalized_cpp_type_name(raw)
|
|
99
|
+
return nil if SCALAR_BRIDGED_QT_TYPES.include?(mutable_reference_type) || %w[QCursor QIcon].include?(mutable_reference_type)
|
|
100
|
+
return nil unless ast_qt_value_class?(ast, mutable_reference_type)
|
|
101
|
+
|
|
102
|
+
return { ffi: :pointer, cast: :qt_value_ref, value_class: mutable_reference_type }
|
|
103
|
+
end
|
|
44
104
|
|
|
45
105
|
compact_raw = raw.gsub(/\s+/, ' ')
|
|
46
106
|
|
|
47
107
|
type = raw
|
|
48
108
|
type = type.sub(/\Aconst\s+/, '').sub(/\s*&\z/, '').strip
|
|
49
|
-
return
|
|
109
|
+
return { ffi: :string, cast: :qint_list_from_variant } if type == 'QList<int>'
|
|
50
110
|
return { ffi: :string, cast: :qstring } if type == 'QString'
|
|
51
111
|
return { ffi: :string, cast: :qdatetime_from_utf8 } if type == 'QDateTime'
|
|
52
112
|
return { ffi: :string, cast: :qdate_from_utf8 } if type == 'QDate'
|
|
@@ -58,7 +118,13 @@ def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil)
|
|
|
58
118
|
return { ffi: :string, cast: :qvariant_from_utf8 } if type == 'QVariant'
|
|
59
119
|
return { ffi: :string } if compact_raw.match?(/\Aconst\s+char\s*\*\z/)
|
|
60
120
|
|
|
61
|
-
|
|
121
|
+
if ast_qt_value_class?(ast, type)
|
|
122
|
+
return { ffi: :pointer, cast: :qt_value_ref, value_class: type }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
return nil if unsupported_cpp_type?(type)
|
|
126
|
+
|
|
127
|
+
map_cpp_pointer_arg_type(type, qt_class, ast: ast) || map_cpp_intlike_arg_type(type, qt_class, int_cast_types, ast: ast)
|
|
62
128
|
end
|
|
63
129
|
|
|
64
130
|
def normalized_cpp_type_name(type_name)
|
|
@@ -68,13 +134,34 @@ def normalized_cpp_type_name(type_name)
|
|
|
68
134
|
type
|
|
69
135
|
end
|
|
70
136
|
|
|
71
|
-
def map_cpp_return_type(type_name, ast: nil)
|
|
137
|
+
def map_cpp_return_type(type_name, ast: nil, qt_class: nil)
|
|
72
138
|
raw = type_name.to_s.strip
|
|
139
|
+
type = raw.sub(/\Aconst\s+/, '').sub(/\s*&\z/, '').strip
|
|
140
|
+
return { ffi_return: :string, return_cast: :qint_list_to_variant } if type == 'QList<int>'
|
|
73
141
|
return nil if unsupported_cpp_type?(raw)
|
|
74
142
|
return nil if raw.start_with?('const ') && raw.end_with?('*')
|
|
75
143
|
|
|
76
|
-
|
|
77
|
-
|
|
144
|
+
scalar = map_scalar_cpp_return_type(type)
|
|
145
|
+
return scalar if scalar
|
|
146
|
+
|
|
147
|
+
int_cast_types = ast ? ast_int_cast_type_set(ast) : nil
|
|
148
|
+
intlike = map_cpp_intlike_arg_type(type, qt_class, int_cast_types, ast: ast)
|
|
149
|
+
return { ffi_return: :int, return_cast: :int_cast } if intlike
|
|
150
|
+
|
|
151
|
+
map_pointer_cpp_return_type(type, ast: ast) || map_qt_value_return_type(type, ast: ast)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def ast_qt_value_class?(ast, type)
|
|
155
|
+
return false unless ast && type.match?(/\AQ[A-Z]\w*\z/)
|
|
156
|
+
return false unless ast_class_index(ast)[:methods_by_class].key?(type)
|
|
157
|
+
|
|
158
|
+
!class_inherits?(ast, type, 'QObject')
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def map_qt_value_return_type(type, ast:)
|
|
162
|
+
return nil unless ast_qt_value_class?(ast, type)
|
|
163
|
+
|
|
164
|
+
{ ffi_return: :pointer, return_cast: :qt_value_copy, value_class: type }
|
|
78
165
|
end
|
|
79
166
|
|
|
80
167
|
def map_scalar_cpp_return_type(type)
|
|
@@ -82,6 +169,7 @@ def map_scalar_cpp_return_type(type)
|
|
|
82
169
|
return { ffi_return: :int } if type == 'int'
|
|
83
170
|
return { ffi_return: :bool } if type == 'bool'
|
|
84
171
|
return { ffi_return: :string, return_cast: :qstring_to_utf8 } if type == 'QString'
|
|
172
|
+
return { ffi_return: :string, return_cast: :qstring_list_to_json } if type == 'QStringList'
|
|
85
173
|
return { ffi_return: :string, return_cast: :qobject_list_to_wrapped_array, object_list_class: 'QObject' } if type == 'QObjectList'
|
|
86
174
|
return { ffi_return: :string, return_cast: :qdatetime_to_utf8 } if type == 'QDateTime'
|
|
87
175
|
return { ffi_return: :string, return_cast: :qdate_to_utf8 } if type == 'QDate'
|
|
@@ -135,7 +223,7 @@ def parse_method_signature(method_decl)
|
|
|
135
223
|
}
|
|
136
224
|
end
|
|
137
225
|
|
|
138
|
-
def build_auto_method_args(parsed, entry, qt_class, int_cast_types)
|
|
226
|
+
def build_auto_method_args(parsed, entry, qt_class, int_cast_types, ast)
|
|
139
227
|
arg_cast_overrides = Array(entry[:arg_casts])
|
|
140
228
|
params = parsed[:params]
|
|
141
229
|
required_arg_count = 0
|
|
@@ -143,7 +231,7 @@ def build_auto_method_args(parsed, entry, qt_class, int_cast_types)
|
|
|
143
231
|
|
|
144
232
|
params.each_with_index do |param, idx|
|
|
145
233
|
cast_override = arg_cast_overrides[idx]
|
|
146
|
-
arg_info = map_cpp_arg_type(param[:type], qt_class: qt_class, int_cast_types: int_cast_types)
|
|
234
|
+
arg_info = map_cpp_arg_type(param[:type], qt_class: qt_class, int_cast_types: int_cast_types, ast: ast)
|
|
147
235
|
arg_info ||= { ffi: :int } if cast_override
|
|
148
236
|
unless arg_info
|
|
149
237
|
return nil unless skip_unsupported_optional_tail?(params, idx, param)
|
|
@@ -151,7 +239,13 @@ def build_auto_method_args(parsed, entry, qt_class, int_cast_types)
|
|
|
151
239
|
break
|
|
152
240
|
end
|
|
153
241
|
|
|
154
|
-
args << {
|
|
242
|
+
args << {
|
|
243
|
+
name: param[:name],
|
|
244
|
+
ffi: arg_info[:ffi],
|
|
245
|
+
cast: cast_override || arg_info[:cast],
|
|
246
|
+
value_class: arg_info[:value_class],
|
|
247
|
+
cpp_type: param[:type]
|
|
248
|
+
}.compact
|
|
155
249
|
required_arg_count += 1 unless param[:has_default]
|
|
156
250
|
end
|
|
157
251
|
|
|
@@ -172,8 +266,10 @@ def build_auto_method_hash(entry, ret_info, args, required_arg_count)
|
|
|
172
266
|
args: args,
|
|
173
267
|
required_arg_count: required_arg_count
|
|
174
268
|
}
|
|
269
|
+
method[:static] = entry[:static] if entry.key?(:static)
|
|
175
270
|
method[:return_cast] = ret_info[:return_cast] if ret_info[:return_cast]
|
|
176
271
|
method[:pointer_class] = ret_info[:pointer_class] if ret_info[:pointer_class]
|
|
272
|
+
method[:value_class] = ret_info[:value_class] if ret_info[:value_class]
|
|
177
273
|
method
|
|
178
274
|
end
|
|
179
275
|
|
|
@@ -181,10 +277,10 @@ def build_auto_method_from_decl(method_decl, entry, qt_class:, int_cast_types:,
|
|
|
181
277
|
parsed = parse_method_signature(method_decl)
|
|
182
278
|
return nil unless parsed
|
|
183
279
|
|
|
184
|
-
ret_info = map_cpp_return_type(parsed[:return_type], ast: ast)
|
|
280
|
+
ret_info = map_cpp_return_type(parsed[:return_type], ast: ast, qt_class: qt_class)
|
|
185
281
|
return nil unless ret_info
|
|
186
282
|
|
|
187
|
-
args, required_arg_count = build_auto_method_args(parsed, entry, qt_class, int_cast_types)
|
|
283
|
+
args, required_arg_count = build_auto_method_args(parsed, entry, qt_class, int_cast_types, ast)
|
|
188
284
|
return nil unless args
|
|
189
285
|
|
|
190
286
|
build_auto_method_hash(entry, ret_info, args, required_arg_count)
|
|
@@ -237,8 +333,15 @@ def build_auto_method_candidate(ast, decl, entry, qt_class, int_cast_types)
|
|
|
237
333
|
parsed = parse_method_signature(decl)
|
|
238
334
|
return nil unless parsed
|
|
239
335
|
|
|
240
|
-
|
|
336
|
+
method_entry = entry.merge(static: decl['storageClass'] == 'static')
|
|
337
|
+
method = build_auto_method_from_decl(decl, method_entry, qt_class: qt_class, int_cast_types: int_cast_types, ast: ast)
|
|
241
338
|
return nil unless method
|
|
339
|
+
method[:owner_class] = qt_class if method[:static]
|
|
340
|
+
method[:cpp_return_type] = parsed[:return_type]
|
|
341
|
+
method[:virtual] = virtual_method_declaration?(ast, decl)
|
|
342
|
+
method[:cpp_const] = decl.dig('type', 'qualType').to_s.match?(/\)\s*const\b/)
|
|
343
|
+
method[:cpp_params] = parsed[:params].map { |param| param[:type] }
|
|
344
|
+
method[:final] = final_method_declaration?(ast, decl)
|
|
242
345
|
|
|
243
346
|
{
|
|
244
347
|
method: method,
|
|
@@ -246,6 +349,77 @@ def build_auto_method_candidate(ast, decl, entry, qt_class, int_cast_types)
|
|
|
246
349
|
}
|
|
247
350
|
end
|
|
248
351
|
|
|
352
|
+
def method_declaration_signature_key(decl)
|
|
353
|
+
parsed = parse_method_signature(decl)
|
|
354
|
+
return nil unless parsed
|
|
355
|
+
|
|
356
|
+
params = parsed[:params].map do |param|
|
|
357
|
+
param[:type].to_s.gsub(/\s+/, ' ').gsub(/\s*([*&])\s*/, '\\1').strip
|
|
358
|
+
end
|
|
359
|
+
const_method = decl.dig('type', 'qualType').to_s.match?(/\)\s*const\b/)
|
|
360
|
+
[params, const_method]
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def method_declaration_has_attribute?(decl, attribute)
|
|
364
|
+
if attribute == 'OverrideAttr'
|
|
365
|
+
return decl['virtual'] == true || Array(decl['inner']).any? { |node| node['kind'] == attribute }
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
Array(decl['inner']).any? { |node| node['kind'] == attribute }
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def inherited_method_attribute?(ast, owner_class, method_name, signature_key, attribute, visited = {})
|
|
372
|
+
return false if owner_class.nil? || visited[owner_class]
|
|
373
|
+
|
|
374
|
+
visited[owner_class] = true
|
|
375
|
+
collect_class_bases(ast, owner_class).any? do |base_class|
|
|
376
|
+
matching_declaration = collect_method_decls(ast, base_class, method_name).find do |candidate|
|
|
377
|
+
method_declaration_signature_key(candidate) == signature_key
|
|
378
|
+
end
|
|
379
|
+
next true if matching_declaration && method_declaration_has_attribute?(matching_declaration, attribute)
|
|
380
|
+
next false unless matching_declaration
|
|
381
|
+
|
|
382
|
+
inherited_method_attribute?(
|
|
383
|
+
ast,
|
|
384
|
+
base_class,
|
|
385
|
+
method_name,
|
|
386
|
+
signature_key,
|
|
387
|
+
attribute,
|
|
388
|
+
visited
|
|
389
|
+
)
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def method_inherits_attribute?(ast, decl, attribute)
|
|
394
|
+
return true if method_declaration_has_attribute?(decl, attribute)
|
|
395
|
+
|
|
396
|
+
owner_class = decl['__owner_class']
|
|
397
|
+
signature_key = method_declaration_signature_key(decl)
|
|
398
|
+
return false unless owner_class && signature_key
|
|
399
|
+
|
|
400
|
+
cache = (@inherited_method_attribute_cache ||= {}.compare_by_identity)
|
|
401
|
+
per_ast = (cache[ast] ||= {})
|
|
402
|
+
cache_key = [owner_class, decl['name'], signature_key, attribute]
|
|
403
|
+
return per_ast[cache_key] if per_ast.key?(cache_key)
|
|
404
|
+
|
|
405
|
+
per_ast[cache_key] = inherited_method_attribute?(
|
|
406
|
+
ast,
|
|
407
|
+
owner_class,
|
|
408
|
+
decl['name'],
|
|
409
|
+
signature_key,
|
|
410
|
+
attribute
|
|
411
|
+
)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def virtual_method_declaration?(ast, decl)
|
|
415
|
+
method_inherits_attribute?(ast, decl, 'OverrideAttr') ||
|
|
416
|
+
decl['virtual'] == true
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def final_method_declaration?(ast, decl)
|
|
420
|
+
method_inherits_attribute?(ast, decl, 'FinalAttr')
|
|
421
|
+
end
|
|
422
|
+
|
|
249
423
|
def auto_method_decl_candidate?(decl)
|
|
250
424
|
return false unless decl['__effective_access'] == 'public'
|
|
251
425
|
return false if deprecated_method_decl?(decl)
|
|
@@ -352,7 +526,13 @@ def resolve_auto_method(ast, qt_class, auto_entry)
|
|
|
352
526
|
built = resolve_auto_method_built_candidates(ast, qt_class, entry)
|
|
353
527
|
return per_ast_cache[cache_key] = nil unless built
|
|
354
528
|
|
|
355
|
-
|
|
529
|
+
methods = built.uniq { |candidate| candidate[:param_types] }
|
|
530
|
+
.sort_by do |candidate|
|
|
531
|
+
method = candidate[:method]
|
|
532
|
+
value_arg_count = method[:args].count { |arg| arg[:cast] == :qt_value_ref }
|
|
533
|
+
[method[:required_arg_count], -value_arg_count, method[:args].length, candidate[:param_types]]
|
|
534
|
+
end.map { |candidate| candidate[:method] }
|
|
535
|
+
per_ast_cache[cache_key] = methods
|
|
356
536
|
end
|
|
357
537
|
|
|
358
538
|
def auto_entries_for_spec(spec, ast)
|
|
@@ -371,9 +551,10 @@ def resolve_auto_methods_for_spec(ast, spec, auto_entries, manual_methods, auto_
|
|
|
371
551
|
resolver = build_auto_method_resolver(ast, spec, manual_methods, auto_mode)
|
|
372
552
|
spec_resolved = 0
|
|
373
553
|
spec_skipped = 0
|
|
374
|
-
auto_methods =
|
|
554
|
+
auto_methods = []
|
|
555
|
+
auto_entries.each do |entry|
|
|
375
556
|
method, spec_skipped, spec_resolved = resolve_with_resolver(resolver, entry, spec_skipped, spec_resolved)
|
|
376
|
-
method
|
|
557
|
+
auto_methods.concat(Array(method))
|
|
377
558
|
end
|
|
378
559
|
|
|
379
560
|
[auto_methods, spec_resolved, spec_skipped]
|
|
@@ -10,6 +10,9 @@ class CppMethodReturnEmitter
|
|
|
10
10
|
|
|
11
11
|
def emit
|
|
12
12
|
return emit_void if method[:ffi_return] == :void
|
|
13
|
+
return emit_qt_value_copy if method[:return_cast] == :qt_value_copy
|
|
14
|
+
return emit_qint_list if method[:return_cast] == :qint_list_to_variant
|
|
15
|
+
return emit_qstring_list if method[:return_cast] == :qstring_list_to_json
|
|
13
16
|
return emit_qstring if qstring_return?
|
|
14
17
|
return emit_qobject_list if qobject_list_return?
|
|
15
18
|
return emit_qdatetime if qdatetime_return?
|
|
@@ -17,6 +20,7 @@ class CppMethodReturnEmitter
|
|
|
17
20
|
return emit_qtime if qtime_return?
|
|
18
21
|
return emit_qvariant if qvariant_return?
|
|
19
22
|
return emit_pointer if method[:ffi_return] == :pointer
|
|
23
|
+
return emit_int_cast if method[:return_cast] == :int_cast
|
|
20
24
|
|
|
21
25
|
emit_value
|
|
22
26
|
end
|
|
@@ -54,52 +58,99 @@ class CppMethodReturnEmitter
|
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
def emit_qstring
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
lines <<
|
|
60
|
-
lines <<
|
|
61
|
+
result = unique_local_name('result')
|
|
62
|
+
utf8 = unique_local_name('utf8')
|
|
63
|
+
lines << " const QString #{result} = #{invocation};"
|
|
64
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
65
|
+
lines << " #{utf8} = #{result}.toUtf8();"
|
|
66
|
+
lines << " return #{utf8}.constData();"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def emit_qstring_list
|
|
70
|
+
result = unique_local_name('result')
|
|
71
|
+
utf8 = unique_local_name('utf8')
|
|
72
|
+
lines << " const QStringList #{result} = #{invocation};"
|
|
73
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
74
|
+
lines << " #{utf8} = qstring_list_to_bridge_string(#{result}).toUtf8();"
|
|
75
|
+
lines << " return #{utf8}.constData();"
|
|
61
76
|
end
|
|
62
77
|
|
|
63
78
|
def emit_qvariant
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
lines <<
|
|
67
|
-
lines <<
|
|
79
|
+
result = unique_local_name('result')
|
|
80
|
+
utf8 = unique_local_name('utf8')
|
|
81
|
+
lines << " const QVariant #{result} = #{invocation};"
|
|
82
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
83
|
+
lines << " #{utf8} = qvariant_to_bridge_string(#{result}).toUtf8();"
|
|
84
|
+
lines << " return #{utf8}.constData();"
|
|
68
85
|
end
|
|
69
86
|
|
|
70
87
|
def emit_qobject_list
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
lines <<
|
|
74
|
-
lines <<
|
|
88
|
+
result = unique_local_name('result')
|
|
89
|
+
utf8 = unique_local_name('utf8')
|
|
90
|
+
lines << " const QObjectList #{result} = #{invocation};"
|
|
91
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
92
|
+
lines << " #{utf8} = qobject_list_to_bridge_string(#{result}).toUtf8();"
|
|
93
|
+
lines << " return #{utf8}.constData();"
|
|
75
94
|
end
|
|
76
95
|
|
|
77
96
|
def emit_qdatetime
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
lines <<
|
|
81
|
-
lines <<
|
|
97
|
+
result = unique_local_name('result')
|
|
98
|
+
utf8 = unique_local_name('utf8')
|
|
99
|
+
lines << " const QDateTime #{result} = #{invocation};"
|
|
100
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
101
|
+
lines << " #{utf8} = qdatetime_to_bridge_string(#{result}).toUtf8();"
|
|
102
|
+
lines << " return #{utf8}.constData();"
|
|
82
103
|
end
|
|
83
104
|
|
|
84
105
|
def emit_qdate
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
lines <<
|
|
88
|
-
lines <<
|
|
106
|
+
result = unique_local_name('result')
|
|
107
|
+
utf8 = unique_local_name('utf8')
|
|
108
|
+
lines << " const QDate #{result} = #{invocation};"
|
|
109
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
110
|
+
lines << " #{utf8} = qdate_to_bridge_string(#{result}).toUtf8();"
|
|
111
|
+
lines << " return #{utf8}.constData();"
|
|
89
112
|
end
|
|
90
113
|
|
|
91
114
|
def emit_qtime
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
lines <<
|
|
95
|
-
lines <<
|
|
115
|
+
result = unique_local_name('result')
|
|
116
|
+
utf8 = unique_local_name('utf8')
|
|
117
|
+
lines << " const QTime #{result} = #{invocation};"
|
|
118
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
119
|
+
lines << " #{utf8} = qtime_to_bridge_string(#{result}).toUtf8();"
|
|
120
|
+
lines << " return #{utf8}.constData();"
|
|
96
121
|
end
|
|
97
122
|
|
|
98
123
|
def emit_pointer
|
|
99
124
|
lines << " return const_cast<void*>(static_cast<const void*>(#{invocation}));"
|
|
100
125
|
end
|
|
101
126
|
|
|
127
|
+
def emit_qt_value_copy
|
|
128
|
+
lines << " return new #{method[:value_class]}(#{invocation});"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def emit_qint_list
|
|
132
|
+
result = unique_local_name('result')
|
|
133
|
+
variant = unique_local_name('variant')
|
|
134
|
+
utf8 = unique_local_name('utf8')
|
|
135
|
+
lines << " const QList<int> #{result} = #{invocation};"
|
|
136
|
+
lines << " const QVariant #{variant} = QtRubyRuntime::qvariant_from_qint_list(#{result});"
|
|
137
|
+
lines << " thread_local QByteArray #{utf8};"
|
|
138
|
+
lines << " #{utf8} = qvariant_to_bridge_string(#{variant}).toUtf8();"
|
|
139
|
+
lines << " return #{utf8}.constData();"
|
|
140
|
+
end
|
|
141
|
+
|
|
102
142
|
def emit_value
|
|
103
143
|
lines << " return #{invocation};"
|
|
104
144
|
end
|
|
145
|
+
|
|
146
|
+
def emit_int_cast
|
|
147
|
+
lines << " return static_cast<int>(#{invocation});"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def unique_local_name(suffix)
|
|
151
|
+
used = Array(method[:args]).map { |arg| arg[:name].to_s }.to_set
|
|
152
|
+
candidate = "qt_ruby_#{suffix}"
|
|
153
|
+
candidate += '_' while used.include?(candidate)
|
|
154
|
+
candidate
|
|
155
|
+
end
|
|
105
156
|
end
|
|
@@ -15,9 +15,25 @@ def all_ffi_functions(specs, free_function_specs:)
|
|
|
15
15
|
append_method_ffi_functions(fns, spec)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
value_wrapper_classes(specs, free_function_specs: free_function_specs).each do |qt_class|
|
|
19
|
+
fns << { name: qt_value_delete_function_name(qt_class), ffi_return: :void, args: [:pointer] }
|
|
20
|
+
end
|
|
21
|
+
|
|
18
22
|
fns
|
|
19
23
|
end
|
|
20
24
|
|
|
25
|
+
def value_wrapper_classes(specs, free_function_specs: [])
|
|
26
|
+
spec_classes = specs.flat_map do |spec|
|
|
27
|
+
spec[:methods].filter_map { |method| method[:value_class] if method[:return_cast] == :qt_value_copy }
|
|
28
|
+
end
|
|
29
|
+
free_classes = free_function_specs.filter_map { |spec| spec[:value_class] }
|
|
30
|
+
(spec_classes + free_classes).uniq.sort
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def qt_value_delete_function_name(qt_class)
|
|
34
|
+
"qt_ruby_#{to_snake(qt_class)}_value_delete"
|
|
35
|
+
end
|
|
36
|
+
|
|
21
37
|
def append_constructor_ffi_function(fns, spec)
|
|
22
38
|
return if spec[:constructor][:mode] == :wrap_only
|
|
23
39
|
|
|
@@ -42,7 +58,7 @@ end
|
|
|
42
58
|
|
|
43
59
|
def append_method_ffi_functions(fns, spec)
|
|
44
60
|
spec[:methods].each do |method|
|
|
45
|
-
args = [:pointer] + method[:args].map { |arg| arg[:ffi] }
|
|
61
|
+
args = [:pointer] + (method[:dispatch] ? [:int] : []) + method[:args].map { |arg| arg[:ffi] }
|
|
46
62
|
fns << { name: method_function_name(spec, method), ffi_return: method[:ffi_return], args: args }
|
|
47
63
|
end
|
|
48
64
|
end
|