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