codegen: Add get_field_cvalue and load_field
[vala-lang.git] / codegen / valagvariantmodule.vala
blob6e87eb06aafcdcef1eb6d78e031bea01a8a87412
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 var dbus = symbol.get_attribute ("DBus");
48 return dbus != null && dbus.get_bool ("use_string_marshalling");
50 return false;
53 string get_dbus_value (EnumValue value, string default_value) {
54 var dbus = value.get_attribute ("DBus");
55 if (dbus == null) {
56 return default_value;
59 string dbus_value = dbus.get_string ("value");
60 if (dbus_value == null) {
61 return default_value;
63 return dbus_value;
66 public static string? get_dbus_signature (Symbol symbol) {
67 var dbus = symbol.get_attribute ("DBus");
68 if (dbus == null) {
69 return null;
72 return dbus.get_string ("signature");
75 bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
76 foreach (BasicTypeInfo info in basic_types) {
77 if (info.signature == signature) {
78 basic_type = info;
79 return true;
82 return false;
85 public static string? get_type_signature (DataType datatype, Symbol? symbol = null) {
86 if (symbol != null) {
87 string sig = get_dbus_signature (symbol);
88 if (sig != null) {
89 // allow overriding signature in attribute, used for raw GVariants
90 return sig;
94 var array_type = datatype as ArrayType;
96 if (array_type != null) {
97 string element_type_signature = get_type_signature (array_type.element_type);
99 if (element_type_signature == null) {
100 return null;
103 return string.nfill (array_type.rank, 'a') + element_type_signature;
104 } else if (is_string_marshalled_enum (datatype.data_type)) {
105 return "s";
106 } else if (datatype.data_type != null) {
107 string sig = null;
109 var ccode = datatype.data_type.get_attribute ("CCode");
110 if (ccode != null) {
111 sig = ccode.get_string ("type_signature");
114 var st = datatype.data_type as Struct;
115 var en = datatype.data_type as Enum;
116 if (sig == null && st != null) {
117 var str = new StringBuilder ();
118 str.append_c ('(');
119 foreach (Field f in st.get_fields ()) {
120 if (f.binding == MemberBinding.INSTANCE) {
121 str.append (get_type_signature (f.variable_type));
124 str.append_c (')');
125 sig = str.str;
126 } else if (sig == null && en != null) {
127 if (en.is_flags) {
128 return "u";
129 } else {
130 return "i";
134 var type_args = datatype.get_type_arguments ();
135 if (sig != null && "%s" in sig && type_args.size > 0) {
136 string element_sig = "";
137 foreach (DataType type_arg in type_args) {
138 var s = get_type_signature (type_arg);
139 if (s != null) {
140 element_sig += s;
144 sig = sig.printf (element_sig);
147 if (sig == null &&
148 (datatype.data_type.get_full_name () == "GLib.UnixInputStream" ||
149 datatype.data_type.get_full_name () == "GLib.UnixOutputStream" ||
150 datatype.data_type.get_full_name () == "GLib.Socket")) {
151 return "h";
154 return sig;
155 } else {
156 return null;
160 public override void visit_enum (Enum en) {
161 base.visit_enum (en);
163 if (is_string_marshalled_enum (en)) {
164 // strcmp
165 cfile.add_include ("string.h");
167 cfile.add_function (generate_enum_from_string_function (en));
168 cfile.add_function (generate_enum_to_string_function (en));
172 public override bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
173 if (base.generate_enum_declaration (en, decl_space)) {
174 if (is_string_marshalled_enum (en)) {
175 decl_space.add_function_declaration (generate_enum_from_string_function_declaration (en));
176 decl_space.add_function_declaration (generate_enum_to_string_function_declaration (en));
178 return true;
180 return false;
183 CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
184 var id = expr as CCodeIdentifier;
185 var ma = expr as CCodeMemberAccess;
186 if (id != null) {
187 return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
188 } else if (ma != null) {
189 if (ma.is_pointer) {
190 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
191 } else {
192 return new CCodeMemberAccess (ma.inner, "%s_length%d".printf (ma.member_name, dim));
194 } else {
195 // must be NULL-terminated
196 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
197 len_call.add_argument (expr);
198 return len_call;
202 CCodeExpression? generate_enum_value_from_string (EnumValueType type, CCodeExpression? expr, CCodeExpression? error_expr) {
203 var en = type.type_symbol as Enum;
204 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
206 var from_string_call = new CCodeFunctionCall (new CCodeIdentifier (from_string_name));
207 from_string_call.add_argument (expr);
208 from_string_call.add_argument (error_expr != null ? error_expr : new CCodeConstant ("NULL"));
210 return from_string_call;
213 public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
214 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
216 var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
217 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
218 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
220 return from_string_func;
223 public CCodeFunction generate_enum_from_string_function (Enum en) {
224 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
226 var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
227 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
228 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
230 var from_string_block = new CCodeBlock ();
231 from_string_func.block = from_string_block;
233 var cdecl = new CCodeDeclaration (en.get_cname ());
234 cdecl.add_declarator (new CCodeVariableDeclarator.zero ("value", new CCodeConstant ("0")));
235 from_string_block.add_statement (cdecl);
237 CCodeStatement if_else_if = null;
238 CCodeIfStatement last_statement = null;
239 foreach (EnumValue enum_value in en.get_values ()) {
240 var true_block = new CCodeBlock ();
241 true_block.suppress_newline = true;
242 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("value"), new CCodeIdentifier (enum_value.get_cname ()))));
244 string dbus_value = get_dbus_value (enum_value, enum_value.name);
245 var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
246 string_comparison.add_argument (new CCodeIdentifier ("str"));
247 string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
248 var stmt = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0")), true_block);
250 if (last_statement != null) {
251 last_statement.false_statement = stmt;
252 } else {
253 if_else_if = stmt;
255 last_statement = stmt;
258 var set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
259 set_error.add_argument (new CCodeIdentifier ("error"));
260 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR"));
261 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR_INVALID_ARGS"));
262 set_error.add_argument (new CCodeConstant ("\"Invalid value for enum `%s'\"".printf (en.get_cname ())));
263 var error_block = new CCodeBlock ();
264 error_block.add_statement (new CCodeExpressionStatement (set_error));
265 last_statement.false_statement = error_block;
267 from_string_block.add_statement (if_else_if);
269 from_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
271 return from_string_func;
274 CCodeExpression deserialize_basic (BasicTypeInfo basic_type, CCodeExpression variant_expr, bool transfer = false) {
275 var get_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_" + basic_type.type_name));
276 get_call.add_argument (variant_expr);
278 if (basic_type.is_string) {
279 if (transfer) {
280 get_call.call = new CCodeIdentifier ("g_variant_get_string");
281 } else {
282 get_call.call = new CCodeIdentifier ("g_variant_dup_string");
284 get_call.add_argument (new CCodeConstant ("NULL"));
287 return get_call;
290 CCodeExpression deserialize_array (ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
291 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
293 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
294 new_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
295 // add one extra element for NULL-termination
296 new_call.add_argument (new CCodeConstant ("5"));
298 ccode.add_declaration (array_type.get_cname (), new CCodeVariableDeclarator (temp_name, new_call));
299 ccode.add_declaration ("int", new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
300 ccode.add_declaration ("int", new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
302 deserialize_array_dim (array_type, 1, temp_name, variant_expr, expr);
304 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
305 // NULL terminate array
306 var length = new CCodeIdentifier (temp_name + "_length");
307 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
308 ccode.add_assignment (element_access, new CCodeIdentifier ("NULL"));
311 return new CCodeIdentifier (temp_name);
314 void deserialize_array_dim (ArrayType array_type, int dim, string temp_name, CCodeExpression variant_expr, CCodeExpression? expr) {
315 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
316 string element_name = "_tmp%d_".printf (next_temp_var_id++);
318 ccode.add_declaration ("int", new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
319 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
320 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (element_name));
322 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
323 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
324 iter_call.add_argument (variant_expr);
325 ccode.add_expression (iter_call);
327 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
328 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
330 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeAssignment (new CCodeIdentifier (element_name), iter_call), new CCodeConstant ("NULL"));
331 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
332 ccode.open_for (null, cforcond, cforiter);
334 if (dim < array_type.rank) {
335 deserialize_array_dim (array_type, dim + 1, temp_name, new CCodeIdentifier (element_name), expr);
336 } else {
337 var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
339 ccode.open_if (size_check);
341 // tmp_size = (2 * tmp_size);
342 var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
343 ccode.add_assignment (new CCodeIdentifier (temp_name + "_size"), new_size);
345 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
346 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
347 renew_call.add_argument (new CCodeIdentifier (temp_name));
348 // add one extra element for NULL-termination
349 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
350 ccode.add_assignment (new CCodeIdentifier (temp_name), renew_call);
352 ccode.close ();
354 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
355 var element_expr = deserialize_expression (array_type.element_type, new CCodeIdentifier (element_name), null);
356 ccode.add_assignment (element_access, element_expr);
359 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
360 unref.add_argument (new CCodeIdentifier (element_name));
361 ccode.add_expression (unref);
363 ccode.close ();
365 if (expr != null) {
366 ccode.add_assignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
370 CCodeExpression? deserialize_struct (Struct st, CCodeExpression variant_expr) {
371 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
372 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
374 ccode.add_declaration (st.get_cname (), new CCodeVariableDeclarator (temp_name));
375 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
377 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
378 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
379 iter_call.add_argument (variant_expr);
380 ccode.add_expression (iter_call);
382 bool field_found = false;;
384 foreach (Field f in st.get_fields ()) {
385 if (f.binding != MemberBinding.INSTANCE) {
386 continue;
389 field_found = true;
391 read_expression (f.variable_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()), f);
394 if (!field_found) {
395 return null;
398 return new CCodeIdentifier (temp_name);
401 CCodeExpression? deserialize_hash_table (ObjectType type, CCodeExpression variant_expr) {
402 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
403 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
404 string key_name = "_tmp%d_".printf (next_temp_var_id++);
405 string value_name = "_tmp%d_".printf (next_temp_var_id++);
407 var type_args = type.get_type_arguments ();
408 assert (type_args.size == 2);
409 var key_type = type_args.get (0);
410 var value_type = type_args.get (1);
412 ccode.add_declaration ("GHashTable*", new CCodeVariableDeclarator (temp_name));
413 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
414 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (key_name));
415 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (value_name));
417 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
418 if (key_type.data_type == string_type.data_type) {
419 hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
420 hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
421 } else {
422 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
423 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
425 if (key_type.data_type == string_type.data_type) {
426 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
427 } else {
428 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
430 if (value_type.data_type == string_type.data_type) {
431 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
432 } else {
433 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
435 ccode.add_assignment (new CCodeIdentifier (temp_name), hash_table_new);
437 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
438 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
439 iter_call.add_argument (variant_expr);
440 ccode.add_expression (iter_call);
442 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_loop"));
443 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
444 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
445 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
446 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
448 ccode.open_while (iter_call);
450 var key_expr = deserialize_expression (key_type, new CCodeIdentifier (key_name), null);
451 var value_expr = deserialize_expression (value_type, new CCodeIdentifier (value_name), null);
452 if (key_expr == null || value_expr == null) {
453 return null;
456 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
457 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
458 hash_table_insert.add_argument (convert_to_generic_pointer (key_expr, key_type));
459 hash_table_insert.add_argument (convert_to_generic_pointer (value_expr, value_type));
460 ccode.add_expression (hash_table_insert);
462 ccode.close ();
464 return new CCodeIdentifier (temp_name);
467 public override CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
468 BasicTypeInfo basic_type;
469 CCodeExpression result = null;
470 if (is_string_marshalled_enum (type.data_type)) {
471 get_basic_type_info ("s", out basic_type);
472 result = deserialize_basic (basic_type, variant_expr, true);
473 result = generate_enum_value_from_string (type as EnumValueType, result, error_expr);
474 may_fail = true;
475 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
476 result = deserialize_basic (basic_type, variant_expr);
477 } else if (type is ArrayType) {
478 result = deserialize_array ((ArrayType) type, variant_expr, expr);
479 } else if (type.data_type is Struct) {
480 var st = (Struct) type.data_type;
481 result = deserialize_struct (st, variant_expr);
482 if (result != null && type.nullable) {
483 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
484 csizeof.add_argument (new CCodeIdentifier (st.get_cname ()));
485 var cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
486 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
487 cdup.add_argument (csizeof);
488 result = cdup;
490 } else if (type is ObjectType) {
491 if (type.data_type.get_full_name () == "GLib.Variant") {
492 var variant_get = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_variant"));
493 variant_get.add_argument (variant_expr);
494 result = variant_get;
495 } else if (type.data_type.get_full_name () == "GLib.HashTable") {
496 result = deserialize_hash_table ((ObjectType) type, variant_expr);
500 if (result == null) {
501 Report.error (type.source_reference, "GVariant deserialization of type `%s' is not supported".printf (type.to_string ()));
504 return result;
507 public void read_expression (DataType type, CCodeExpression iter_expr, CCodeExpression target_expr, Symbol? sym, CCodeExpression? error_expr = null, out bool may_fail = null) {
508 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
509 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
511 if (sym != null && get_dbus_signature (sym) != null) {
512 // raw GVariant
513 ccode.add_assignment (target_expr, iter_call);
514 return;
517 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
519 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (temp_name));
521 var variant_expr = new CCodeIdentifier (temp_name);
523 ccode.add_assignment (variant_expr, iter_call);
525 var result = deserialize_expression (type, variant_expr, target_expr, error_expr, out may_fail);
526 if (result == null) {
527 // error already reported
528 return;
531 ccode.add_assignment (target_expr, result);
533 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
534 unref.add_argument (variant_expr);
535 ccode.add_expression (unref);
538 CCodeExpression? generate_enum_value_to_string (EnumValueType type, CCodeExpression? expr) {
539 var en = type.type_symbol as Enum;
540 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
542 var to_string_call = new CCodeFunctionCall (new CCodeIdentifier (to_string_name));
543 to_string_call.add_argument (expr);
545 return to_string_call;
548 public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
549 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
551 var to_string_func = new CCodeFunction (to_string_name, "const char*");
552 to_string_func.add_parameter (new CCodeParameter ("value", en.get_cname ()));
554 return to_string_func;
557 public CCodeFunction generate_enum_to_string_function (Enum en) {
558 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
560 var to_string_func = new CCodeFunction (to_string_name, "const char*");
561 to_string_func.add_parameter (new CCodeParameter ("value", en.get_cname ()));
563 var to_string_block = new CCodeBlock ();
564 to_string_func.block = to_string_block;
566 var cdecl = new CCodeDeclaration ("const char *");
567 cdecl.add_declarator (new CCodeVariableDeclarator ("str"));
568 to_string_block.add_statement (cdecl);
570 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("value"));
571 foreach (EnumValue enum_value in en.get_values ()) {
572 string dbus_value = get_dbus_value (enum_value, enum_value.name);
573 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value.get_cname ())));
574 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)))));
575 cswitch.add_statement (new CCodeBreakStatement ());
577 to_string_block.add_statement (cswitch);
579 to_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("str")));
581 return to_string_func;
584 CCodeExpression? serialize_basic (BasicTypeInfo basic_type, CCodeExpression expr) {
585 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_" + basic_type.type_name));
586 new_call.add_argument (expr);
587 return new_call;
590 CCodeExpression? serialize_array (ArrayType array_type, CCodeExpression array_expr) {
591 string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
593 ccode.add_declaration (array_type.get_cname (), new CCodeVariableDeclarator (array_iter_name));
594 ccode.add_assignment (new CCodeIdentifier (array_iter_name), array_expr);
596 return serialize_array_dim (array_type, 1, array_expr, new CCodeIdentifier (array_iter_name));
599 CCodeExpression? serialize_array_dim (ArrayType array_type, int dim, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
600 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
601 string index_name = "_tmp%d_".printf (next_temp_var_id++);
603 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
604 ccode.add_declaration ("int", new CCodeVariableDeclarator (index_name));
606 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
607 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (array_type))));
609 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
610 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
611 builder_init.add_argument (gvariant_type);
612 ccode.add_expression (builder_init);
614 var cforinit = new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0"));
615 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim));
616 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name));
617 ccode.open_for (cforinit, cforcond, cforiter);
619 CCodeExpression element_variant;
620 if (dim < array_type.rank) {
621 element_variant = serialize_array_dim (array_type, dim + 1, array_expr, array_iter_expr);
622 } else {
623 var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
624 element_variant = serialize_expression (array_type.element_type, element_expr);
627 var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
628 builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
629 builder_add.add_argument (element_variant);
630 ccode.add_expression (builder_add);
632 if (dim == array_type.rank) {
633 var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
634 ccode.add_expression (array_iter_incr);
637 ccode.close ();
639 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
640 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
641 return builder_end;
644 CCodeExpression? serialize_struct (Struct st, CCodeExpression struct_expr) {
645 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
647 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
649 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
650 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
651 iter_call.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
652 ccode.add_expression (iter_call);
654 bool field_found = false;;
656 foreach (Field f in st.get_fields ()) {
657 if (f.binding != MemberBinding.INSTANCE) {
658 continue;
661 field_found = true;
663 write_expression (f.variable_type, new CCodeIdentifier (builder_name), new CCodeMemberAccess (struct_expr, f.get_cname ()), f);
666 if (!field_found) {
667 return null;
670 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
671 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
672 return builder_end;
675 CCodeExpression? serialize_hash_table (ObjectType type, CCodeExpression hash_table_expr) {
676 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
677 string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
678 string key_name = "_tmp%d_".printf (next_temp_var_id++);
679 string value_name = "_tmp%d_".printf (next_temp_var_id++);
681 var type_args = type.get_type_arguments ();
682 assert (type_args.size == 2);
683 var key_type = type_args.get (0);
684 var value_type = type_args.get (1);
686 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (subiter_name));
687 ccode.add_declaration ("GHashTableIter", new CCodeVariableDeclarator (tableiter_name));
688 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (key_name));
689 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (value_name));
691 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
692 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
693 iter_init_call.add_argument (hash_table_expr);
694 ccode.add_expression (iter_init_call);
696 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
697 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (type))));
699 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
700 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
701 iter_call.add_argument (gvariant_type);
702 ccode.add_expression (iter_call);
704 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
705 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
706 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
707 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
709 ccode.open_while (iter_next_call);
711 ccode.add_declaration (key_type.get_cname (), new CCodeVariableDeclarator ("_key"));
712 ccode.add_declaration (value_type.get_cname (), new CCodeVariableDeclarator ("_value"));
714 ccode.add_assignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type));
715 ccode.add_assignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type));
717 var serialized_key = serialize_expression (key_type, new CCodeIdentifier ("_key"));
718 var serialized_value = serialize_expression (value_type, new CCodeIdentifier ("_value"));
719 if (serialized_key == null || serialized_value == null) {
720 return null;
723 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add"));
724 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
725 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
726 iter_call.add_argument (serialized_key);
727 iter_call.add_argument (serialized_value);
728 ccode.add_expression (iter_call);
730 ccode.close ();
732 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
733 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
734 return iter_call;
737 public override CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
738 BasicTypeInfo basic_type;
739 CCodeExpression result = null;
740 if (is_string_marshalled_enum (type.data_type)) {
741 get_basic_type_info ("s", out basic_type);
742 result = generate_enum_value_to_string (type as EnumValueType, expr);
743 result = serialize_basic (basic_type, result);
744 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
745 result = serialize_basic (basic_type, expr);
746 } else if (type is ArrayType) {
747 result = serialize_array ((ArrayType) type, expr);
748 } else if (type.data_type is Struct) {
749 var st_expr = expr;
750 if (type.nullable) {
751 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
753 result = serialize_struct ((Struct) type.data_type, st_expr);
754 } else if (type is ObjectType) {
755 if (type.data_type.get_full_name () == "GLib.Variant") {
756 var variant_new = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_variant"));
757 variant_new.add_argument (expr);
758 result = variant_new;
759 } else if (type.data_type.get_full_name () == "GLib.HashTable") {
760 result = serialize_hash_table ((ObjectType) type, expr);
764 if (result == null) {
765 Report.error (type.source_reference, "GVariant serialization of type `%s' is not supported".printf (type.to_string ()));
768 return result;
771 public void write_expression (DataType type, CCodeExpression builder_expr, CCodeExpression expr, Symbol? sym) {
772 var variant_expr = expr;
773 if (sym == null || get_dbus_signature (sym) == null) {
774 // perform boxing
775 variant_expr = serialize_expression (type, expr);
777 if (variant_expr != null) {
778 var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
779 builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, builder_expr));
780 builder_add.add_argument (variant_expr);
781 ccode.add_expression (builder_add);