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
20 * Jürg Billeter <j@bitron.ch>
23 public class Vala.GVariantModule : GValueModule {
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");
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) {
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 if (signature != null) {
66 foreach (BasicTypeInfo info in basic_types) {
67 if (info.signature == signature) {
73 basic_type = BasicTypeInfo ();
77 public override void visit_enum (Enum en) {
80 if (is_string_marshalled_enum (en)) {
82 cfile.add_include ("string.h");
85 cfile.add_include ("gio/gio.h");
87 cfile.add_function (generate_enum_from_string_function (en));
88 cfile.add_function (generate_enum_to_string_function (en));
92 public override bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
93 if (base.generate_enum_declaration (en, decl_space)) {
94 if (is_string_marshalled_enum (en)) {
95 decl_space.add_function_declaration (generate_enum_from_string_function_declaration (en));
96 decl_space.add_function_declaration (generate_enum_to_string_function_declaration (en));
103 int next_variant_function_id = 0;
105 public override void visit_cast_expression (CastExpression expr) {
106 var value = expr.inner.target_value;
107 var target_type = expr.type_reference;
109 if (expr.is_non_null_cast || value.value_type == null || gvariant_type == null || value.value_type.type_symbol != gvariant_type) {
110 base.visit_cast_expression (expr);
114 generate_type_declaration (expr.type_reference, cfile);
116 string variant_func = "_variant_get%d".printf (++next_variant_function_id);
119 if (value.value_type.value_owned) {
120 // value leaked, destroy it
121 var temp_value = store_temp_value (value, expr);
122 temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
123 variant = temp_value;
126 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
127 ccall.add_argument (get_cvalue_ (variant));
129 var needs_init = (target_type is ArrayType);
130 var result = create_temp_value (target_type, needs_init, expr);
132 var cfunc = new CCodeFunction (variant_func);
133 cfunc.modifiers = CCodeModifiers.STATIC;
134 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
136 if (!target_type.is_real_non_null_struct_type ()) {
137 cfunc.return_type = get_ccode_name (target_type);
140 if (target_type.is_real_non_null_struct_type ()) {
141 // structs are returned via out parameter
142 cfunc.add_parameter (new CCodeParameter ("result", "%s *".printf (get_ccode_name (target_type))));
143 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (result)));
144 } else if (target_type is ArrayType) {
145 // return array length if appropriate
146 // tmp = _variant_get (variant, &tmp_length);
147 unowned ArrayType array_type = (ArrayType) target_type;
148 var length_ctype = get_ccode_array_length_type (array_type);
149 for (int dim = 1; dim <= array_type.rank; dim++) {
150 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (result, dim)));
151 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), length_ctype + "*"));
155 if (!target_type.is_real_non_null_struct_type ()) {
156 ccode.add_assignment (get_cvalue_ (result), ccall);
158 ccode.add_expression (ccall);
161 push_context (new EmitContext ());
162 push_function (cfunc);
164 CCodeExpression type_expr = null;
165 BasicTypeInfo basic_type = {};
166 bool is_basic_type = false;
167 if (expr.is_silent_cast) {
168 var signature = target_type.get_type_signature ();
169 is_basic_type = get_basic_type_info (signature, out basic_type);
170 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_is_of_type"));
171 ccheck.add_argument (new CCodeIdentifier ("value"));
173 type_expr = new CCodeIdentifier ("G_VARIANT_TYPE_" + basic_type.type_name.ascii_up ());
175 var gvariant_type_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("VariantType"));
176 var type_temp = get_temp_variable (gvariant_type_type, true, expr, true);
177 emit_temp_var (type_temp);
178 type_expr = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_type_new"));
179 ((CCodeFunctionCall) type_expr).add_argument (new CCodeIdentifier ("\"%s\"".printf (signature)));
180 store_value (get_local_cvalue (type_temp), new GLibValue (gvariant_type_type, type_expr), expr.source_reference);
181 type_expr = get_variable_cexpression (type_temp.name);
183 ccheck.add_argument (type_expr);
184 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("value"), ccheck));
187 CCodeExpression func_result = deserialize_expression (target_type, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
189 if (expr.is_silent_cast) {
190 if (is_basic_type && basic_type.is_string) {
191 ccode.add_return (func_result);
193 if (!is_basic_type) {
194 var type_free = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_type_free"));
195 type_free.add_argument (type_expr);
196 ccode.add_expression (type_free);
198 var temp_type = expr.target_type.copy ();
199 if (!expr.target_type.is_real_struct_type ()) {
200 temp_type.nullable = false;
202 var temp_value = create_temp_value (temp_type, false, expr);
203 store_value (temp_value, new GLibValue (temp_type, func_result), expr.source_reference);
204 ccode.add_return (get_cvalue_ (transform_value (temp_value, expr.target_type, expr)));
207 if (!is_basic_type) {
208 var type_free = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_type_free"));
209 type_free.add_argument (type_expr);
210 ccode.add_expression (type_free);
212 ccode.add_return (new CCodeConstant ("NULL"));
214 } else if (target_type.is_real_non_null_struct_type ()) {
215 ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
217 ccode.add_return (func_result);
223 cfile.add_function_declaration (cfunc);
224 cfile.add_function (cfunc);
226 expr.target_value = load_temp_value (result);
229 CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
230 var id = expr as CCodeIdentifier;
231 var ma = expr as CCodeMemberAccess;
233 return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
234 } else if (ma != null) {
236 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
238 return new CCodeMemberAccess (ma.inner, "%s_length%d".printf (ma.member_name, dim));
241 // must be NULL-terminated
242 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
243 len_call.add_argument (expr);
248 CCodeExpression? generate_enum_value_from_string (EnumValueType type, CCodeExpression? expr, CCodeExpression? error_expr) {
249 var en = type.type_symbol as Enum;
250 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
252 var from_string_call = new CCodeFunctionCall (new CCodeIdentifier (from_string_name));
253 from_string_call.add_argument (expr);
254 from_string_call.add_argument (error_expr != null ? error_expr : new CCodeConstant ("NULL"));
256 return from_string_call;
259 public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
260 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
262 var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
263 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
264 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
265 from_string_func.modifiers |= CCodeModifiers.EXTERN;
266 requires_vala_extern = true;
268 return from_string_func;
271 public CCodeFunction generate_enum_from_string_function (Enum en) {
272 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
274 var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
275 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
276 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
278 push_function (from_string_func);
280 ccode.add_declaration (get_ccode_name (en), new CCodeVariableDeclarator.zero ("value", new CCodeConstant ("0")));
283 foreach (EnumValue enum_value in en.get_values ()) {
284 string dbus_value = get_dbus_value (enum_value, enum_value.name);
285 var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
286 string_comparison.add_argument (new CCodeIdentifier ("str"));
287 string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
288 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0"));
290 ccode.open_if (cond);
293 ccode.else_if (cond);
295 ccode.add_assignment (new CCodeIdentifier ("value"), new CCodeIdentifier (get_ccode_name (enum_value)));
299 var set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
300 set_error.add_argument (new CCodeIdentifier ("error"));
301 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR"));
302 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR_INVALID_ARGS"));
303 set_error.add_argument (new CCodeConstant ("\"Invalid value for enum `%s'\"".printf (get_ccode_name (en))));
304 ccode.add_expression (set_error);
307 ccode.add_return (new CCodeIdentifier ("value"));
310 return from_string_func;
313 CCodeExpression deserialize_basic (BasicTypeInfo basic_type, CCodeExpression variant_expr, bool transfer = false) {
314 var get_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_" + basic_type.type_name));
315 get_call.add_argument (variant_expr);
317 if (basic_type.is_string) {
319 get_call.call = new CCodeIdentifier ("g_variant_get_string");
321 get_call.call = new CCodeIdentifier ("g_variant_dup_string");
323 get_call.add_argument (new CCodeConstant ("NULL"));
329 CCodeExpression deserialize_array (ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
330 if (array_type.rank == 1 && array_type.get_type_signature () == "ay") {
331 return deserialize_buffer_array (array_type, variant_expr, expr);
334 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
336 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
337 new_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
338 // add one extra element for NULL-termination
339 new_call.add_argument (new CCodeConstant ("5"));
341 var length_ctype = get_ccode_array_length_type (array_type);
342 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (temp_name, new_call));
343 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
344 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
346 deserialize_array_dim (array_type, 1, temp_name, variant_expr, expr);
348 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
349 // NULL terminate array
350 var length = new CCodeIdentifier (temp_name + "_length");
351 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
352 ccode.add_assignment (element_access, new CCodeConstant ("NULL"));
355 return new CCodeIdentifier (temp_name);
358 void deserialize_array_dim (ArrayType array_type, int dim, string temp_name, CCodeExpression variant_expr, CCodeExpression? expr) {
359 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
360 string element_name = "_tmp%d_".printf (next_temp_var_id++);
362 ccode.add_declaration (get_ccode_array_length_type (array_type), new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
363 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
364 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (element_name));
366 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
367 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
368 iter_call.add_argument (variant_expr);
369 ccode.add_expression (iter_call);
371 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
372 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
374 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeAssignment (new CCodeIdentifier (element_name), iter_call), new CCodeConstant ("NULL"));
375 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
376 ccode.open_for (null, cforcond, cforiter);
378 if (dim < array_type.rank) {
379 deserialize_array_dim (array_type, dim + 1, temp_name, new CCodeIdentifier (element_name), expr);
381 var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
383 ccode.open_if (size_check);
385 // tmp_size = (2 * tmp_size);
386 var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
387 ccode.add_assignment (new CCodeIdentifier (temp_name + "_size"), new_size);
389 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
390 renew_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
391 renew_call.add_argument (new CCodeIdentifier (temp_name));
392 // add one extra element for NULL-termination
393 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
394 ccode.add_assignment (new CCodeIdentifier (temp_name), renew_call);
398 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
399 var element_expr = deserialize_expression (array_type.element_type, new CCodeIdentifier (element_name), null);
400 ccode.add_assignment (element_access, element_expr);
403 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
404 unref.add_argument (new CCodeIdentifier (element_name));
405 ccode.add_expression (unref);
410 ccode.add_assignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
414 CCodeExpression deserialize_buffer_array (ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
415 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
417 var get_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_data"));
418 get_data_call.add_argument (variant_expr);
420 var get_size_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_size"));
421 get_size_call.add_argument (variant_expr);
422 ccode.add_declaration ("gsize", new CCodeVariableDeclarator (temp_name + "_length", get_size_call));
423 var length = new CCodeIdentifier (temp_name + "_length");
425 CCodeFunctionCall dup_call;
426 if (context.require_glib_version (2, 68)) {
427 dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
429 requires_memdup2 = true;
430 dup_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
432 dup_call.add_argument (get_data_call);
433 dup_call.add_argument (length);
435 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (temp_name, dup_call));
437 ccode.add_assignment (get_array_length (expr, 1), length);
440 return new CCodeIdentifier (temp_name);
443 CCodeExpression? deserialize_struct (Struct st, CCodeExpression variant_expr) {
444 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
445 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
447 ccode.add_declaration (get_ccode_name (st), new CCodeVariableDeclarator (temp_name));
448 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
450 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
451 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
452 iter_call.add_argument (variant_expr);
453 ccode.add_expression (iter_call);
455 bool field_found = false;;
457 foreach (Field f in st.get_fields ()) {
458 if (f.binding != MemberBinding.INSTANCE) {
464 read_expression (f.variable_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), get_ccode_name (f)), f);
471 return new CCodeIdentifier (temp_name);
474 CCodeExpression? deserialize_hash_table (ObjectType type, CCodeExpression variant_expr) {
475 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
476 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
477 string key_name = "_tmp%d_".printf (next_temp_var_id++);
478 string value_name = "_tmp%d_".printf (next_temp_var_id++);
480 var type_args = type.get_type_arguments ();
481 if (type_args.size != 2) {
482 Report.error (type.source_reference, "Missing type-arguments for GVariant deserialization of `%s'", type.type_symbol.get_full_name ());
483 return new CCodeInvalidExpression ();
485 var key_type = type_args.get (0);
486 var value_type = type_args.get (1);
488 ccode.add_declaration ("GHashTable*", new CCodeVariableDeclarator (temp_name));
489 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
490 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (key_name));
491 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (value_name));
493 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
494 if (key_type.type_symbol.is_subtype_of (string_type.type_symbol)) {
495 hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
496 hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
497 } else if (key_type.type_symbol == gvariant_type) {
498 hash_table_new.add_argument (new CCodeIdentifier ("g_variant_hash"));
499 hash_table_new.add_argument (new CCodeIdentifier ("g_variant_equal"));
501 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
502 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
505 if (key_type.type_symbol.is_subtype_of (string_type.type_symbol)) {
506 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
507 } else if (key_type.type_symbol == gvariant_type) {
508 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
509 } else if (key_type.type_symbol.get_full_name () == "GLib.HashTable") {
510 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
512 hash_table_new.add_argument (new CCodeConstant ("NULL"));
515 if (value_type.type_symbol.is_subtype_of (string_type.type_symbol)) {
516 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
517 } else if (value_type.type_symbol == gvariant_type) {
518 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
519 } else if (value_type.type_symbol.get_full_name () == "GLib.HashTable") {
520 hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
522 hash_table_new.add_argument (new CCodeConstant ("NULL"));
524 ccode.add_assignment (new CCodeIdentifier (temp_name), hash_table_new);
526 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
527 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
528 iter_call.add_argument (variant_expr);
529 ccode.add_expression (iter_call);
531 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_loop"));
532 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
533 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
534 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
535 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
537 ccode.open_while (iter_call);
539 var key_expr = deserialize_expression (key_type, new CCodeIdentifier (key_name), null);
540 var value_expr = deserialize_expression (value_type, new CCodeIdentifier (value_name), null);
541 if (key_expr == null || value_expr == null) {
545 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
546 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
547 hash_table_insert.add_argument (convert_to_generic_pointer (key_expr, key_type));
548 hash_table_insert.add_argument (convert_to_generic_pointer (value_expr, value_type));
549 ccode.add_expression (hash_table_insert);
553 return new CCodeIdentifier (temp_name);
556 public override CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
557 BasicTypeInfo basic_type;
558 CCodeExpression result = null;
560 if (is_string_marshalled_enum (type.type_symbol)) {
561 get_basic_type_info ("s", out basic_type);
562 result = deserialize_basic (basic_type, variant_expr, true);
563 result = generate_enum_value_from_string (type as EnumValueType, result, error_expr);
565 } else if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
566 result = deserialize_basic (basic_type, variant_expr);
567 } else if (type is ArrayType) {
568 result = deserialize_array ((ArrayType) type, variant_expr, expr);
569 } else if (type.type_symbol is Struct) {
570 unowned Struct st = (Struct) type.type_symbol;
571 result = deserialize_struct (st, variant_expr);
572 if (result != null && type.nullable) {
573 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
574 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (st)));
575 CCodeFunctionCall cdup;
576 if (context.require_glib_version (2, 68)) {
577 cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
579 requires_memdup2 = true;
580 cdup = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
582 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
583 cdup.add_argument (csizeof);
586 } else if (type is ObjectType) {
587 if (type.type_symbol.get_full_name () == "GLib.Variant") {
588 var variant_get = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_variant"));
589 variant_get.add_argument (variant_expr);
590 result = variant_get;
591 } else if (type.type_symbol.get_full_name () == "GLib.HashTable") {
592 result = deserialize_hash_table ((ObjectType) type, variant_expr);
596 if (result == null) {
597 Report.error (type.source_reference, "GVariant deserialization of type `%s' is not supported", type.to_string ());
598 return new CCodeInvalidExpression ();
604 public void read_expression (DataType type, CCodeExpression iter_expr, CCodeExpression target_expr, Symbol? sym, CCodeExpression? error_expr = null, out bool may_fail = null) {
605 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
606 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
608 if (sym != null && get_dbus_signature (sym) != null) {
610 ccode.add_assignment (target_expr, iter_call);
615 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
617 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (temp_name));
619 var variant_expr = new CCodeIdentifier (temp_name);
621 ccode.add_assignment (variant_expr, iter_call);
623 var result = deserialize_expression (type, variant_expr, target_expr, error_expr, out may_fail);
624 if (result == null) {
625 // error already reported
629 ccode.add_assignment (target_expr, result);
631 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
632 unref.add_argument (variant_expr);
633 ccode.add_expression (unref);
636 CCodeExpression? generate_enum_value_to_string (EnumValueType type, CCodeExpression? expr) {
637 var en = type.type_symbol as Enum;
638 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
640 var to_string_call = new CCodeFunctionCall (new CCodeIdentifier (to_string_name));
641 to_string_call.add_argument (expr);
643 return to_string_call;
646 public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
647 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
649 var to_string_func = new CCodeFunction (to_string_name, "const char*");
650 to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
651 to_string_func.modifiers |= CCodeModifiers.EXTERN;
652 requires_vala_extern = true;
654 return to_string_func;
657 public CCodeFunction generate_enum_to_string_function (Enum en) {
658 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
660 var to_string_func = new CCodeFunction (to_string_name, "const char*");
661 to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
663 push_function (to_string_func);
665 ccode.add_declaration ("const char *", new CCodeVariableDeclarator ("str"));
667 ccode.open_switch (new CCodeIdentifier ("value"));
668 foreach (EnumValue enum_value in en.get_values ()) {
669 string dbus_value = get_dbus_value (enum_value, enum_value.name);
670 ccode.add_case (new CCodeIdentifier (get_ccode_name (enum_value)));
671 ccode.add_assignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)));
677 ccode.add_return (new CCodeIdentifier ("str"));
680 return to_string_func;
683 CCodeExpression? serialize_basic (BasicTypeInfo basic_type, CCodeExpression expr) {
684 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_" + basic_type.type_name));
685 new_call.add_argument (expr);
689 CCodeExpression? serialize_array (ArrayType array_type, CCodeExpression array_expr) {
690 if (array_type.rank == 1 && array_type.get_type_signature () == "ay") {
691 return serialize_buffer_array (array_type, array_expr);
694 string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
696 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (array_iter_name));
697 ccode.add_assignment (new CCodeIdentifier (array_iter_name), array_expr);
699 return serialize_array_dim (array_type, 1, array_expr, new CCodeIdentifier (array_iter_name));
702 CCodeExpression? serialize_array_dim (ArrayType array_type, int dim, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
703 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
704 string index_name = "_tmp%d_".printf (next_temp_var_id++);
706 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
707 ccode.add_declaration (get_ccode_array_length_type (array_type), new CCodeVariableDeclarator (index_name));
709 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
710 ArrayType array_type_copy = (ArrayType) array_type.copy ();
711 array_type_copy.rank -= dim - 1;
712 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (array_type_copy.get_type_signature ())));
714 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
715 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
716 builder_init.add_argument (gvariant_type);
717 ccode.add_expression (builder_init);
719 var cforinit = new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0"));
720 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim));
721 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name));
722 ccode.open_for (cforinit, cforcond, cforiter);
724 CCodeExpression element_variant;
725 if (dim < array_type.rank) {
726 element_variant = serialize_array_dim (array_type, dim + 1, array_expr, array_iter_expr);
728 var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
729 element_variant = serialize_expression (array_type.element_type, element_expr);
732 var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
733 builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
734 builder_add.add_argument (element_variant);
735 ccode.add_expression (builder_add);
737 if (dim == array_type.rank) {
738 var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
739 ccode.add_expression (array_iter_incr);
744 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
745 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
749 CCodeExpression serialize_buffer_array (ArrayType array_type, CCodeExpression array_expr) {
750 string buffer_name = "_tmp%d_".printf (next_temp_var_id++);
752 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
753 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (array_type.get_type_signature ())));
755 CCodeFunctionCall dup_call;
756 if (context.require_glib_version (2, 68)) {
757 dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
759 requires_memdup2 = true;
760 dup_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
762 dup_call.add_argument (array_expr);
763 dup_call.add_argument (get_array_length (array_expr, 1));
764 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (buffer_name, dup_call));
766 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_from_data"));
767 new_call.add_argument (gvariant_type);
768 new_call.add_argument (new CCodeIdentifier (buffer_name));
769 new_call.add_argument (get_array_length (array_expr, 1));
770 new_call.add_argument (new CCodeConstant ("TRUE"));
771 new_call.add_argument (new CCodeIdentifier ("g_free"));
772 new_call.add_argument (new CCodeIdentifier (buffer_name));
777 CCodeExpression? serialize_struct (Struct st, CCodeExpression struct_expr) {
778 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
780 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
782 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
783 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
784 iter_call.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
785 ccode.add_expression (iter_call);
787 bool field_found = false;;
789 foreach (Field f in st.get_fields ()) {
790 if (f.binding != MemberBinding.INSTANCE) {
796 write_expression (f.variable_type, new CCodeIdentifier (builder_name), new CCodeMemberAccess (struct_expr, get_ccode_name (f)), f);
803 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
804 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
808 CCodeExpression? serialize_hash_table (ObjectType type, CCodeExpression hash_table_expr) {
809 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
810 string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
811 string key_name = "_tmp%d_".printf (next_temp_var_id++);
812 string value_name = "_tmp%d_".printf (next_temp_var_id++);
814 var type_args = type.get_type_arguments ();
815 if (type_args.size != 2) {
816 Report.error (type.source_reference, "Missing type-arguments for GVariant serialization of `%s'", type.type_symbol.get_full_name ());
817 return new CCodeInvalidExpression ();
819 var key_type = type_args.get (0);
820 var value_type = type_args.get (1);
822 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (subiter_name));
823 ccode.add_declaration ("GHashTableIter", new CCodeVariableDeclarator (tableiter_name));
824 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (key_name));
825 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (value_name));
827 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
828 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
829 iter_init_call.add_argument (hash_table_expr);
830 ccode.add_expression (iter_init_call);
832 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
833 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (type.get_type_signature ())));
835 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
836 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
837 iter_call.add_argument (gvariant_type);
838 ccode.add_expression (iter_call);
840 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
841 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
842 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
843 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
845 ccode.open_while (iter_next_call);
847 ccode.add_declaration (get_ccode_name (key_type), new CCodeVariableDeclarator ("_key"));
848 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("_value"));
850 ccode.add_assignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type));
851 ccode.add_assignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type));
853 var serialized_key = serialize_expression (key_type, new CCodeIdentifier ("_key"));
854 var serialized_value = serialize_expression (value_type, new CCodeIdentifier ("_value"));
855 if (serialized_key == null || serialized_value == null) {
859 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add"));
860 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
861 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
862 iter_call.add_argument (serialized_key);
863 iter_call.add_argument (serialized_value);
864 ccode.add_expression (iter_call);
868 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
869 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
873 public override CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
874 BasicTypeInfo basic_type;
875 CCodeExpression result = null;
876 if (is_string_marshalled_enum (type.type_symbol)) {
877 get_basic_type_info ("s", out basic_type);
878 result = generate_enum_value_to_string (type as EnumValueType, expr);
879 result = serialize_basic (basic_type, result);
880 } else if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
881 result = serialize_basic (basic_type, expr);
882 } else if (type is ArrayType) {
883 result = serialize_array ((ArrayType) type, expr);
884 } else if (type.type_symbol is Struct) {
887 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
889 result = serialize_struct ((Struct) type.type_symbol, st_expr);
890 } else if (type is ObjectType) {
891 if (type.type_symbol.get_full_name () == "GLib.Variant") {
892 var variant_new = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_variant"));
893 variant_new.add_argument (expr);
894 result = variant_new;
895 } else if (type.type_symbol.get_full_name () == "GLib.HashTable") {
896 result = serialize_hash_table ((ObjectType) type, expr);
900 if (result == null) {
901 Report.error (type.source_reference, "GVariant serialization of type `%s' is not supported", type.to_string ());
902 return new CCodeInvalidExpression ();
908 public void write_expression (DataType type, CCodeExpression builder_expr, CCodeExpression expr, Symbol? sym) {
909 var variant_expr = expr;
910 if (sym == null || get_dbus_signature (sym) == null) {
912 variant_expr = serialize_expression (type, expr);
914 if (variant_expr != null) {
915 var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
916 builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, builder_expr));
917 builder_add.add_argument (variant_expr);
918 ccode.add_expression (builder_add);