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