gtk+-4.0: Update to 3.93.0+6aeae2c8
[vala-gnome.git] / codegen / valagasyncmodule.vala
blobdd8e916e202bdaea8596d5310e6a10a53bd85ff4
1 /* valagasyncmodule.vala
3 * Copyright (C) 2008-2012 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library 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 GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 public class Vala.GAsyncModule : GtkModule {
26 CCodeStruct generate_data_struct (Method m) {
27 string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
28 var data = new CCodeStruct ("_" + dataname);
30 data.add_field ("int", "_state_");
31 data.add_field ("GObject*", "_source_object_");
32 data.add_field ("GAsyncResult*", "_res_");
34 data.add_field ("GTask*", "_async_result");
35 if (!context.require_glib_version (2, 44)) {
36 data.add_field ("GAsyncReadyCallback", "_callback_");
37 data.add_field ("gboolean", "_task_complete_");
40 if (m is CreationMethod) {
41 data.add_field ("GType", "object_type");
44 if (m.binding == MemberBinding.INSTANCE) {
45 var type_sym = (TypeSymbol) m.parent_symbol;
46 if (type_sym is ObjectTypeSymbol) {
47 data.add_field (get_ccode_name (type_sym) + "*", "self");
48 } else {
49 data.add_field (get_ccode_name (type_sym), "self");
53 foreach (Parameter param in m.get_parameters ()) {
54 bool is_unowned_delegate = param.variable_type is DelegateType && !param.variable_type.value_owned;
56 var param_type = param.variable_type.copy ();
57 param_type.value_owned = true;
58 data.add_field (get_ccode_name (param_type), get_variable_cname (param.name));
60 if (param.variable_type is ArrayType) {
61 var array_type = (ArrayType) param.variable_type;
62 if (get_ccode_array_length (param)) {
63 for (int dim = 1; dim <= array_type.rank; dim++) {
64 data.add_field ("gint", get_parameter_array_length_cname (param, dim));
67 } else if (param.variable_type is DelegateType) {
68 var deleg_type = (DelegateType) param.variable_type;
69 if (deleg_type.delegate_symbol.has_target) {
70 data.add_field ("gpointer", get_ccode_delegate_target_name (param));
71 if (!is_unowned_delegate) {
72 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
78 foreach (var type_param in m.get_type_parameters ()) {
79 data.add_field ("GType", "%s_type".printf (type_param.name.down ()));
80 data.add_field ("GBoxedCopyFunc", "%s_dup_func".printf (type_param.name.down ()));
81 data.add_field ("GDestroyNotify", "%s_destroy_func".printf (type_param.name.down ()));
84 if (!(m.return_type is VoidType)) {
85 data.add_field (get_ccode_name (m.return_type), "result");
86 if (m.return_type is ArrayType) {
87 var array_type = (ArrayType) m.return_type;
88 if (get_ccode_array_length (m)) {
89 for (int dim = 1; dim <= array_type.rank; dim++) {
90 data.add_field ("gint", get_array_length_cname ("result", dim));
93 } else if (m.return_type is DelegateType) {
94 var deleg_type = (DelegateType) m.return_type;
95 if (deleg_type.delegate_symbol.has_target) {
96 data.add_field ("gpointer", get_delegate_target_cname ("result"));
97 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname ("result"));
102 return data;
105 CCodeFunction generate_free_function (Method m) {
106 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
108 var freefunc = new CCodeFunction (get_ccode_real_name (m) + "_data_free", "void");
109 freefunc.modifiers = CCodeModifiers.STATIC;
110 freefunc.add_parameter (new CCodeParameter ("_data", "gpointer"));
112 push_context (new EmitContext (m));
113 push_function (freefunc);
115 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_", new CCodeIdentifier ("_data")));
117 foreach (Parameter param in m.get_parameters ()) {
118 if (!param.captured && param.direction != ParameterDirection.OUT) {
119 var param_type = param.variable_type.copy ();
120 if (!param_type.value_owned) {
121 param_type.value_owned = !no_implicit_copy (param_type);
124 if (requires_destroy (param_type)) {
125 ccode.add_expression (destroy_parameter (param));
130 if (requires_destroy (m.return_type)) {
131 if (get_ccode_array_length (m) || !(m.return_type is ArrayType)) {
132 /* this is very evil. */
133 var v = new LocalVariable (m.return_type, ".result");
134 ccode.add_expression (destroy_local (v));
135 } else {
136 var v = new GLibValue (m.return_type, new CCodeIdentifier ("_data_->result"), true);
137 v.array_null_terminated = get_ccode_array_null_terminated (m);
138 ccode.add_expression (destroy_value (v));
142 if (m.binding == MemberBinding.INSTANCE) {
143 var this_type = m.this_parameter.variable_type.copy ();
144 this_type.value_owned = true;
146 if (requires_destroy (this_type)) {
147 ccode.add_expression (destroy_parameter (m.this_parameter));
151 var freecall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
152 freecall.add_argument (new CCodeIdentifier (dataname));
153 freecall.add_argument (new CCodeIdentifier ("_data_"));
154 ccode.add_expression (freecall);
156 pop_context ();
158 cfile.add_function_declaration (freefunc);
159 cfile.add_function (freefunc);
161 return freefunc;
164 void generate_async_ready_callback_wrapper (Method m, string function_name) {
165 var function = new CCodeFunction (function_name, "void");
166 function.modifiers = CCodeModifiers.STATIC;
168 function.add_parameter (new CCodeParameter ("*source_object", "GObject"));
169 function.add_parameter (new CCodeParameter ("*res", "GAsyncResult"));
170 function.add_parameter (new CCodeParameter ("*user_data", "void"));
172 push_function (function);
174 // Set _task_complete_ to false after calling back to the real func
175 var async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_TASK"));
176 async_result_cast.add_argument (new CCodeIdentifier ("res"));
178 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
179 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_task_data_"));
181 var get_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_task_data"));
182 get_data_call.add_argument (async_result_cast);
184 var data_var = new CCodeIdentifier ("_task_data_");
185 ccode.add_assignment (data_var, get_data_call);
187 var task_inner_callback = new CCodeMemberAccess.pointer (data_var, "_callback_");
188 var callback_is_nonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, task_inner_callback, new CCodeConstant ("NULL"));
190 ccode.open_if (callback_is_nonnull);
191 var nested_callback = new CCodeFunctionCall (task_inner_callback);
192 nested_callback.add_argument (new CCodeIdentifier ("source_object"));
193 nested_callback.add_argument (new CCodeIdentifier ("res"));
194 nested_callback.add_argument (new CCodeIdentifier ("user_data"));
195 ccode.add_expression (nested_callback);
196 ccode.close ();
198 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_task_complete_"), new CCodeConstant ("TRUE"));
200 pop_function ();
202 cfile.add_function_declaration (function);
203 cfile.add_function (function);
206 void generate_async_function (Method m) {
207 push_context (new EmitContext ());
209 string? callback_wrapper = null;
211 if (!context.require_glib_version (2, 44)) {
212 callback_wrapper = get_ccode_real_name (m) + "_async_ready_wrapper";
213 generate_async_ready_callback_wrapper (m, callback_wrapper);
216 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
217 var asyncfunc = new CCodeFunction (get_ccode_real_name (m), "void");
218 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
220 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
221 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
223 generate_cparameters (m, cfile, cparam_map, asyncfunc, null, null, null, 1);
225 if (m.base_method != null || m.base_interface_method != null) {
226 // declare *_real_* function
227 asyncfunc.modifiers |= CCodeModifiers.STATIC;
228 cfile.add_function_declaration (asyncfunc);
229 } else if (m.is_private_symbol ()) {
230 asyncfunc.modifiers |= CCodeModifiers.STATIC;
231 } else if (context.hide_internal && m.is_internal_symbol ()) {
232 asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
235 push_function (asyncfunc);
237 // logic copied from valaccodemethodmodule
238 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
239 Method base_method;
241 if (m.overrides) {
242 base_method = m.base_method;
243 } else {
244 base_method = m.base_interface_method;
247 var base_expression_type = new ObjectType ((ObjectTypeSymbol) base_method.parent_symbol);
248 var type_symbol = m.parent_symbol as ObjectTypeSymbol;
250 var self_target_type = new ObjectType (type_symbol);
251 var cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
252 ccode.add_declaration ("%s *".printf (get_ccode_name (type_symbol)), new CCodeVariableDeclarator ("self"));
253 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
256 var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
257 dataalloc.add_argument (new CCodeIdentifier (dataname));
259 var data_var = new CCodeIdentifier ("_data_");
261 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
262 ccode.add_assignment (data_var, dataalloc);
264 if (!context.require_glib_version (2, 44)) {
265 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_callback_"), new CCodeConstant ("_callback_"));
268 var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new"));
270 var t = m.parent_symbol as TypeSymbol;
271 if (!(m is CreationMethod) && m.binding == MemberBinding.INSTANCE &&
272 t != null && t.is_subtype_of (gobject_type)) {
273 var gobject_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
274 gobject_cast.add_argument (new CCodeIdentifier ("self"));
276 create_result.add_argument (gobject_cast);
277 } else {
278 create_result.add_argument (new CCodeConstant ("NULL"));
281 Parameter cancellable_param = null;
283 foreach (Parameter param in m.get_parameters ()) {
284 if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
285 cancellable_param = param;
286 break;
290 if (cancellable_param == null) {
291 create_result.add_argument (new CCodeConstant ("NULL"));
292 } else {
293 create_result.add_argument (new CCodeIdentifier (get_variable_cname (cancellable_param.name)));
296 if (context.require_glib_version (2, 44)) {
297 create_result.add_argument (new CCodeIdentifier ("_callback_"));
298 } else {
299 create_result.add_argument (new CCodeIdentifier (callback_wrapper));
301 create_result.add_argument (new CCodeIdentifier ("_user_data_"));
303 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_async_result"), create_result);
305 if (!context.require_glib_version (2, 44)) {
306 var task_completed_var = new CCodeMemberAccess.pointer (data_var, "_task_complete_");
307 var callback = new CCodeIdentifier ("_callback_");
308 var callback_is_null = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, callback, new CCodeConstant ("NULL"));
310 ccode.open_if (callback_is_null);
311 ccode.add_assignment (task_completed_var, new CCodeConstant ("TRUE"));
312 ccode.close ();
315 var attach_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_set_task_data"));
317 attach_data_call.add_argument (new CCodeMemberAccess.pointer (data_var, "_async_result"));
318 attach_data_call.add_argument (data_var);
319 attach_data_call.add_argument (new CCodeIdentifier (get_ccode_real_name (m) + "_data_free"));
320 ccode.add_expression (attach_data_call);
322 if (m is CreationMethod) {
323 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "object_type"), new CCodeIdentifier ("object_type"));
324 } else if (m.binding == MemberBinding.INSTANCE) {
325 var this_type = m.this_parameter.variable_type.copy ();
326 this_type.value_owned = true;
328 // create copy if necessary as variables in async methods may need to be kept alive
329 CCodeExpression cself = new CCodeIdentifier ("self");
330 if (this_type.is_real_non_null_struct_type ()) {
331 cself = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cself);
333 if (requires_copy (this_type)) {
334 cself = get_cvalue_ (copy_value (new GLibValue (m.this_parameter.variable_type, cself, true), m.this_parameter));
337 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), cself);
340 emit_context.push_symbol (m);
341 foreach (Parameter param in m.get_parameters ()) {
342 if (param.direction != ParameterDirection.OUT) {
343 // create copy if necessary as variables in async methods may need to be kept alive
344 var old_captured = param.captured;
345 param.captured = false;
346 current_method.coroutine = false;
348 TargetValue value;
349 if (param.variable_type.value_owned) {
350 // do not use load_parameter for reference/ownership transfer
351 // otherwise delegate destroy notify will not be moved
352 value = get_parameter_cvalue (param);
353 } else {
354 value = load_parameter (param);
357 current_method.coroutine = true;
359 store_parameter (param, value);
361 param.captured = old_captured;
364 emit_context.pop_symbol ();
366 foreach (var type_param in m.get_type_parameters ()) {
367 var type = "%s_type".printf (type_param.name.down ());
368 var dup_func = "%s_dup_func".printf (type_param.name.down ());
369 var destroy_func = "%s_destroy_func".printf (type_param.name.down ());
370 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, type), new CCodeIdentifier (type));
371 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, dup_func), new CCodeIdentifier (dup_func));
372 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, destroy_func), new CCodeIdentifier (destroy_func));
375 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
376 ccall.add_argument (data_var);
377 ccode.add_expression (ccall);
379 cfile.add_function (asyncfunc);
381 pop_context ();
384 void append_struct (CCodeStruct structure) {
385 var typename = new CCodeVariableDeclarator (structure.name.substring (1));
386 var typedef = new CCodeTypeDefinition ("struct " + structure.name, typename);
387 cfile.add_type_declaration (typedef);
388 cfile.add_type_definition (structure);
391 public override void generate_method_declaration (Method m, CCodeFile decl_space) {
392 if (m.coroutine) {
393 if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
394 return;
397 var cl = m.parent_symbol as Class;
399 var asyncfunc = new CCodeFunction (get_ccode_name (m), "void");
400 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
401 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
403 if (m.is_private_symbol ()) {
404 asyncfunc.modifiers |= CCodeModifiers.STATIC;
405 } else if (context.hide_internal && m.is_internal_symbol ()) {
406 asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
409 // do not generate _new functions for creation methods of abstract classes
410 if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
411 generate_cparameters (m, decl_space, cparam_map, asyncfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 1);
413 decl_space.add_function_declaration (asyncfunc);
416 var finishfunc = new CCodeFunction (get_ccode_finish_name (m));
417 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
418 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
420 if (m.is_private_symbol ()) {
421 finishfunc.modifiers |= CCodeModifiers.STATIC;
422 } else if (context.hide_internal && m.is_internal_symbol ()) {
423 finishfunc.modifiers |= CCodeModifiers.INTERNAL;
426 // do not generate _new functions for creation methods of abstract classes
427 if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
428 generate_cparameters (m, decl_space, cparam_map, finishfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 2);
430 decl_space.add_function_declaration (finishfunc);
433 if (m is CreationMethod && cl != null) {
434 // _construct function
435 var function = new CCodeFunction (get_ccode_real_name (m));
437 if (m.is_private_symbol ()) {
438 function.modifiers |= CCodeModifiers.STATIC;
439 } else if (context.hide_internal && m.is_internal_symbol ()) {
440 function.modifiers |= CCodeModifiers.INTERNAL;
443 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
444 generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 1);
446 decl_space.add_function_declaration (function);
448 function = new CCodeFunction (get_ccode_finish_real_name (m));
450 if (m.is_private_symbol ()) {
451 function.modifiers |= CCodeModifiers.STATIC;
452 } else if (context.hide_internal && m.is_internal_symbol ()) {
453 function.modifiers |= CCodeModifiers.INTERNAL;
456 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
457 generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 2);
459 decl_space.add_function_declaration (function);
461 } else {
462 base.generate_method_declaration (m, decl_space);
466 public override void visit_method (Method m) {
467 if (m.coroutine) {
468 cfile.add_include ("gio/gio.h");
469 if (!m.is_internal_symbol ()) {
470 header_file.add_include ("gio/gio.h");
473 if (!m.is_abstract && m.body != null) {
474 var data = generate_data_struct (m);
476 closure_struct = data;
478 generate_free_function (m);
479 generate_async_function (m);
480 generate_finish_function (m);
482 // append the _co function
483 base.visit_method (m);
484 closure_struct = null;
486 // only append data struct here to make sure all struct member
487 // types are declared before the struct definition
488 append_struct (data);
489 } else {
490 generate_method_declaration (m, cfile);
492 if (!m.is_internal_symbol ()) {
493 generate_method_declaration (m, header_file);
495 if (!m.is_private_symbol ()) {
496 generate_method_declaration (m, internal_header_file);
500 if (m.is_abstract || m.is_virtual) {
501 // generate virtual function wrappers
502 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
503 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
504 generate_vfunc (m, new VoidType (), cparam_map, carg_map, "", 1);
506 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
507 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
508 generate_vfunc (m, m.return_type, cparam_map, carg_map, "_finish", 2);
510 } else {
511 base.visit_method (m);
515 public override void visit_creation_method (CreationMethod m) {
516 if (!m.coroutine) {
517 base.visit_creation_method (m);
518 } else {
519 push_line (m.source_reference);
521 bool visible = !m.is_private_symbol ();
523 visit_method (m);
525 if (m.source_type == SourceFileType.FAST) {
526 return;
529 // do not generate _new functions for creation methods of abstract classes
530 if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
531 var vfunc = new CCodeFunction (get_ccode_name (m));
533 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
534 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
536 push_function (vfunc);
538 var vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
539 vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
541 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 1);
542 ccode.add_expression (vcall);
544 if (!visible) {
545 vfunc.modifiers |= CCodeModifiers.STATIC;
548 pop_function ();
550 cfile.add_function (vfunc);
553 vfunc = new CCodeFunction (get_ccode_finish_name (m));
555 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
556 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
558 push_function (vfunc);
560 vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_real_name (m)));
562 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 2);
563 ccode.add_return (vcall);
565 if (!visible) {
566 vfunc.modifiers |= CCodeModifiers.STATIC;
569 pop_function ();
571 cfile.add_function (vfunc);
574 pop_line ();
578 void generate_finish_function (Method m) {
579 push_context (new EmitContext ());
581 string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
583 var finishfunc = new CCodeFunction (get_ccode_finish_real_name (m));
585 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
587 cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
589 generate_cparameters (m, cfile, cparam_map, finishfunc, null, null, null, 2);
591 if (m.is_private_symbol () || m.base_method != null || m.base_interface_method != null) {
592 finishfunc.modifiers |= CCodeModifiers.STATIC;
593 } else if (context.hide_internal && m.is_internal_symbol ()) {
594 finishfunc.modifiers |= CCodeModifiers.INTERNAL;
597 push_function (finishfunc);
599 var return_type = m.return_type;
600 if (m is CreationMethod) {
601 var type_sym = (TypeSymbol) m.parent_symbol;
602 if (type_sym is ObjectTypeSymbol) {
603 ccode.add_declaration (get_ccode_name (type_sym) + "*", new CCodeVariableDeclarator ("result"));
605 } else if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type ()) {
606 ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("result"));
609 var data_var = new CCodeIdentifier ("_data_");
611 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
613 var async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_TASK"));
614 async_result_cast.add_argument (new CCodeIdentifier ("_res_"));
616 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer"));
617 ccall.add_argument (async_result_cast);
619 if (m.get_error_types ().size > 0) {
620 ccall.add_argument (new CCodeIdentifier ("error"));
621 } else {
622 ccall.add_argument (new CCodeConstant ("NULL"));
625 ccode.add_assignment (data_var, ccall);
627 bool has_cancellable = false;
629 foreach (Parameter param in m.get_parameters ()) {
630 if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
631 has_cancellable = true;
632 break;
636 // If a task is cancelled, g_task_propagate_pointer returns NULL
637 if (m.get_error_types ().size > 0 || has_cancellable) {
638 var is_null = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), data_var);
640 ccode.open_if (is_null);
641 return_default_value (return_type);
642 ccode.close ();
645 emit_context.push_symbol (m);
646 foreach (Parameter param in m.get_parameters ()) {
647 if (param.direction != ParameterDirection.IN) {
648 return_out_parameter (param);
649 if (!(param.variable_type is ValueType) || param.variable_type.nullable) {
650 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_variable_cname (param.name)), new CCodeConstant ("NULL"));
654 emit_context.pop_symbol ();
656 if (m is CreationMethod) {
657 ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "self"));
658 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), new CCodeConstant ("NULL"));
659 ccode.add_return (new CCodeIdentifier ("result"));
660 } else if (return_type.is_real_non_null_struct_type ()) {
661 // structs are returned via out parameter
662 CCodeExpression cexpr = new CCodeMemberAccess.pointer (data_var, "result");
663 if (requires_copy (return_type)) {
664 cexpr = get_cvalue_ (copy_value (new GLibValue (return_type, cexpr, true), return_type));
666 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result")), cexpr);
667 } else if (!(return_type is VoidType)) {
668 ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "result"));
669 if (return_type is ArrayType) {
670 var array_type = (ArrayType) return_type;
671 if (get_ccode_array_length (m)) {
672 for (int dim = 1; dim <= array_type.rank; dim++) {
673 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_array_length_cname ("result", dim))), new CCodeMemberAccess.pointer (data_var, get_array_length_cname ("result", dim)));
676 } else if (return_type is DelegateType && ((DelegateType) return_type).delegate_symbol.has_target) {
677 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_delegate_target_cname ("result"))), new CCodeMemberAccess.pointer (data_var, get_delegate_target_cname ("result")));
679 if (!(return_type is ValueType) || return_type.nullable) {
680 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "result"), new CCodeConstant ("NULL"));
682 ccode.add_return (new CCodeIdentifier ("result"));
685 pop_function ();
687 cfile.add_function (finishfunc);
689 pop_context ();
692 public override string generate_ready_function (Method m) {
693 // generate ready callback handler
695 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
697 var readyfunc = new CCodeFunction (get_ccode_name (m) + "_ready", "void");
699 if (!add_wrapper (readyfunc.name)) {
700 // wrapper already defined
701 return readyfunc.name;
704 readyfunc.add_parameter (new CCodeParameter ("source_object", "GObject*"));
705 readyfunc.add_parameter (new CCodeParameter ("_res_", "GAsyncResult*"));
706 readyfunc.add_parameter (new CCodeParameter ("_user_data_", "gpointer"));
708 push_function (readyfunc);
710 var data_var = new CCodeIdentifier ("_data_");
712 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
713 ccode.add_assignment (data_var, new CCodeIdentifier ("_user_data_"));
714 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_source_object_"), new CCodeIdentifier ("source_object"));
715 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_res_"), new CCodeIdentifier ("_res_"));
717 if (!context.require_glib_version (2, 44)) {
718 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_task_complete_"), new CCodeConstant ("TRUE"));
721 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
722 ccall.add_argument (data_var);
723 ccode.add_expression (ccall);
725 readyfunc.modifiers |= CCodeModifiers.STATIC;
727 pop_function ();
729 cfile.add_function_declaration (readyfunc);
730 cfile.add_function (readyfunc);
732 return readyfunc.name;
735 public override void generate_virtual_method_declaration (Method m, CCodeFile decl_space, CCodeStruct type_struct) {
736 if (!m.coroutine) {
737 base.generate_virtual_method_declaration (m, decl_space, type_struct);
738 return;
741 if (!m.is_abstract && !m.is_virtual) {
742 return;
745 var creturn_type = m.return_type;
746 if (m.return_type.is_real_non_null_struct_type ()) {
747 // structs are returned via out parameter
748 creturn_type = new VoidType ();
751 // add vfunc field to the type struct
752 var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
753 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
755 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 1);
757 var vdecl = new CCodeDeclaration ("void");
758 vdecl.add_declarator (vdeclarator);
759 type_struct.add_declaration (vdecl);
761 // add vfunc field to the type struct
762 vdeclarator = new CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m));
763 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
765 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 2);
767 vdecl = new CCodeDeclaration (get_ccode_name (creturn_type));
768 vdecl.add_declarator (vdeclarator);
769 type_struct.add_declaration (vdecl);
772 public override void visit_yield_statement (YieldStatement stmt) {
773 if (!is_in_coroutine ()) {
774 return;
777 if (stmt.yield_expression == null) {
778 int state = emit_context.next_coroutine_state++;
780 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
781 ccode.add_return (new CCodeConstant ("FALSE"));
782 ccode.add_label ("_state_%d".printf (state));
783 ccode.add_statement (new CCodeEmptyStatement ());
785 return;
788 if (stmt.yield_expression.error) {
789 stmt.error = true;
790 return;
793 ccode.add_expression (get_cvalue (stmt.yield_expression));
795 if (stmt.tree_can_fail && stmt.yield_expression.tree_can_fail) {
796 // simple case, no node breakdown necessary
798 add_simple_check (stmt.yield_expression);
801 /* free temporary objects */
803 foreach (var value in temp_ref_values) {
804 ccode.add_expression (destroy_value (value));
807 temp_ref_values.clear ();
810 public override void return_with_exception (CCodeExpression error_expr)
812 if (!is_in_coroutine ()) {
813 base.return_with_exception (error_expr);
814 return;
817 var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_async_result");
818 CCodeFunctionCall set_error = null;
820 set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_error"));
821 set_error.add_argument (async_result_expr);
822 set_error.add_argument (error_expr);
823 ccode.add_expression (set_error);
825 append_local_free (current_symbol, false);
827 // We already returned the error above, we must not return anything else here.
828 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
829 unref.add_argument (async_result_expr);
830 ccode.add_expression (unref);
832 ccode.add_return (new CCodeConstant ("FALSE"));
835 public override void visit_return_statement (ReturnStatement stmt) {
836 base.visit_return_statement (stmt);
838 if (!is_in_coroutine ()) {
839 return;
842 complete_async ();
845 public override void generate_cparameters (Method m, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
846 if (m.coroutine) {
847 decl_space.add_include ("gio/gio.h");
849 if (direction == 1) {
850 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
851 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
852 if (carg_map != null) {
853 carg_map.set (get_param_pos (-1), new CCodeIdentifier ("_callback_"));
854 carg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_user_data_"));
856 } else if (direction == 2) {
857 cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
858 if (carg_map != null) {
859 carg_map.set (get_param_pos (0.1), new CCodeIdentifier ("_res_"));
863 base.generate_cparameters (m, decl_space, cparam_map, func, vdeclarator, carg_map, vcall, direction);
866 public string generate_async_callback_wrapper () {
867 string async_callback_wrapper_func = "_vala_g_async_ready_callback";
869 if (!add_wrapper (async_callback_wrapper_func)) {
870 return async_callback_wrapper_func;
873 var function = new CCodeFunction (async_callback_wrapper_func, "void");
874 function.modifiers = CCodeModifiers.STATIC;
876 function.add_parameter (new CCodeParameter ("*source_object", "GObject"));
877 function.add_parameter (new CCodeParameter ("*res", "GAsyncResult"));
878 function.add_parameter (new CCodeParameter ("*user_data", "void"));
880 push_function (function);
882 var res_ref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
883 res_ref.add_argument (new CCodeIdentifier ("res"));
885 CCodeFunctionCall ccall = null;
887 // store reference to async result of inner async function in out async result
888 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer"));
889 ccall.add_argument (new CCodeIdentifier ("user_data"));
890 ccall.add_argument (res_ref);
891 ccall.add_argument (new CCodeIdentifier ("g_object_unref"));
892 ccode.add_expression (ccall);
894 // free async result
895 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
896 ccall.add_argument (new CCodeIdentifier ("user_data"));
897 ccode.add_expression (ccall);
899 pop_function ();
901 cfile.add_function_declaration (function);
902 cfile.add_function (function);
904 return async_callback_wrapper_func;