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
: 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");
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 static string?
get_type_signature (DataType datatype
, Symbol? symbol
= null) {
79 string sig
= get_dbus_signature (symbol
);
81 // allow overriding signature in attribute, used for raw GVariants
86 var array_type
= datatype as ArrayType
;
88 if (array_type
!= null) {
89 string element_type_signature
= get_type_signature (array_type
.element_type
);
91 if (element_type_signature
== null) {
95 return string.nfill (array_type
.rank
, 'a') + element_type_signature
;
96 } else if (is_string_marshalled_enum (datatype
.data_type
)) {
98 } else if (datatype
.data_type
!= null) {
99 string sig
= datatype
.data_type
.get_attribute_string ("CCode", "type_signature");
101 var st
= datatype
.data_type as Struct
;
102 var en
= datatype
.data_type as Enum
;
103 if (sig
== null && st
!= null) {
104 var str
= new
StringBuilder ();
106 foreach (Field f
in st
.get_fields ()) {
107 if (f
.binding
== MemberBinding
.INSTANCE
) {
108 str
.append (get_type_signature (f
.variable_type
, f
));
113 } else if (sig
== null && en
!= null) {
121 var type_args
= datatype
.get_type_arguments ();
122 if (sig
!= null && "%s" in sig
&& type_args
.size
> 0) {
123 string element_sig
= "";
124 foreach (DataType type_arg
in type_args
) {
125 var s
= get_type_signature (type_arg
);
131 sig
= sig
.replace ("%s", element_sig
);
135 (datatype
.data_type
.get_full_name () == "GLib.UnixInputStream" ||
136 datatype
.data_type
.get_full_name () == "GLib.UnixOutputStream" ||
137 datatype
.data_type
.get_full_name () == "GLib.Socket")) {
147 public override void visit_enum (Enum en
) {
148 base.visit_enum (en
);
150 if (is_string_marshalled_enum (en
)) {
152 cfile
.add_include ("string.h");
155 cfile
.add_include ("gio/gio.h");
157 cfile
.add_function (generate_enum_from_string_function (en
));
158 cfile
.add_function (generate_enum_to_string_function (en
));
162 public override bool generate_enum_declaration (Enum en
, CCodeFile decl_space
) {
163 if (base.generate_enum_declaration (en
, decl_space
)) {
164 if (is_string_marshalled_enum (en
)) {
165 decl_space
.add_function_declaration (generate_enum_from_string_function_declaration (en
));
166 decl_space
.add_function_declaration (generate_enum_to_string_function_declaration (en
));
173 CCodeExpression?
get_array_length (CCodeExpression expr
, int dim
) {
174 var id
= expr as CCodeIdentifier
;
175 var ma
= expr as CCodeMemberAccess
;
177 return new
CCodeIdentifier ("%s_length%d".printf (id
.name
, dim
));
178 } else if (ma
!= null) {
180 return new CCodeMemberAccess
.pointer (ma
.inner
, "%s_length%d".printf (ma
.member_name
, dim
));
182 return new
CCodeMemberAccess (ma
.inner
, "%s_length%d".printf (ma
.member_name
, dim
));
185 // must be NULL-terminated
186 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
187 len_call
.add_argument (expr
);
192 CCodeExpression?
generate_enum_value_from_string (EnumValueType type
, CCodeExpression? expr
, CCodeExpression? error_expr
) {
193 var en
= type
.type_symbol as Enum
;
194 var from_string_name
= "%s_from_string".printf (get_ccode_lower_case_name (en
, null));
196 var from_string_call
= new
CCodeFunctionCall (new
CCodeIdentifier (from_string_name
));
197 from_string_call
.add_argument (expr
);
198 from_string_call
.add_argument (error_expr
!= null ? error_expr
: new
CCodeConstant ("NULL"));
200 return from_string_call
;
203 public CCodeFunction
generate_enum_from_string_function_declaration (Enum en
) {
204 var from_string_name
= "%s_from_string".printf (get_ccode_lower_case_name (en
, null));
206 var from_string_func
= new
CCodeFunction (from_string_name
, get_ccode_name (en
));
207 from_string_func
.add_parameter (new
CCodeParameter ("str", "const char*"));
208 from_string_func
.add_parameter (new
CCodeParameter ("error", "GError**"));
210 return from_string_func
;
213 public CCodeFunction
generate_enum_from_string_function (Enum en
) {
214 var from_string_name
= "%s_from_string".printf (get_ccode_lower_case_name (en
, null));
216 var from_string_func
= new
CCodeFunction (from_string_name
, get_ccode_name (en
));
217 from_string_func
.add_parameter (new
CCodeParameter ("str", "const char*"));
218 from_string_func
.add_parameter (new
CCodeParameter ("error", "GError**"));
220 push_function (from_string_func
);
222 ccode
.add_declaration (get_ccode_name (en
), new CCodeVariableDeclarator
.zero ("value", new
CCodeConstant ("0")));
225 foreach (EnumValue enum_value
in en
.get_values ()) {
226 string dbus_value
= get_dbus_value (enum_value
, enum_value
.name
);
227 var string_comparison
= new
CCodeFunctionCall (new
CCodeIdentifier ("strcmp"));
228 string_comparison
.add_argument (new
CCodeIdentifier ("str"));
229 string_comparison
.add_argument (new
CCodeConstant ("\"%s\"".printf (dbus_value
)));
230 var cond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, string_comparison
, new
CCodeConstant ("0"));
232 ccode
.open_if (cond
);
235 ccode
.else_if (cond
);
237 ccode
.add_assignment (new
CCodeIdentifier ("value"), new
CCodeIdentifier (get_ccode_name (enum_value
)));
241 var set_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_set_error"));
242 set_error
.add_argument (new
CCodeIdentifier ("error"));
243 set_error
.add_argument (new
CCodeIdentifier ("G_DBUS_ERROR"));
244 set_error
.add_argument (new
CCodeIdentifier ("G_DBUS_ERROR_INVALID_ARGS"));
245 set_error
.add_argument (new
CCodeConstant ("\"Invalid value for enum `%s'\"".printf (get_ccode_name (en
))));
246 ccode
.add_expression (set_error
);
249 ccode
.add_return (new
CCodeIdentifier ("value"));
252 return from_string_func
;
255 CCodeExpression
deserialize_basic (BasicTypeInfo basic_type
, CCodeExpression variant_expr
, bool transfer
= false) {
256 var get_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_get_" + basic_type
.type_name
));
257 get_call
.add_argument (variant_expr
);
259 if (basic_type
.is_string
) {
261 get_call
.call
= new
CCodeIdentifier ("g_variant_get_string");
263 get_call
.call
= new
CCodeIdentifier ("g_variant_dup_string");
265 get_call
.add_argument (new
CCodeConstant ("NULL"));
271 CCodeExpression
deserialize_array (ArrayType array_type
, CCodeExpression variant_expr
, CCodeExpression? expr
) {
272 if (array_type
.rank
== 1 && get_type_signature (array_type
) == "ay") {
273 return deserialize_buffer_array (array_type
, variant_expr
, expr
);
276 string temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
278 var new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new"));
279 new_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
280 // add one extra element for NULL-termination
281 new_call
.add_argument (new
CCodeConstant ("5"));
283 ccode
.add_declaration (get_ccode_name (array_type
), new
CCodeVariableDeclarator (temp_name
, new_call
));
284 ccode
.add_declaration ("int", new
CCodeVariableDeclarator (temp_name
+ "_length", new
CCodeConstant ("0")));
285 ccode
.add_declaration ("int", new
CCodeVariableDeclarator (temp_name
+ "_size", new
CCodeConstant ("4")));
287 deserialize_array_dim (array_type
, 1, temp_name
, variant_expr
, expr
);
289 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
290 // NULL terminate array
291 var length
= new
CCodeIdentifier (temp_name
+ "_length");
292 var element_access
= new
CCodeElementAccess (new
CCodeIdentifier (temp_name
), length
);
293 ccode
.add_assignment (element_access
, new
CCodeIdentifier ("NULL"));
296 return new
CCodeIdentifier (temp_name
);
299 void deserialize_array_dim (ArrayType array_type
, int dim
, string temp_name
, CCodeExpression variant_expr
, CCodeExpression? expr
) {
300 string subiter_name
= "_tmp%d_".printf (next_temp_var_id
++);
301 string element_name
= "_tmp%d_".printf (next_temp_var_id
++);
303 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("%s_length%d".printf (temp_name
, dim
), new
CCodeConstant ("0")));
304 ccode
.add_declaration ("GVariantIter", new
CCodeVariableDeclarator (subiter_name
));
305 ccode
.add_declaration ("GVariant*", new
CCodeVariableDeclarator (element_name
));
307 var iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_iter_init"));
308 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
309 iter_call
.add_argument (variant_expr
);
310 ccode
.add_expression (iter_call
);
312 iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_iter_next_value"));
313 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
315 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeAssignment (new
CCodeIdentifier (element_name
), iter_call
), new
CCodeConstant ("NULL"));
316 var cforiter
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("%s_length%d".printf (temp_name
, dim
)));
317 ccode
.open_for (null, cforcond
, cforiter
);
319 if (dim
< array_type
.rank
) {
320 deserialize_array_dim (array_type
, dim
+ 1, temp_name
, new
CCodeIdentifier (element_name
), expr
);
322 var size_check
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier (temp_name
+ "_size"), new
CCodeIdentifier (temp_name
+ "_length"));
324 ccode
.open_if (size_check
);
326 // tmp_size = (2 * tmp_size);
327 var new_size
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("2"), new
CCodeIdentifier (temp_name
+ "_size"));
328 ccode
.add_assignment (new
CCodeIdentifier (temp_name
+ "_size"), new_size
);
330 var renew_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_renew"));
331 renew_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
332 renew_call
.add_argument (new
CCodeIdentifier (temp_name
));
333 // add one extra element for NULL-termination
334 renew_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier (temp_name
+ "_size"), new
CCodeConstant ("1")));
335 ccode
.add_assignment (new
CCodeIdentifier (temp_name
), renew_call
);
339 var element_access
= new
CCodeElementAccess (new
CCodeIdentifier (temp_name
), new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier (temp_name
+ "_length")));
340 var element_expr
= deserialize_expression (array_type
.element_type
, new
CCodeIdentifier (element_name
), null);
341 ccode
.add_assignment (element_access
, element_expr
);
344 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_unref"));
345 unref
.add_argument (new
CCodeIdentifier (element_name
));
346 ccode
.add_expression (unref
);
351 ccode
.add_assignment (get_array_length (expr
, dim
), new
CCodeIdentifier ("%s_length%d".printf (temp_name
, dim
)));
355 CCodeExpression
deserialize_buffer_array (ArrayType array_type
, CCodeExpression variant_expr
, CCodeExpression? expr
) {
356 string temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
358 var get_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_get_data"));
359 get_data_call
.add_argument (variant_expr
);
361 var get_size_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_get_size"));
362 get_size_call
.add_argument (variant_expr
);
363 ccode
.add_declaration ("gsize", new
CCodeVariableDeclarator (temp_name
+ "_length", get_size_call
));
364 var length
= new
CCodeIdentifier (temp_name
+ "_length");
366 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
367 dup_call
.add_argument (get_data_call
);
368 dup_call
.add_argument (length
);
370 ccode
.add_declaration (get_ccode_name (array_type
), new
CCodeVariableDeclarator (temp_name
, dup_call
));
372 ccode
.add_assignment (get_array_length (expr
, 1), length
);
375 return new
CCodeIdentifier (temp_name
);
378 CCodeExpression?
deserialize_struct (Struct st
, CCodeExpression variant_expr
) {
379 string temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
380 string subiter_name
= "_tmp%d_".printf (next_temp_var_id
++);
382 ccode
.add_declaration (get_ccode_name (st
), new
CCodeVariableDeclarator (temp_name
));
383 ccode
.add_declaration ("GVariantIter", new
CCodeVariableDeclarator (subiter_name
));
385 var iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_iter_init"));
386 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
387 iter_call
.add_argument (variant_expr
);
388 ccode
.add_expression (iter_call
);
390 bool field_found
= false;;
392 foreach (Field f
in st
.get_fields ()) {
393 if (f
.binding
!= MemberBinding
.INSTANCE
) {
399 read_expression (f
.variable_type
, new
CCodeIdentifier (subiter_name
), new
CCodeMemberAccess (new
CCodeIdentifier (temp_name
), get_ccode_name (f
)), f
);
406 return new
CCodeIdentifier (temp_name
);
409 CCodeExpression?
deserialize_hash_table (ObjectType type
, CCodeExpression variant_expr
) {
410 string temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
411 string subiter_name
= "_tmp%d_".printf (next_temp_var_id
++);
412 string key_name
= "_tmp%d_".printf (next_temp_var_id
++);
413 string value_name
= "_tmp%d_".printf (next_temp_var_id
++);
415 var type_args
= type
.get_type_arguments ();
416 assert (type_args
.size
== 2);
417 var key_type
= type_args
.get (0);
418 var value_type
= type_args
.get (1);
420 ccode
.add_declaration ("GHashTable*", new
CCodeVariableDeclarator (temp_name
));
421 ccode
.add_declaration ("GVariantIter", new
CCodeVariableDeclarator (subiter_name
));
422 ccode
.add_declaration ("GVariant*", new
CCodeVariableDeclarator (key_name
));
423 ccode
.add_declaration ("GVariant*", new
CCodeVariableDeclarator (value_name
));
425 var hash_table_new
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_hash_table_new_full"));
426 if (key_type
.data_type
.is_subtype_of (string_type
.data_type
)) {
427 hash_table_new
.add_argument (new
CCodeIdentifier ("g_str_hash"));
428 hash_table_new
.add_argument (new
CCodeIdentifier ("g_str_equal"));
429 } else if (key_type
.data_type
== gvariant_type
) {
430 hash_table_new
.add_argument (new
CCodeIdentifier ("g_variant_hash"));
431 hash_table_new
.add_argument (new
CCodeIdentifier ("g_variant_equal"));
433 hash_table_new
.add_argument (new
CCodeIdentifier ("g_direct_hash"));
434 hash_table_new
.add_argument (new
CCodeIdentifier ("g_direct_equal"));
437 if (key_type
.data_type
.is_subtype_of (string_type
.data_type
)) {
438 hash_table_new
.add_argument (new
CCodeIdentifier ("g_free"));
439 } else if (key_type
.data_type
== gvariant_type
) {
440 hash_table_new
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
441 } else if (key_type
.data_type
.get_full_name () == "GLib.HashTable") {
442 hash_table_new
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
444 hash_table_new
.add_argument (new
CCodeIdentifier ("NULL"));
447 if (value_type
.data_type
.is_subtype_of (string_type
.data_type
)) {
448 hash_table_new
.add_argument (new
CCodeIdentifier ("g_free"));
449 } else if (value_type
.data_type
== gvariant_type
) {
450 hash_table_new
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
451 } else if (value_type
.data_type
.get_full_name () == "GLib.HashTable") {
452 hash_table_new
.add_argument (new
CCodeCastExpression (new
CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
454 hash_table_new
.add_argument (new
CCodeIdentifier ("NULL"));
456 ccode
.add_assignment (new
CCodeIdentifier (temp_name
), hash_table_new
);
458 var iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_iter_init"));
459 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
460 iter_call
.add_argument (variant_expr
);
461 ccode
.add_expression (iter_call
);
463 iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_iter_loop"));
464 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
465 iter_call
.add_argument (new
CCodeConstant ("\"{?*}\""));
466 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (key_name
)));
467 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (value_name
)));
469 ccode
.open_while (iter_call
);
471 var key_expr
= deserialize_expression (key_type
, new
CCodeIdentifier (key_name
), null);
472 var value_expr
= deserialize_expression (value_type
, new
CCodeIdentifier (value_name
), null);
473 if (key_expr
== null || value_expr
== null) {
477 var hash_table_insert
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_hash_table_insert"));
478 hash_table_insert
.add_argument (new
CCodeIdentifier (temp_name
));
479 hash_table_insert
.add_argument (convert_to_generic_pointer (key_expr
, key_type
));
480 hash_table_insert
.add_argument (convert_to_generic_pointer (value_expr
, value_type
));
481 ccode
.add_expression (hash_table_insert
);
485 return new
CCodeIdentifier (temp_name
);
488 public override CCodeExpression?
deserialize_expression (DataType type
, CCodeExpression variant_expr
, CCodeExpression? expr
, CCodeExpression? error_expr
= null, out bool may_fail
= null) {
489 BasicTypeInfo basic_type
;
490 CCodeExpression result
= null;
492 if (is_string_marshalled_enum (type
.data_type
)) {
493 get_basic_type_info ("s", out basic_type
);
494 result
= deserialize_basic (basic_type
, variant_expr
, true);
495 result
= generate_enum_value_from_string (type as EnumValueType
, result
, error_expr
);
497 } else if (get_basic_type_info (get_type_signature (type
), out basic_type
)) {
498 result
= deserialize_basic (basic_type
, variant_expr
);
499 } else if (type is ArrayType
) {
500 result
= deserialize_array ((ArrayType
) type
, variant_expr
, expr
);
501 } else if (type
.data_type is Struct
) {
502 var st
= (Struct
) type
.data_type
;
503 result
= deserialize_struct (st
, variant_expr
);
504 if (result
!= null && type
.nullable
) {
505 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
506 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (st
)));
507 var cdup
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
508 cdup
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, result
));
509 cdup
.add_argument (csizeof
);
512 } else if (type is ObjectType
) {
513 if (type
.data_type
.get_full_name () == "GLib.Variant") {
514 var variant_get
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_get_variant"));
515 variant_get
.add_argument (variant_expr
);
516 result
= variant_get
;
517 } else if (type
.data_type
.get_full_name () == "GLib.HashTable") {
518 result
= deserialize_hash_table ((ObjectType
) type
, variant_expr
);
522 if (result
== null) {
523 Report
.error (type
.source_reference
, "GVariant deserialization of type `%s' is not supported".printf (type
.to_string ()));
529 public void read_expression (DataType type
, CCodeExpression iter_expr
, CCodeExpression target_expr
, Symbol? sym
, CCodeExpression? error_expr
= null, out bool may_fail
= null) {
530 var iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_iter_next_value"));
531 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, iter_expr
));
533 if (sym
!= null && get_dbus_signature (sym
) != null) {
535 ccode
.add_assignment (target_expr
, iter_call
);
540 string temp_name
= "_tmp%d_".printf (next_temp_var_id
++);
542 ccode
.add_declaration ("GVariant*", new
CCodeVariableDeclarator (temp_name
));
544 var variant_expr
= new
CCodeIdentifier (temp_name
);
546 ccode
.add_assignment (variant_expr
, iter_call
);
548 var result
= deserialize_expression (type
, variant_expr
, target_expr
, error_expr
, out may_fail
);
549 if (result
== null) {
550 // error already reported
554 ccode
.add_assignment (target_expr
, result
);
556 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_unref"));
557 unref
.add_argument (variant_expr
);
558 ccode
.add_expression (unref
);
561 CCodeExpression?
generate_enum_value_to_string (EnumValueType type
, CCodeExpression? expr
) {
562 var en
= type
.type_symbol as Enum
;
563 var to_string_name
= "%s_to_string".printf (get_ccode_lower_case_name (en
, null));
565 var to_string_call
= new
CCodeFunctionCall (new
CCodeIdentifier (to_string_name
));
566 to_string_call
.add_argument (expr
);
568 return to_string_call
;
571 public CCodeFunction
generate_enum_to_string_function_declaration (Enum en
) {
572 var to_string_name
= "%s_to_string".printf (get_ccode_lower_case_name (en
, null));
574 var to_string_func
= new
CCodeFunction (to_string_name
, "const char*");
575 to_string_func
.add_parameter (new
CCodeParameter ("value", get_ccode_name (en
)));
577 return to_string_func
;
580 public CCodeFunction
generate_enum_to_string_function (Enum en
) {
581 var to_string_name
= "%s_to_string".printf (get_ccode_lower_case_name (en
, null));
583 var to_string_func
= new
CCodeFunction (to_string_name
, "const char*");
584 to_string_func
.add_parameter (new
CCodeParameter ("value", get_ccode_name (en
)));
586 push_function (to_string_func
);
588 ccode
.add_declaration ("const char *", new
CCodeVariableDeclarator ("str"));
590 ccode
.open_switch (new
CCodeIdentifier ("value"));
591 foreach (EnumValue enum_value
in en
.get_values ()) {
592 string dbus_value
= get_dbus_value (enum_value
, enum_value
.name
);
593 ccode
.add_case (new
CCodeIdentifier (get_ccode_name (enum_value
)));
594 ccode
.add_assignment (new
CCodeIdentifier ("str"), new
CCodeConstant ("\"%s\"".printf (dbus_value
)));
600 ccode
.add_return (new
CCodeIdentifier ("str"));
603 return to_string_func
;
606 CCodeExpression?
serialize_basic (BasicTypeInfo basic_type
, CCodeExpression expr
) {
607 var new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_new_" + basic_type
.type_name
));
608 new_call
.add_argument (expr
);
612 CCodeExpression?
serialize_array (ArrayType array_type
, CCodeExpression array_expr
) {
613 if (array_type
.rank
== 1 && get_type_signature (array_type
) == "ay") {
614 return serialize_buffer_array (array_type
, array_expr
);
617 string array_iter_name
= "_tmp%d_".printf (next_temp_var_id
++);
619 ccode
.add_declaration (get_ccode_name (array_type
), new
CCodeVariableDeclarator (array_iter_name
));
620 ccode
.add_assignment (new
CCodeIdentifier (array_iter_name
), array_expr
);
622 return serialize_array_dim (array_type
, 1, array_expr
, new
CCodeIdentifier (array_iter_name
));
625 CCodeExpression?
serialize_array_dim (ArrayType array_type
, int dim
, CCodeExpression array_expr
, CCodeExpression array_iter_expr
) {
626 string builder_name
= "_tmp%d_".printf (next_temp_var_id
++);
627 string index_name
= "_tmp%d_".printf (next_temp_var_id
++);
629 ccode
.add_declaration ("GVariantBuilder", new
CCodeVariableDeclarator (builder_name
));
630 ccode
.add_declaration ("int", new
CCodeVariableDeclarator (index_name
));
632 var gvariant_type
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VARIANT_TYPE"));
633 ArrayType array_type_copy
= (ArrayType
) array_type
.copy ();
634 array_type_copy
.rank
-= dim
- 1;
635 gvariant_type
.add_argument (new
CCodeConstant ("\"%s\"".printf (get_type_signature (array_type_copy
))));
637 var builder_init
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_init"));
638 builder_init
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (builder_name
)));
639 builder_init
.add_argument (gvariant_type
);
640 ccode
.add_expression (builder_init
);
642 var cforinit
= new
CCodeAssignment (new
CCodeIdentifier (index_name
), new
CCodeConstant ("0"));
643 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier (index_name
), get_array_length (array_expr
, dim
));
644 var cforiter
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier (index_name
));
645 ccode
.open_for (cforinit
, cforcond
, cforiter
);
647 CCodeExpression element_variant
;
648 if (dim
< array_type
.rank
) {
649 element_variant
= serialize_array_dim (array_type
, dim
+ 1, array_expr
, array_iter_expr
);
651 var element_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, array_iter_expr
);
652 element_variant
= serialize_expression (array_type
.element_type
, element_expr
);
655 var builder_add
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_add_value"));
656 builder_add
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (builder_name
)));
657 builder_add
.add_argument (element_variant
);
658 ccode
.add_expression (builder_add
);
660 if (dim
== array_type
.rank
) {
661 var array_iter_incr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, array_iter_expr
);
662 ccode
.add_expression (array_iter_incr
);
667 var builder_end
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_end"));
668 builder_end
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (builder_name
)));
672 CCodeExpression
serialize_buffer_array (ArrayType array_type
, CCodeExpression array_expr
) {
673 string buffer_name
= "_tmp%d_".printf (next_temp_var_id
++);
675 var gvariant_type
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VARIANT_TYPE"));
676 gvariant_type
.add_argument (new
CCodeConstant ("\"%s\"".printf (get_type_signature (array_type
))));
678 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
679 dup_call
.add_argument (array_expr
);
680 dup_call
.add_argument (get_array_length (array_expr
, 1));
681 ccode
.add_declaration (get_ccode_name (array_type
), new
CCodeVariableDeclarator (buffer_name
, dup_call
));
683 var new_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_new_from_data"));
684 new_call
.add_argument (gvariant_type
);
685 new_call
.add_argument (new
CCodeIdentifier (buffer_name
));
686 new_call
.add_argument (get_array_length (array_expr
, 1));
687 new_call
.add_argument (new
CCodeConstant ("TRUE"));
688 new_call
.add_argument (new
CCodeIdentifier ("g_free"));
689 new_call
.add_argument (new
CCodeIdentifier (buffer_name
));
694 CCodeExpression?
serialize_struct (Struct st
, CCodeExpression struct_expr
) {
695 string builder_name
= "_tmp%d_".printf (next_temp_var_id
++);
697 ccode
.add_declaration ("GVariantBuilder", new
CCodeVariableDeclarator (builder_name
));
699 var iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_init"));
700 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (builder_name
)));
701 iter_call
.add_argument (new
CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
702 ccode
.add_expression (iter_call
);
704 bool field_found
= false;;
706 foreach (Field f
in st
.get_fields ()) {
707 if (f
.binding
!= MemberBinding
.INSTANCE
) {
713 write_expression (f
.variable_type
, new
CCodeIdentifier (builder_name
), new
CCodeMemberAccess (struct_expr
, get_ccode_name (f
)), f
);
720 var builder_end
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_end"));
721 builder_end
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (builder_name
)));
725 CCodeExpression?
serialize_hash_table (ObjectType type
, CCodeExpression hash_table_expr
) {
726 string subiter_name
= "_tmp%d_".printf (next_temp_var_id
++);
727 string tableiter_name
= "_tmp%d_".printf (next_temp_var_id
++);
728 string key_name
= "_tmp%d_".printf (next_temp_var_id
++);
729 string value_name
= "_tmp%d_".printf (next_temp_var_id
++);
731 var type_args
= type
.get_type_arguments ();
732 assert (type_args
.size
== 2);
733 var key_type
= type_args
.get (0);
734 var value_type
= type_args
.get (1);
736 ccode
.add_declaration ("GVariantBuilder", new
CCodeVariableDeclarator (subiter_name
));
737 ccode
.add_declaration ("GHashTableIter", new
CCodeVariableDeclarator (tableiter_name
));
738 ccode
.add_declaration ("gpointer", new
CCodeVariableDeclarator (key_name
));
739 ccode
.add_declaration ("gpointer", new
CCodeVariableDeclarator (value_name
));
741 var iter_init_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_hash_table_iter_init"));
742 iter_init_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (tableiter_name
)));
743 iter_init_call
.add_argument (hash_table_expr
);
744 ccode
.add_expression (iter_init_call
);
746 var gvariant_type
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_VARIANT_TYPE"));
747 gvariant_type
.add_argument (new
CCodeConstant ("\"%s\"".printf (get_type_signature (type
))));
749 var iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_init"));
750 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
751 iter_call
.add_argument (gvariant_type
);
752 ccode
.add_expression (iter_call
);
754 var iter_next_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_hash_table_iter_next"));
755 iter_next_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (tableiter_name
)));
756 iter_next_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (key_name
)));
757 iter_next_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (value_name
)));
759 ccode
.open_while (iter_next_call
);
761 ccode
.add_declaration (get_ccode_name (key_type
), new
CCodeVariableDeclarator ("_key"));
762 ccode
.add_declaration (get_ccode_name (value_type
), new
CCodeVariableDeclarator ("_value"));
764 ccode
.add_assignment (new
CCodeIdentifier ("_key"), convert_from_generic_pointer (new
CCodeIdentifier (key_name
), key_type
));
765 ccode
.add_assignment (new
CCodeIdentifier ("_value"), convert_from_generic_pointer (new
CCodeIdentifier (value_name
), value_type
));
767 var serialized_key
= serialize_expression (key_type
, new
CCodeIdentifier ("_key"));
768 var serialized_value
= serialize_expression (value_type
, new
CCodeIdentifier ("_value"));
769 if (serialized_key
== null || serialized_value
== null) {
773 iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_add"));
774 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
775 iter_call
.add_argument (new
CCodeConstant ("\"{?*}\""));
776 iter_call
.add_argument (serialized_key
);
777 iter_call
.add_argument (serialized_value
);
778 ccode
.add_expression (iter_call
);
782 iter_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_end"));
783 iter_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (subiter_name
)));
787 public override CCodeExpression?
serialize_expression (DataType type
, CCodeExpression expr
) {
788 BasicTypeInfo basic_type
;
789 CCodeExpression result
= null;
790 if (is_string_marshalled_enum (type
.data_type
)) {
791 get_basic_type_info ("s", out basic_type
);
792 result
= generate_enum_value_to_string (type as EnumValueType
, expr
);
793 result
= serialize_basic (basic_type
, result
);
794 } else if (get_basic_type_info (get_type_signature (type
), out basic_type
)) {
795 result
= serialize_basic (basic_type
, expr
);
796 } else if (type is ArrayType
) {
797 result
= serialize_array ((ArrayType
) type
, expr
);
798 } else if (type
.data_type is Struct
) {
801 st_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, st_expr
);
803 result
= serialize_struct ((Struct
) type
.data_type
, st_expr
);
804 } else if (type is ObjectType
) {
805 if (type
.data_type
.get_full_name () == "GLib.Variant") {
806 var variant_new
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_new_variant"));
807 variant_new
.add_argument (expr
);
808 result
= variant_new
;
809 } else if (type
.data_type
.get_full_name () == "GLib.HashTable") {
810 result
= serialize_hash_table ((ObjectType
) type
, expr
);
814 if (result
== null) {
815 Report
.error (type
.source_reference
, "GVariant serialization of type `%s' is not supported".printf (type
.to_string ()));
821 public void write_expression (DataType type
, CCodeExpression builder_expr
, CCodeExpression expr
, Symbol? sym
) {
822 var variant_expr
= expr
;
823 if (sym
== null || get_dbus_signature (sym
) == null) {
825 variant_expr
= serialize_expression (type
, expr
);
827 if (variant_expr
!= null) {
828 var builder_add
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_variant_builder_add_value"));
829 builder_add
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, builder_expr
));
830 builder_add
.add_argument (variant_expr
);
831 ccode
.add_expression (builder_add
);