gstreamer-1.0: Update to 1.13.1+
[vala-gnome.git] / codegen / valagvariantmodule.vala
blobbca03f12cb0ba2bc7b158fb9becca78dc53cc0a4
1 /* valagvariantmodule.vala
3 * Copyright (C) 2010-2011 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 public class Vala.GVariantModule : GAsyncModule {
24 struct BasicTypeInfo {
25 public unowned string signature;
26 public unowned string type_name;
27 public bool is_string;
30 const BasicTypeInfo[] basic_types = {
31 { "y", "byte", false },
32 { "b", "boolean", false },
33 { "n", "int16", false },
34 { "q", "uint16", false },
35 { "i", "int32", false },
36 { "u", "uint32", false },
37 { "x", "int64", false },
38 { "t", "uint64", false },
39 { "d", "double", false },
40 { "s", "string", true },
41 { "o", "object_path", true },
42 { "g", "signature", true }
45 static bool is_string_marshalled_enum (TypeSymbol? symbol) {
46 if (symbol != null && symbol is Enum) {
47 return symbol.get_attribute_bool ("DBus", "use_string_marshalling");
49 return false;
52 string get_dbus_value (EnumValue value, string default_value) {
53 var dbus_value = value.get_attribute_string ("DBus", "value");
54 if (dbus_value != null) {
55 return dbus_value;;
57 return default_value;
60 public static string? get_dbus_signature (Symbol symbol) {
61 return symbol.get_attribute_string ("DBus", "signature");
64 bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
65 foreach (BasicTypeInfo info in basic_types) {
66 if (info.signature == signature) {
67 basic_type = info;
68 return true;
71 basic_type = BasicTypeInfo ();
72 return false;
75 public static string? get_type_signature (DataType datatype, Symbol? symbol = null) {
76 if (symbol != null) {
77 string sig = get_dbus_signature (symbol);
78 if (sig != null) {
79 // allow overriding signature in attribute, used for raw GVariants
80 return sig;
84 var array_type = datatype as ArrayType;
86 if (array_type != null) {
87 string element_type_signature = get_type_signature (array_type.element_type);
89 if (element_type_signature == null) {
90 return null;
93 return string.nfill (array_type.rank, 'a') + element_type_signature;
94 } else if (is_string_marshalled_enum (datatype.data_type)) {
95 return "s";
96 } else if (datatype.data_type != null) {
97 string sig = datatype.data_type.get_attribute_string ("CCode", "type_signature");
99 var st = datatype.data_type as Struct;
100 var en = datatype.data_type as Enum;
101 if (sig == null && st != null) {
102 var str = new StringBuilder ();
103 str.append_c ('(');
104 foreach (Field f in st.get_fields ()) {
105 if (f.binding == MemberBinding.INSTANCE) {
106 str.append (get_type_signature (f.variable_type, f));
109 str.append_c (')');
110 sig = str.str;
111 } else if (sig == null && en != null) {
112 if (en.is_flags) {
113 return "u";
114 } else {
115 return "i";
119 var type_args = datatype.get_type_arguments ();
120 if (sig != null && "%s" in sig && type_args.size > 0) {
121 string element_sig = "";
122 foreach (DataType type_arg in type_args) {
123 var s = get_type_signature (type_arg);
124 if (s != null) {
125 element_sig += s;
129 sig = sig.replace ("%s", element_sig);
132 if (sig == null &&
133 (datatype.data_type.get_full_name () == "GLib.UnixInputStream" ||
134 datatype.data_type.get_full_name () == "GLib.UnixOutputStream" ||
135 datatype.data_type.get_full_name () == "GLib.Socket")) {
136 return "h";
139 return sig;
140 } else {
141 return null;
145 public override void visit_enum (Enum en) {
146 base.visit_enum (en);
148 if (is_string_marshalled_enum (en)) {
149 // strcmp
150 cfile.add_include ("string.h");
152 // for G_DBUS_ERROR
153 cfile.add_include ("gio/gio.h");
155 cfile.add_function (generate_enum_from_string_function (en));
156 cfile.add_function (generate_enum_to_string_function (en));
160 public override bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
161 if (base.generate_enum_declaration (en, decl_space)) {
162 if (is_string_marshalled_enum (en)) {
163 decl_space.add_function_declaration (generate_enum_from_string_function_declaration (en));
164 decl_space.add_function_declaration (generate_enum_to_string_function_declaration (en));
166 return true;
168 return false;
171 CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
172 var id = expr as CCodeIdentifier;
173 var ma = expr as CCodeMemberAccess;
174 if (id != null) {
175 return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
176 } else if (ma != null) {
177 if (ma.is_pointer) {
178 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
179 } else {
180 return new CCodeMemberAccess (ma.inner, "%s_length%d".printf (ma.member_name, dim));
182 } else {
183 // must be NULL-terminated
184 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
185 len_call.add_argument (expr);
186 return len_call;
190 CCodeExpression? generate_enum_value_from_string (EnumValueType type, CCodeExpression? expr, CCodeExpression? error_expr) {
191 var en = type.type_symbol as Enum;
192 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
194 var from_string_call = new CCodeFunctionCall (new CCodeIdentifier (from_string_name));
195 from_string_call.add_argument (expr);
196 from_string_call.add_argument (error_expr != null ? error_expr : new CCodeConstant ("NULL"));
198 return from_string_call;
201 public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
202 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
204 var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
205 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
206 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
208 return from_string_func;
211 public CCodeFunction generate_enum_from_string_function (Enum en) {
212 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
214 var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
215 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
216 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
218 push_function (from_string_func);
220 ccode.add_declaration (get_ccode_name (en), new CCodeVariableDeclarator.zero ("value", new CCodeConstant ("0")));
222 bool firstif = true;
223 foreach (EnumValue enum_value in en.get_values ()) {
224 string dbus_value = get_dbus_value (enum_value, enum_value.name);
225 var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
226 string_comparison.add_argument (new CCodeIdentifier ("str"));
227 string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
228 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0"));
229 if (firstif) {
230 ccode.open_if (cond);
231 firstif = false;
232 } else {
233 ccode.else_if (cond);
235 ccode.add_assignment (new CCodeIdentifier ("value"), new CCodeIdentifier (get_ccode_name (enum_value)));
238 ccode.add_else ();
239 var set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
240 set_error.add_argument (new CCodeIdentifier ("error"));
241 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR"));
242 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR_INVALID_ARGS"));
243 set_error.add_argument (new CCodeConstant ("\"Invalid value for enum `%s'\"".printf (get_ccode_name (en))));
244 ccode.add_expression (set_error);
245 ccode.close ();
247 ccode.add_return (new CCodeIdentifier ("value"));
249 pop_function ();
250 return from_string_func;
253 CCodeExpression deserialize_basic (BasicTypeInfo basic_type, CCodeExpression variant_expr, bool transfer = false) {
254 var get_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_" + basic_type.type_name));
255 get_call.add_argument (variant_expr);
257 if (basic_type.is_string) {
258 if (transfer) {
259 get_call.call = new CCodeIdentifier ("g_variant_get_string");
260 } else {
261 get_call.call = new CCodeIdentifier ("g_variant_dup_string");
263 get_call.add_argument (new CCodeConstant ("NULL"));
266 return get_call;
269 CCodeExpression deserialize_array (ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
270 if (array_type.rank == 1 && get_type_signature (array_type) == "ay") {
271 return deserialize_buffer_array (array_type, variant_expr, expr);
274 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
276 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
277 new_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
278 // add one extra element for NULL-termination
279 new_call.add_argument (new CCodeConstant ("5"));
281 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (temp_name, new_call));
282 ccode.add_declaration ("int", new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
283 ccode.add_declaration ("int", new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
285 deserialize_array_dim (array_type, 1, temp_name, variant_expr, expr);
287 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
288 // NULL terminate array
289 var length = new CCodeIdentifier (temp_name + "_length");
290 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
291 ccode.add_assignment (element_access, new CCodeIdentifier ("NULL"));
294 return new CCodeIdentifier (temp_name);
297 void deserialize_array_dim (ArrayType array_type, int dim, string temp_name, CCodeExpression variant_expr, CCodeExpression? expr) {
298 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
299 string element_name = "_tmp%d_".printf (next_temp_var_id++);
301 ccode.add_declaration ("int", new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
302 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
303 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (element_name));
305 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
306 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
307 iter_call.add_argument (variant_expr);
308 ccode.add_expression (iter_call);
310 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
311 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
313 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeAssignment (new CCodeIdentifier (element_name), iter_call), new CCodeConstant ("NULL"));
314 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
315 ccode.open_for (null, cforcond, cforiter);
317 if (dim < array_type.rank) {
318 deserialize_array_dim (array_type, dim + 1, temp_name, new CCodeIdentifier (element_name), expr);
319 } else {
320 var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
322 ccode.open_if (size_check);
324 // tmp_size = (2 * tmp_size);
325 var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
326 ccode.add_assignment (new CCodeIdentifier (temp_name + "_size"), new_size);
328 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
329 renew_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
330 renew_call.add_argument (new CCodeIdentifier (temp_name));
331 // add one extra element for NULL-termination
332 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
333 ccode.add_assignment (new CCodeIdentifier (temp_name), renew_call);
335 ccode.close ();
337 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
338 var element_expr = deserialize_expression (array_type.element_type, new CCodeIdentifier (element_name), null);
339 ccode.add_assignment (element_access, element_expr);
342 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
343 unref.add_argument (new CCodeIdentifier (element_name));
344 ccode.add_expression (unref);
346 ccode.close ();
348 if (expr != null) {
349 ccode.add_assignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
353 CCodeExpression deserialize_buffer_array (ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
354 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
356 var get_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_data"));
357 get_data_call.add_argument (variant_expr);
359 var get_size_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_size"));
360 get_size_call.add_argument (variant_expr);
361 ccode.add_declaration ("gsize", new CCodeVariableDeclarator (temp_name + "_length", get_size_call));
362 var length = new CCodeIdentifier (temp_name + "_length");
364 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
365 dup_call.add_argument (get_data_call);
366 dup_call.add_argument (length);
368 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (temp_name, dup_call));
369 if (expr != null) {
370 ccode.add_assignment (get_array_length (expr, 1), length);
373 return new CCodeIdentifier (temp_name);
376 CCodeExpression? deserialize_struct (Struct st, CCodeExpression variant_expr) {
377 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
378 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
380 ccode.add_declaration (get_ccode_name (st), new CCodeVariableDeclarator (temp_name));
381 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
383 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
384 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
385 iter_call.add_argument (variant_expr);
386 ccode.add_expression (iter_call);
388 bool field_found = false;;
390 foreach (Field f in st.get_fields ()) {
391 if (f.binding != MemberBinding.INSTANCE) {
392 continue;
395 field_found = true;
397 read_expression (f.variable_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), get_ccode_name (f)), f);
400 if (!field_found) {
401 return null;
404 return new CCodeIdentifier (temp_name);
407 CCodeExpression? deserialize_hash_table (ObjectType type, CCodeExpression variant_expr) {
408 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
409 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
410 string key_name = "_tmp%d_".printf (next_temp_var_id++);
411 string value_name = "_tmp%d_".printf (next_temp_var_id++);
413 var type_args = type.get_type_arguments ();
414 assert (type_args.size == 2);
415 var key_type = type_args.get (0);
416 var value_type = type_args.get (1);
418 ccode.add_declaration ("GHashTable*", new CCodeVariableDeclarator (temp_name));
419 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
420 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (key_name));
421 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (value_name));
423 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
424 if (key_type.data_type.is_subtype_of (string_type.data_type)) {
425 hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
426 hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
427 } else if (key_type.data_type == gvariant_type) {
428 hash_table_new.add_argument (new CCodeIdentifier ("g_variant_hash"));
429 hash_table_new.add_argument (new CCodeIdentifier ("g_variant_equal"));
430 } else {
431 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
432 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
435 if (key_type.data_type.is_subtype_of (string_type.data_type)) {
436 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
437 } else if (key_type.data_type == gvariant_type) {
438 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
439 } else if (key_type.data_type.get_full_name () == "GLib.HashTable") {
440 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
441 } else {
442 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
445 if (value_type.data_type.is_subtype_of (string_type.data_type)) {
446 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
447 } else if (value_type.data_type == gvariant_type) {
448 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
449 } else if (value_type.data_type.get_full_name () == "GLib.HashTable") {
450 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
451 } else {
452 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
454 ccode.add_assignment (new CCodeIdentifier (temp_name), hash_table_new);
456 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
457 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
458 iter_call.add_argument (variant_expr);
459 ccode.add_expression (iter_call);
461 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_loop"));
462 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
463 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
464 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
465 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
467 ccode.open_while (iter_call);
469 var key_expr = deserialize_expression (key_type, new CCodeIdentifier (key_name), null);
470 var value_expr = deserialize_expression (value_type, new CCodeIdentifier (value_name), null);
471 if (key_expr == null || value_expr == null) {
472 return null;
475 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
476 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
477 hash_table_insert.add_argument (convert_to_generic_pointer (key_expr, key_type));
478 hash_table_insert.add_argument (convert_to_generic_pointer (value_expr, value_type));
479 ccode.add_expression (hash_table_insert);
481 ccode.close ();
483 return new CCodeIdentifier (temp_name);
486 public override CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
487 BasicTypeInfo basic_type;
488 CCodeExpression result = null;
489 may_fail = false;
490 if (is_string_marshalled_enum (type.data_type)) {
491 get_basic_type_info ("s", out basic_type);
492 result = deserialize_basic (basic_type, variant_expr, true);
493 result = generate_enum_value_from_string (type as EnumValueType, result, error_expr);
494 may_fail = true;
495 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
496 result = deserialize_basic (basic_type, variant_expr);
497 } else if (type is ArrayType) {
498 result = deserialize_array ((ArrayType) type, variant_expr, expr);
499 } else if (type.data_type is Struct) {
500 var st = (Struct) type.data_type;
501 result = deserialize_struct (st, variant_expr);
502 if (result != null && type.nullable) {
503 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
504 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (st)));
505 var cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
506 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
507 cdup.add_argument (csizeof);
508 result = cdup;
510 } else if (type is ObjectType) {
511 if (type.data_type.get_full_name () == "GLib.Variant") {
512 var variant_get = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_variant"));
513 variant_get.add_argument (variant_expr);
514 result = variant_get;
515 } else if (type.data_type.get_full_name () == "GLib.HashTable") {
516 result = deserialize_hash_table ((ObjectType) type, variant_expr);
520 if (result == null) {
521 Report.error (type.source_reference, "GVariant deserialization of type `%s' is not supported".printf (type.to_string ()));
524 return result;
527 public void read_expression (DataType type, CCodeExpression iter_expr, CCodeExpression target_expr, Symbol? sym, CCodeExpression? error_expr = null, out bool may_fail = null) {
528 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
529 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
531 if (sym != null && get_dbus_signature (sym) != null) {
532 // raw GVariant
533 ccode.add_assignment (target_expr, iter_call);
534 may_fail = false;
535 return;
538 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
540 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (temp_name));
542 var variant_expr = new CCodeIdentifier (temp_name);
544 ccode.add_assignment (variant_expr, iter_call);
546 var result = deserialize_expression (type, variant_expr, target_expr, error_expr, out may_fail);
547 if (result == null) {
548 // error already reported
549 return;
552 ccode.add_assignment (target_expr, result);
554 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
555 unref.add_argument (variant_expr);
556 ccode.add_expression (unref);
559 CCodeExpression? generate_enum_value_to_string (EnumValueType type, CCodeExpression? expr) {
560 var en = type.type_symbol as Enum;
561 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
563 var to_string_call = new CCodeFunctionCall (new CCodeIdentifier (to_string_name));
564 to_string_call.add_argument (expr);
566 return to_string_call;
569 public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
570 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
572 var to_string_func = new CCodeFunction (to_string_name, "const char*");
573 to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
575 return to_string_func;
578 public CCodeFunction generate_enum_to_string_function (Enum en) {
579 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
581 var to_string_func = new CCodeFunction (to_string_name, "const char*");
582 to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
584 push_function (to_string_func);
586 ccode.add_declaration ("const char *", new CCodeVariableDeclarator ("str"));
588 ccode.open_switch (new CCodeIdentifier ("value"));
589 foreach (EnumValue enum_value in en.get_values ()) {
590 string dbus_value = get_dbus_value (enum_value, enum_value.name);
591 ccode.add_case (new CCodeIdentifier (get_ccode_name (enum_value)));
592 ccode.add_assignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)));
593 ccode.add_break ();
596 ccode.close();
598 ccode.add_return (new CCodeIdentifier ("str"));
600 pop_function ();
601 return to_string_func;
604 CCodeExpression? serialize_basic (BasicTypeInfo basic_type, CCodeExpression expr) {
605 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_" + basic_type.type_name));
606 new_call.add_argument (expr);
607 return new_call;
610 CCodeExpression? serialize_array (ArrayType array_type, CCodeExpression array_expr) {
611 if (array_type.rank == 1 && get_type_signature (array_type) == "ay") {
612 return serialize_buffer_array (array_type, array_expr);
615 string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
617 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (array_iter_name));
618 ccode.add_assignment (new CCodeIdentifier (array_iter_name), array_expr);
620 return serialize_array_dim (array_type, 1, array_expr, new CCodeIdentifier (array_iter_name));
623 CCodeExpression? serialize_array_dim (ArrayType array_type, int dim, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
624 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
625 string index_name = "_tmp%d_".printf (next_temp_var_id++);
627 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
628 ccode.add_declaration ("int", new CCodeVariableDeclarator (index_name));
630 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
631 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (array_type))));
633 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
634 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
635 builder_init.add_argument (gvariant_type);
636 ccode.add_expression (builder_init);
638 var cforinit = new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0"));
639 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim));
640 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name));
641 ccode.open_for (cforinit, cforcond, cforiter);
643 CCodeExpression element_variant;
644 if (dim < array_type.rank) {
645 element_variant = serialize_array_dim (array_type, dim + 1, array_expr, array_iter_expr);
646 } else {
647 var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
648 element_variant = serialize_expression (array_type.element_type, element_expr);
651 var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
652 builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
653 builder_add.add_argument (element_variant);
654 ccode.add_expression (builder_add);
656 if (dim == array_type.rank) {
657 var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
658 ccode.add_expression (array_iter_incr);
661 ccode.close ();
663 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
664 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
665 return builder_end;
668 CCodeExpression serialize_buffer_array (ArrayType array_type, CCodeExpression array_expr) {
669 string buffer_name = "_tmp%d_".printf (next_temp_var_id++);
671 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
672 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (array_type))));
674 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
675 dup_call.add_argument (array_expr);
676 dup_call.add_argument (get_array_length (array_expr, 1));
677 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (buffer_name, dup_call));
679 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_from_data"));
680 new_call.add_argument (gvariant_type);
681 new_call.add_argument (new CCodeIdentifier (buffer_name));
682 new_call.add_argument (get_array_length (array_expr, 1));
683 new_call.add_argument (new CCodeConstant ("TRUE"));
684 new_call.add_argument (new CCodeIdentifier ("g_free"));
685 new_call.add_argument (new CCodeIdentifier (buffer_name));
687 return new_call;
690 CCodeExpression? serialize_struct (Struct st, CCodeExpression struct_expr) {
691 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
693 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
695 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
696 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
697 iter_call.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
698 ccode.add_expression (iter_call);
700 bool field_found = false;;
702 foreach (Field f in st.get_fields ()) {
703 if (f.binding != MemberBinding.INSTANCE) {
704 continue;
707 field_found = true;
709 write_expression (f.variable_type, new CCodeIdentifier (builder_name), new CCodeMemberAccess (struct_expr, get_ccode_name (f)), f);
712 if (!field_found) {
713 return null;
716 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
717 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
718 return builder_end;
721 CCodeExpression? serialize_hash_table (ObjectType type, CCodeExpression hash_table_expr) {
722 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
723 string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
724 string key_name = "_tmp%d_".printf (next_temp_var_id++);
725 string value_name = "_tmp%d_".printf (next_temp_var_id++);
727 var type_args = type.get_type_arguments ();
728 assert (type_args.size == 2);
729 var key_type = type_args.get (0);
730 var value_type = type_args.get (1);
732 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (subiter_name));
733 ccode.add_declaration ("GHashTableIter", new CCodeVariableDeclarator (tableiter_name));
734 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (key_name));
735 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (value_name));
737 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
738 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
739 iter_init_call.add_argument (hash_table_expr);
740 ccode.add_expression (iter_init_call);
742 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
743 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (type))));
745 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
746 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
747 iter_call.add_argument (gvariant_type);
748 ccode.add_expression (iter_call);
750 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
751 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
752 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
753 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
755 ccode.open_while (iter_next_call);
757 ccode.add_declaration (get_ccode_name (key_type), new CCodeVariableDeclarator ("_key"));
758 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("_value"));
760 ccode.add_assignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type));
761 ccode.add_assignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type));
763 var serialized_key = serialize_expression (key_type, new CCodeIdentifier ("_key"));
764 var serialized_value = serialize_expression (value_type, new CCodeIdentifier ("_value"));
765 if (serialized_key == null || serialized_value == null) {
766 return null;
769 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add"));
770 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
771 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
772 iter_call.add_argument (serialized_key);
773 iter_call.add_argument (serialized_value);
774 ccode.add_expression (iter_call);
776 ccode.close ();
778 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
779 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
780 return iter_call;
783 public override CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
784 BasicTypeInfo basic_type;
785 CCodeExpression result = null;
786 if (is_string_marshalled_enum (type.data_type)) {
787 get_basic_type_info ("s", out basic_type);
788 result = generate_enum_value_to_string (type as EnumValueType, expr);
789 result = serialize_basic (basic_type, result);
790 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
791 result = serialize_basic (basic_type, expr);
792 } else if (type is ArrayType) {
793 result = serialize_array ((ArrayType) type, expr);
794 } else if (type.data_type is Struct) {
795 var st_expr = expr;
796 if (type.nullable) {
797 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
799 result = serialize_struct ((Struct) type.data_type, st_expr);
800 } else if (type is ObjectType) {
801 if (type.data_type.get_full_name () == "GLib.Variant") {
802 var variant_new = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_variant"));
803 variant_new.add_argument (expr);
804 result = variant_new;
805 } else if (type.data_type.get_full_name () == "GLib.HashTable") {
806 result = serialize_hash_table ((ObjectType) type, expr);
810 if (result == null) {
811 Report.error (type.source_reference, "GVariant serialization of type `%s' is not supported".printf (type.to_string ()));
814 return result;
817 public void write_expression (DataType type, CCodeExpression builder_expr, CCodeExpression expr, Symbol? sym) {
818 var variant_expr = expr;
819 if (sym == null || get_dbus_signature (sym) == null) {
820 // perform boxing
821 variant_expr = serialize_expression (type, expr);
823 if (variant_expr != null) {
824 var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
825 builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, builder_expr));
826 builder_add.add_argument (variant_expr);
827 ccode.add_expression (builder_add);