Fix wrapper for delegates returning arrays, fixes bug 564474
[vala-lang.git] / gobject / valadbusmodule.vala
blob9e6d5a46a0bda0e01328494ef6f07b8569b25299
1 /* valadbusmodule.vala
3 * Copyright (C) 2008-2009 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 public class Vala.DBusModule : GAsyncModule {
24 struct BasicTypeInfo {
25 public weak string signature;
26 public weak string type_name;
27 public weak string cname;
28 public weak string gtype;
29 public weak string? get_value_function;
30 public weak string set_value_function;
33 const BasicTypeInfo[] basic_types = {
34 { "y", "BYTE", "guint8", "G_TYPE_UCHAR", "g_value_get_uchar", "g_value_set_uchar" },
35 { "b", "BOOLEAN", "dbus_bool_t", "G_TYPE_BOOLEAN", "g_value_get_boolean", "g_value_set_boolean" },
36 { "n", "INT16", "dbus_int16_t", "G_TYPE_INT", null, "g_value_set_int" },
37 { "q", "UINT16", "dbus_uint16_t", "G_TYPE_UINT", null, "g_value_set_uint" },
38 { "i", "INT32", "dbus_int32_t", "G_TYPE_INT", "g_value_get_int", "g_value_set_int" },
39 { "u", "UINT32", "dbus_uint32_t", "G_TYPE_UINT", "g_value_get_uint", "g_value_set_uint" },
40 { "x", "INT64", "dbus_int64_t", "G_TYPE_INT64", "g_value_get_int64", "g_value_set_int64" },
41 { "t", "UINT64", "dbus_uint64_t", "G_TYPE_UINT64", "g_value_get_uint64", "g_value_set_uint64" },
42 { "d", "DOUBLE", "double", "G_TYPE_DOUBLE", "g_value_get_double", "g_value_set_double" },
43 { "s", "STRING", "const char*", "G_TYPE_STRING", "g_value_get_string", "g_value_take_string" },
44 { "o", "OBJECT_PATH", "const char*", "G_TYPE_STRING", null, "g_value_take_string" },
45 { "g", "SIGNATURE", "const char*", "G_TYPE_STRING", null, "g_value_take_string" }
48 public DBusModule (CCodeGenerator codegen, CCodeModule? next) {
49 base (codegen, next);
52 bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
53 foreach (BasicTypeInfo info in basic_types) {
54 if (info.signature == signature) {
55 basic_type = info;
56 return true;
59 return false;
62 CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
63 var id = expr as CCodeIdentifier;
64 var ma = expr as CCodeMemberAccess;
65 if (id != null) {
66 return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
67 } else if (ma != null) {
68 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
70 return null;
73 CCodeExpression read_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr) {
74 string temp_name = "_tmp%d".printf (next_temp_var_id++);
76 var cdecl = new CCodeDeclaration (basic_type.cname);
77 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
78 fragment.append (cdecl);
80 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_basic"));
81 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
82 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
83 fragment.append (new CCodeExpressionStatement (iter_call));
85 var temp_result = new CCodeIdentifier (temp_name);
87 if (basic_type.signature == "s"
88 || basic_type.signature == "o"
89 || basic_type.signature == "g") {
90 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup"));
91 dup_call.add_argument (temp_result);
92 return dup_call;
93 } else {
94 return temp_result;
98 CCodeExpression read_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression? expr) {
99 string temp_name = "_tmp%d".printf (next_temp_var_id++);
101 var cdecl = new CCodeDeclaration (array_type.get_cname ());
102 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name, new CCodeConstant ("NULL")));
103 fragment.append (cdecl);
105 cdecl = new CCodeDeclaration ("int");
106 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
107 fragment.append (cdecl);
109 cdecl = new CCodeDeclaration ("int");
110 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("0")));
111 fragment.append (cdecl);
113 read_array_dim (fragment, array_type, 1, temp_name, iter_expr, expr);
115 return new CCodeIdentifier (temp_name);
118 void read_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, string temp_name, CCodeExpression iter_expr, CCodeExpression? expr) {
119 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
121 var cdecl = new CCodeDeclaration ("int");
122 cdecl.add_declarator (new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
123 fragment.append (cdecl);
125 cdecl = new CCodeDeclaration ("DBusMessageIter");
126 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
127 fragment.append (cdecl);
129 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
130 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
131 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
132 fragment.append (new CCodeExpressionStatement (iter_call));
134 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
135 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
137 var cforblock = new CCodeBlock ();
138 var cforfragment = new CCodeFragment ();
139 cforblock.add_statement (cforfragment);
140 var cfor = new CCodeForStatement (iter_call, cforblock);
141 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim))));
143 if (dim < array_type.rank) {
144 read_array_dim (cforfragment, array_type, dim + 1, temp_name, new CCodeIdentifier (subiter_name), expr);
146 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
147 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
148 cforfragment.append (new CCodeExpressionStatement (iter_call));
149 } else {
150 var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
151 var renew_block = new CCodeBlock ();
153 // tmp_size = (tmp_size > 0) ? (2 * tmp_size) : 4;
154 var init_check = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("0"));
155 var new_size = new CCodeConditionalExpression (init_check, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size")), new CCodeConstant ("4"));
156 renew_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name + "_size"), new_size)));
158 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
159 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
160 renew_call.add_argument (new CCodeIdentifier (temp_name));
161 renew_call.add_argument (new CCodeIdentifier (temp_name + "_size"));
162 var renew_stmt = new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), renew_call));
163 renew_block.add_statement (renew_stmt);
165 var cif = new CCodeIfStatement (size_check, renew_block);
166 cforfragment.append (cif);
168 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
169 var element_expr = read_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), null);
170 cforfragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, element_expr)));
173 fragment.append (cfor);
175 if (expr != null) {
176 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)))));
180 CCodeExpression read_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr) {
181 string temp_name = "_tmp%d".printf (next_temp_var_id++);
182 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
184 var cdecl = new CCodeDeclaration (st.get_cname ());
185 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
186 fragment.append (cdecl);
188 cdecl = new CCodeDeclaration ("DBusMessageIter");
189 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
190 fragment.append (cdecl);
192 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
193 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
194 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
195 fragment.append (new CCodeExpressionStatement (iter_call));
197 foreach (Field f in st.get_fields ()) {
198 if (f.binding != MemberBinding.INSTANCE) {
199 continue;
202 var field_expr = read_expression (fragment, f.field_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()));
203 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()), field_expr)));
206 return new CCodeIdentifier (temp_name);
209 CCodeExpression read_value (CCodeFragment fragment, CCodeExpression iter_expr) {
210 string temp_name = "_tmp%d".printf (next_temp_var_id++);
211 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
213 // 0-initialize struct with struct initializer { 0 }
214 var cvalinit = new CCodeInitializerList ();
215 cvalinit.append (new CCodeConstant ("0"));
217 var cdecl = new CCodeDeclaration ("GValue");
218 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name, cvalinit));
219 fragment.append (cdecl);
221 cdecl = new CCodeDeclaration ("DBusMessageIter");
222 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
223 fragment.append (cdecl);
225 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
226 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
227 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
228 fragment.append (new CCodeExpressionStatement (iter_call));
230 CCodeIfStatement clastif = null;
232 foreach (BasicTypeInfo basic_type in basic_types) {
233 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
234 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
235 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
237 var type_block = new CCodeBlock ();
238 var type_fragment = new CCodeFragment ();
239 type_block.add_statement (type_fragment);
240 var result = read_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name));
242 var value_init = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
243 value_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
244 value_init.add_argument (new CCodeIdentifier (basic_type.gtype));
245 type_fragment.append (new CCodeExpressionStatement (value_init));
247 var value_set = new CCodeFunctionCall (new CCodeIdentifier (basic_type.set_value_function));
248 value_set.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
249 value_set.add_argument (result);
250 type_fragment.append (new CCodeExpressionStatement (value_set));
252 var cif = new CCodeIfStatement (type_check, type_block);
253 if (clastif == null) {
254 fragment.append (cif);
255 } else {
256 clastif.false_statement = cif;
259 clastif = cif;
262 return new CCodeIdentifier (temp_name);
265 CCodeExpression read_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr) {
266 string temp_name = "_tmp%d".printf (next_temp_var_id++);
267 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
268 string entryiter_name = "_tmp%d".printf (next_temp_var_id++);
270 var type_args = type.get_type_arguments ();
271 assert (type_args.size == 2);
272 var key_type = type_args.get (0);
273 var value_type = type_args.get (1);
275 var cdecl = new CCodeDeclaration ("GHashTable*");
276 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
277 fragment.append (cdecl);
279 cdecl = new CCodeDeclaration ("DBusMessageIter");
280 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
281 fragment.append (cdecl);
283 cdecl = new CCodeDeclaration ("DBusMessageIter");
284 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
285 fragment.append (cdecl);
287 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
288 if (key_type.data_type == string_type.data_type) {
289 hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
290 hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
291 } else {
292 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
293 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
295 if (key_type.data_type == string_type.data_type) {
296 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
297 } else {
298 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
300 if (value_type.data_type == string_type.data_type) {
301 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
302 } else {
303 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
305 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), hash_table_new)));
307 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
308 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
309 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
310 fragment.append (new CCodeExpressionStatement (iter_call));
312 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
313 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
315 var cwhileblock = new CCodeBlock ();
316 var cwhilefragment = new CCodeFragment ();
317 cwhileblock.add_statement (cwhilefragment);
318 var cwhile = new CCodeWhileStatement (iter_call, cwhileblock);
320 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
321 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
322 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
323 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
325 cdecl = new CCodeDeclaration (key_type.get_cname ());
326 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
327 cwhilefragment.append (cdecl);
329 cdecl = new CCodeDeclaration (value_type.get_cname ());
330 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
331 cwhilefragment.append (cdecl);
333 var key_expr = read_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), null);
334 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), key_expr)));
336 var value_expr = read_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), null);
337 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), value_expr)));
339 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
340 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
341 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_key"), key_type));
342 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_value"), value_type));
343 cwhilefragment.append (new CCodeExpressionStatement (hash_table_insert));
345 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
346 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
347 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
349 fragment.append (cwhile);
351 return new CCodeIdentifier (temp_name);
354 public CCodeExpression? read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression? expr) {
355 BasicTypeInfo basic_type;
356 CCodeExpression result = null;
357 if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
358 result = read_basic (fragment, basic_type, iter_expr);
359 } else if (type is ArrayType) {
360 result = read_array (fragment, (ArrayType) type, iter_expr, expr);
361 } else if (type.data_type is Struct) {
362 var st = (Struct) type.data_type;
363 if (type.data_type.get_full_name () == "GLib.Value") {
364 result = read_value (fragment, iter_expr);
365 } else {
366 result = read_struct (fragment, st, iter_expr);
368 if (type.nullable) {
369 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
370 csizeof.add_argument (new CCodeIdentifier (st.get_cname ()));
371 var cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
372 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
373 cdup.add_argument (csizeof);
374 result = cdup;
376 } else if (type is ObjectType) {
377 if (type.data_type.get_full_name () == "GLib.HashTable") {
378 result = read_hash_table (fragment, (ObjectType) type, iter_expr);
380 } else {
381 Report.error (type.source_reference, "D-Bus deserialization of type `%s' is not supported".printf (type.to_string ()));
382 return null;
385 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
386 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
387 fragment.append (new CCodeExpressionStatement (iter_call));
389 return result;
392 void write_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression expr) {
393 string temp_name = "_tmp%d".printf (next_temp_var_id++);
395 var cdecl = new CCodeDeclaration (basic_type.cname);
396 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
397 fragment.append (cdecl);
399 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), expr)));
401 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
402 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
403 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
404 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
405 fragment.append (new CCodeExpressionStatement (iter_call));
408 void write_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression array_expr) {
409 string array_iter_name = "_tmp%d".printf (next_temp_var_id++);
411 var cdecl = new CCodeDeclaration (array_type.get_cname ());
412 cdecl.add_declarator (new CCodeVariableDeclarator (array_iter_name));
413 fragment.append (cdecl);
415 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (array_iter_name), array_expr)));
417 write_array_dim (fragment, array_type, 1, iter_expr, array_expr, new CCodeIdentifier (array_iter_name));
420 void write_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, CCodeExpression iter_expr, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
421 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
422 string index_name = "_tmp%d".printf (next_temp_var_id++);
424 var cdecl = new CCodeDeclaration ("DBusMessageIter");
425 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
426 fragment.append (cdecl);
428 cdecl = new CCodeDeclaration ("int");
429 cdecl.add_declarator (new CCodeVariableDeclarator (index_name));
430 fragment.append (cdecl);
432 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
433 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
434 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
435 iter_call.add_argument (new CCodeConstant ("\"%s%s\"".printf (string.nfill (array_type.rank - dim, 'a'), array_type.element_type.get_type_signature ())));
436 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
437 fragment.append (new CCodeExpressionStatement (iter_call));
439 var cforblock = new CCodeBlock ();
440 var cforfragment = new CCodeFragment ();
441 cforblock.add_statement (cforfragment);
442 var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim)), cforblock);
443 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0")));
444 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name)));
446 if (dim < array_type.rank) {
447 write_array_dim (cforfragment, array_type, dim + 1, new CCodeIdentifier (subiter_name), array_expr, array_iter_expr);
448 } else {
449 var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
450 var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_incr);
451 write_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), element_expr);
453 fragment.append (cfor);
455 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
456 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
457 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
458 fragment.append (new CCodeExpressionStatement (iter_call));
461 void write_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr, CCodeExpression struct_expr) {
462 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
464 var cdecl = new CCodeDeclaration ("DBusMessageIter");
465 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
466 fragment.append (cdecl);
468 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
469 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
470 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_STRUCT"));
471 iter_call.add_argument (new CCodeConstant ("NULL"));
472 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
473 fragment.append (new CCodeExpressionStatement (iter_call));
475 foreach (Field f in st.get_fields ()) {
476 if (f.binding != MemberBinding.INSTANCE) {
477 continue;
480 write_expression (fragment, f.field_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (struct_expr, f.get_cname ()));
483 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
484 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
485 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
486 fragment.append (new CCodeExpressionStatement (iter_call));
489 void write_value (CCodeFragment fragment, CCodeExpression iter_expr, CCodeExpression expr) {
490 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
492 var cdecl = new CCodeDeclaration ("DBusMessageIter");
493 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
494 fragment.append (cdecl);
496 CCodeIfStatement clastif = null;
498 foreach (BasicTypeInfo basic_type in basic_types) {
499 // ensure that there is only one case per GType
500 if (basic_type.get_value_function == null) {
501 continue;
504 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
505 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
506 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier (basic_type.gtype));
508 var type_block = new CCodeBlock ();
509 var type_fragment = new CCodeFragment ();
510 type_block.add_statement (type_fragment);
512 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
513 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
514 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
515 iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (basic_type.signature)));
516 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
517 type_fragment.append (new CCodeExpressionStatement (iter_call));
519 var value_get = new CCodeFunctionCall (new CCodeIdentifier (basic_type.get_value_function));
520 value_get.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
522 write_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name), value_get);
524 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
525 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
526 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
527 type_fragment.append (new CCodeExpressionStatement (iter_call));
529 var cif = new CCodeIfStatement (type_check, type_block);
530 if (clastif == null) {
531 fragment.append (cif);
532 } else {
533 clastif.false_statement = cif;
536 clastif = cif;
540 void write_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr, CCodeExpression hash_table_expr) {
541 string subiter_name = "_tmp%d".printf (next_temp_var_id++);
542 string entryiter_name = "_tmp%d".printf (next_temp_var_id++);
543 string tableiter_name = "_tmp%d".printf (next_temp_var_id++);
544 string key_name = "_tmp%d".printf (next_temp_var_id++);
545 string value_name = "_tmp%d".printf (next_temp_var_id++);
547 var type_args = type.get_type_arguments ();
548 assert (type_args.size == 2);
549 var key_type = type_args.get (0);
550 var value_type = type_args.get (1);
552 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
553 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
554 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
555 iter_call.add_argument (new CCodeConstant ("\"{%s%s}\"".printf (key_type.get_type_signature (), value_type.get_type_signature ())));
556 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
557 fragment.append (new CCodeExpressionStatement (iter_call));
559 var cdecl = new CCodeDeclaration ("DBusMessageIter");
560 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
561 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
562 fragment.append (cdecl);
564 cdecl = new CCodeDeclaration ("GHashTableIter");
565 cdecl.add_declarator (new CCodeVariableDeclarator (tableiter_name));
566 fragment.append (cdecl);
568 cdecl = new CCodeDeclaration ("gpointer");
569 cdecl.add_declarator (new CCodeVariableDeclarator (key_name));
570 cdecl.add_declarator (new CCodeVariableDeclarator (value_name));
571 fragment.append (cdecl);
573 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
574 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
575 iter_init_call.add_argument (hash_table_expr);
576 fragment.append (new CCodeExpressionStatement (iter_init_call));
578 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
579 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
580 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
581 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
583 var cwhileblock = new CCodeBlock ();
584 var cwhilefragment = new CCodeFragment ();
585 cwhileblock.add_statement (cwhilefragment);
586 var cwhile = new CCodeWhileStatement (iter_next_call, cwhileblock);
588 cdecl = new CCodeDeclaration (key_type.get_cname ());
589 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
590 cwhilefragment.append (cdecl);
592 cdecl = new CCodeDeclaration (value_type.get_cname ());
593 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
594 cwhilefragment.append (cdecl);
596 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
597 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
598 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_DICT_ENTRY"));
599 iter_call.add_argument (new CCodeConstant ("NULL"));
600 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
601 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
603 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type))));
604 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type))));
606 write_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_key"));
607 write_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_value"));
609 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
610 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
611 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
612 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
614 fragment.append (cwhile);
616 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
617 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
618 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
619 fragment.append (new CCodeExpressionStatement (iter_call));
622 public void write_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression expr) {
623 BasicTypeInfo basic_type;
624 if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
625 write_basic (fragment, basic_type, iter_expr, expr);
626 } else if (type is ArrayType) {
627 write_array (fragment, (ArrayType) type, iter_expr, expr);
628 } else if (type.data_type is Struct) {
629 var st_expr = expr;
630 if (type.nullable) {
631 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
633 if (type.data_type.get_full_name () == "GLib.Value") {
634 write_value (fragment, iter_expr, st_expr);
635 } else {
636 write_struct (fragment, (Struct) type.data_type, iter_expr, st_expr);
638 } else if (type is ObjectType) {
639 if (type.data_type.get_full_name () == "GLib.HashTable") {
640 write_hash_table (fragment, (ObjectType) type, iter_expr, expr);
642 } else {
643 Report.error (type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (type.to_string ()));