D-Bus: Add get_dbus_name helper method
[vala-lang.git] / codegen / valadbusmodule.vala
blob1e9cb1f9b67608f07fde6f1bd63aa9df645d9b5f
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 internal 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 public string? get_dbus_name (TypeSymbol symbol) {
53 var dbus = symbol.get_attribute ("DBus");
54 if (dbus == null) {
55 return null;
58 return dbus.get_string ("name");
61 bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
62 foreach (BasicTypeInfo info in basic_types) {
63 if (info.signature == signature) {
64 basic_type = info;
65 return true;
68 return false;
71 public static string get_type_signature (DataType datatype) {
72 return datatype.get_type_signature ();
75 CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
76 var id = expr as CCodeIdentifier;
77 var ma = expr as CCodeMemberAccess;
78 if (id != null) {
79 return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
80 } else if (ma != null) {
81 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
83 return null;
86 CCodeExpression read_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr) {
87 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
89 var cdecl = new CCodeDeclaration (basic_type.cname);
90 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
91 fragment.append (cdecl);
93 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_basic"));
94 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
95 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
96 fragment.append (new CCodeExpressionStatement (iter_call));
98 var temp_result = new CCodeIdentifier (temp_name);
100 if (basic_type.signature == "s"
101 || basic_type.signature == "o"
102 || basic_type.signature == "g") {
103 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup"));
104 dup_call.add_argument (temp_result);
105 return dup_call;
106 } else {
107 return temp_result;
111 CCodeExpression read_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression? expr) {
112 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
114 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
115 new_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
116 // add one extra element for NULL-termination
117 new_call.add_argument (new CCodeConstant ("5"));
119 var cdecl = new CCodeDeclaration (array_type.get_cname ());
120 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name, new_call));
121 fragment.append (cdecl);
123 cdecl = new CCodeDeclaration ("int");
124 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
125 fragment.append (cdecl);
127 cdecl = new CCodeDeclaration ("int");
128 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
129 fragment.append (cdecl);
131 read_array_dim (fragment, array_type, 1, temp_name, iter_expr, expr);
133 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
134 // NULL terminate array
135 var length = new CCodeIdentifier (temp_name + "_length");
136 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
137 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, new CCodeIdentifier ("NULL"))));
140 return new CCodeIdentifier (temp_name);
143 void read_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, string temp_name, CCodeExpression iter_expr, CCodeExpression? expr) {
144 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
146 var cdecl = new CCodeDeclaration ("int");
147 cdecl.add_declarator (new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
148 fragment.append (cdecl);
150 cdecl = new CCodeDeclaration ("DBusMessageIter");
151 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
152 fragment.append (cdecl);
154 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
155 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
156 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
157 fragment.append (new CCodeExpressionStatement (iter_call));
159 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
160 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
162 var cforblock = new CCodeBlock ();
163 var cforfragment = new CCodeFragment ();
164 cforblock.add_statement (cforfragment);
165 var cfor = new CCodeForStatement (iter_call, cforblock);
166 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim))));
168 if (dim < array_type.rank) {
169 read_array_dim (cforfragment, array_type, dim + 1, temp_name, new CCodeIdentifier (subiter_name), expr);
171 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
172 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
173 cforfragment.append (new CCodeExpressionStatement (iter_call));
174 } else {
175 var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
176 var renew_block = new CCodeBlock ();
178 // tmp_size = (2 * tmp_size);
179 var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
180 renew_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name + "_size"), new_size)));
182 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
183 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
184 renew_call.add_argument (new CCodeIdentifier (temp_name));
185 // add one extra element for NULL-termination
186 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
187 var renew_stmt = new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), renew_call));
188 renew_block.add_statement (renew_stmt);
190 var cif = new CCodeIfStatement (size_check, renew_block);
191 cforfragment.append (cif);
193 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
194 var element_expr = read_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), null);
195 cforfragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, element_expr)));
198 fragment.append (cfor);
200 if (expr != null) {
201 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)))));
205 CCodeExpression read_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr) {
206 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
207 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
209 var cdecl = new CCodeDeclaration (st.get_cname ());
210 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
211 fragment.append (cdecl);
213 cdecl = new CCodeDeclaration ("DBusMessageIter");
214 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
215 fragment.append (cdecl);
217 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
218 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
219 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
220 fragment.append (new CCodeExpressionStatement (iter_call));
222 foreach (Field f in st.get_fields ()) {
223 if (f.binding != MemberBinding.INSTANCE) {
224 continue;
227 var field_expr = read_expression (fragment, f.field_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()));
228 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()), field_expr)));
231 return new CCodeIdentifier (temp_name);
234 CCodeExpression read_value (CCodeFragment fragment, CCodeExpression iter_expr) {
235 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
236 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
238 // 0-initialize struct with struct initializer { 0 }
239 var cvalinit = new CCodeInitializerList ();
240 cvalinit.append (new CCodeConstant ("0"));
242 var cdecl = new CCodeDeclaration ("GValue");
243 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name, cvalinit));
244 fragment.append (cdecl);
246 cdecl = new CCodeDeclaration ("DBusMessageIter");
247 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
248 fragment.append (cdecl);
250 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
251 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
252 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
253 fragment.append (new CCodeExpressionStatement (iter_call));
255 CCodeIfStatement clastif = null;
257 foreach (BasicTypeInfo basic_type in basic_types) {
258 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
259 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
260 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
262 var type_block = new CCodeBlock ();
263 var type_fragment = new CCodeFragment ();
264 type_block.add_statement (type_fragment);
265 var result = read_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name));
267 var value_init = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
268 value_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
269 value_init.add_argument (new CCodeIdentifier (basic_type.gtype));
270 type_fragment.append (new CCodeExpressionStatement (value_init));
272 var value_set = new CCodeFunctionCall (new CCodeIdentifier (basic_type.set_value_function));
273 value_set.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
274 value_set.add_argument (result);
275 type_fragment.append (new CCodeExpressionStatement (value_set));
277 var cif = new CCodeIfStatement (type_check, type_block);
278 if (clastif == null) {
279 fragment.append (cif);
280 } else {
281 clastif.false_statement = cif;
284 clastif = cif;
287 return new CCodeIdentifier (temp_name);
290 CCodeExpression read_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr) {
291 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
292 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
293 string entryiter_name = "_tmp%d_".printf (next_temp_var_id++);
295 var type_args = type.get_type_arguments ();
296 assert (type_args.size == 2);
297 var key_type = type_args.get (0);
298 var value_type = type_args.get (1);
300 var cdecl = new CCodeDeclaration ("GHashTable*");
301 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
302 fragment.append (cdecl);
304 cdecl = new CCodeDeclaration ("DBusMessageIter");
305 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
306 fragment.append (cdecl);
308 cdecl = new CCodeDeclaration ("DBusMessageIter");
309 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
310 fragment.append (cdecl);
312 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
313 if (key_type.data_type == string_type.data_type) {
314 hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
315 hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
316 } else {
317 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
318 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
320 if (key_type.data_type == string_type.data_type) {
321 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
322 } else {
323 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
325 if (value_type.data_type == string_type.data_type) {
326 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
327 } else {
328 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
330 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), hash_table_new)));
332 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
333 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
334 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
335 fragment.append (new CCodeExpressionStatement (iter_call));
337 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
338 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
340 var cwhileblock = new CCodeBlock ();
341 var cwhilefragment = new CCodeFragment ();
342 cwhileblock.add_statement (cwhilefragment);
343 var cwhile = new CCodeWhileStatement (iter_call, cwhileblock);
345 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
346 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
347 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
348 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
350 cdecl = new CCodeDeclaration (key_type.get_cname ());
351 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
352 cwhilefragment.append (cdecl);
354 cdecl = new CCodeDeclaration (value_type.get_cname ());
355 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
356 cwhilefragment.append (cdecl);
358 var key_expr = read_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), null);
359 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), key_expr)));
361 var value_expr = read_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), null);
362 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), value_expr)));
364 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
365 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
366 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_key"), key_type));
367 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_value"), value_type));
368 cwhilefragment.append (new CCodeExpressionStatement (hash_table_insert));
370 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
371 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
372 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
374 fragment.append (cwhile);
376 return new CCodeIdentifier (temp_name);
379 public CCodeExpression? read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression? expr) {
380 BasicTypeInfo basic_type;
381 CCodeExpression result = null;
382 if (get_basic_type_info (get_type_signature (type), out basic_type)) {
383 result = read_basic (fragment, basic_type, iter_expr);
384 } else if (type is ArrayType) {
385 result = read_array (fragment, (ArrayType) type, iter_expr, expr);
386 } else if (type.data_type is Struct) {
387 var st = (Struct) type.data_type;
388 if (type.data_type.get_full_name () == "GLib.Value") {
389 result = read_value (fragment, iter_expr);
390 } else {
391 result = read_struct (fragment, st, iter_expr);
393 if (type.nullable) {
394 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
395 csizeof.add_argument (new CCodeIdentifier (st.get_cname ()));
396 var cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
397 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
398 cdup.add_argument (csizeof);
399 result = cdup;
401 } else if (type is ObjectType) {
402 if (type.data_type.get_full_name () == "GLib.HashTable") {
403 result = read_hash_table (fragment, (ObjectType) type, iter_expr);
405 } else {
406 Report.error (type.source_reference, "D-Bus deserialization of type `%s' is not supported".printf (type.to_string ()));
407 return null;
410 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
411 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
412 fragment.append (new CCodeExpressionStatement (iter_call));
414 return result;
417 void write_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression expr) {
418 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
420 var cdecl = new CCodeDeclaration (basic_type.cname);
421 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
422 fragment.append (cdecl);
424 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), expr)));
426 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
427 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
428 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
429 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
430 fragment.append (new CCodeExpressionStatement (iter_call));
433 void write_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression array_expr) {
434 string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
436 var cdecl = new CCodeDeclaration (array_type.get_cname ());
437 cdecl.add_declarator (new CCodeVariableDeclarator (array_iter_name));
438 fragment.append (cdecl);
440 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (array_iter_name), array_expr)));
442 write_array_dim (fragment, array_type, 1, iter_expr, array_expr, new CCodeIdentifier (array_iter_name));
445 void write_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, CCodeExpression iter_expr, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
446 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
447 string index_name = "_tmp%d_".printf (next_temp_var_id++);
449 var cdecl = new CCodeDeclaration ("DBusMessageIter");
450 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
451 fragment.append (cdecl);
453 cdecl = new CCodeDeclaration ("int");
454 cdecl.add_declarator (new CCodeVariableDeclarator (index_name));
455 fragment.append (cdecl);
457 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
458 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
459 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
460 iter_call.add_argument (new CCodeConstant ("\"%s%s\"".printf (string.nfill (array_type.rank - dim, 'a'), get_type_signature (array_type.element_type))));
461 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
462 fragment.append (new CCodeExpressionStatement (iter_call));
464 var cforblock = new CCodeBlock ();
465 var cforfragment = new CCodeFragment ();
466 cforblock.add_statement (cforfragment);
467 var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim)), cforblock);
468 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0")));
469 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name)));
471 if (dim < array_type.rank) {
472 write_array_dim (cforfragment, array_type, dim + 1, new CCodeIdentifier (subiter_name), array_expr, array_iter_expr);
473 } else {
474 var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
475 write_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), element_expr);
477 var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
478 cforfragment.append (new CCodeExpressionStatement (array_iter_incr));
480 fragment.append (cfor);
482 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
483 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
484 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
485 fragment.append (new CCodeExpressionStatement (iter_call));
488 void write_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr, CCodeExpression struct_expr) {
489 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
491 var cdecl = new CCodeDeclaration ("DBusMessageIter");
492 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
493 fragment.append (cdecl);
495 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
496 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
497 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_STRUCT"));
498 iter_call.add_argument (new CCodeConstant ("NULL"));
499 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
500 fragment.append (new CCodeExpressionStatement (iter_call));
502 foreach (Field f in st.get_fields ()) {
503 if (f.binding != MemberBinding.INSTANCE) {
504 continue;
507 write_expression (fragment, f.field_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (struct_expr, f.get_cname ()));
510 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
511 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
512 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
513 fragment.append (new CCodeExpressionStatement (iter_call));
516 void write_value (CCodeFragment fragment, CCodeExpression iter_expr, CCodeExpression expr) {
517 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
519 var cdecl = new CCodeDeclaration ("DBusMessageIter");
520 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
521 fragment.append (cdecl);
523 CCodeIfStatement clastif = null;
525 foreach (BasicTypeInfo basic_type in basic_types) {
526 // ensure that there is only one case per GType
527 if (basic_type.get_value_function == null) {
528 continue;
531 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
532 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
533 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier (basic_type.gtype));
535 var type_block = new CCodeBlock ();
536 var type_fragment = new CCodeFragment ();
537 type_block.add_statement (type_fragment);
539 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
540 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
541 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
542 iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (basic_type.signature)));
543 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
544 type_fragment.append (new CCodeExpressionStatement (iter_call));
546 var value_get = new CCodeFunctionCall (new CCodeIdentifier (basic_type.get_value_function));
547 value_get.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
549 write_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name), value_get);
551 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
552 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
553 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
554 type_fragment.append (new CCodeExpressionStatement (iter_call));
556 var cif = new CCodeIfStatement (type_check, type_block);
557 if (clastif == null) {
558 fragment.append (cif);
559 } else {
560 clastif.false_statement = cif;
563 clastif = cif;
567 void write_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr, CCodeExpression hash_table_expr) {
568 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
569 string entryiter_name = "_tmp%d_".printf (next_temp_var_id++);
570 string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
571 string key_name = "_tmp%d_".printf (next_temp_var_id++);
572 string value_name = "_tmp%d_".printf (next_temp_var_id++);
574 var type_args = type.get_type_arguments ();
575 assert (type_args.size == 2);
576 var key_type = type_args.get (0);
577 var value_type = type_args.get (1);
579 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
580 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
581 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
582 iter_call.add_argument (new CCodeConstant ("\"{%s%s}\"".printf (get_type_signature (key_type), get_type_signature (value_type))));
583 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
584 fragment.append (new CCodeExpressionStatement (iter_call));
586 var cdecl = new CCodeDeclaration ("DBusMessageIter");
587 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
588 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
589 fragment.append (cdecl);
591 cdecl = new CCodeDeclaration ("GHashTableIter");
592 cdecl.add_declarator (new CCodeVariableDeclarator (tableiter_name));
593 fragment.append (cdecl);
595 cdecl = new CCodeDeclaration ("gpointer");
596 cdecl.add_declarator (new CCodeVariableDeclarator (key_name));
597 cdecl.add_declarator (new CCodeVariableDeclarator (value_name));
598 fragment.append (cdecl);
600 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
601 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
602 iter_init_call.add_argument (hash_table_expr);
603 fragment.append (new CCodeExpressionStatement (iter_init_call));
605 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
606 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
607 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
608 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
610 var cwhileblock = new CCodeBlock ();
611 var cwhilefragment = new CCodeFragment ();
612 cwhileblock.add_statement (cwhilefragment);
613 var cwhile = new CCodeWhileStatement (iter_next_call, cwhileblock);
615 cdecl = new CCodeDeclaration (key_type.get_cname ());
616 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
617 cwhilefragment.append (cdecl);
619 cdecl = new CCodeDeclaration (value_type.get_cname ());
620 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
621 cwhilefragment.append (cdecl);
623 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
624 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
625 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_DICT_ENTRY"));
626 iter_call.add_argument (new CCodeConstant ("NULL"));
627 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
628 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
630 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type))));
631 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type))));
633 write_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_key"));
634 write_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_value"));
636 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
637 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
638 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
639 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
641 fragment.append (cwhile);
643 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
644 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
645 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
646 fragment.append (new CCodeExpressionStatement (iter_call));
649 public void write_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression expr) {
650 BasicTypeInfo basic_type;
651 if (get_basic_type_info (get_type_signature (type), out basic_type)) {
652 write_basic (fragment, basic_type, iter_expr, expr);
653 } else if (type is ArrayType) {
654 write_array (fragment, (ArrayType) type, iter_expr, expr);
655 } else if (type.data_type is Struct) {
656 var st_expr = expr;
657 if (type.nullable) {
658 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
660 if (type.data_type.get_full_name () == "GLib.Value") {
661 write_value (fragment, iter_expr, st_expr);
662 } else {
663 write_struct (fragment, (Struct) type.data_type, iter_expr, st_expr);
665 } else if (type is ObjectType) {
666 if (type.data_type.get_full_name () == "GLib.HashTable") {
667 write_hash_table (fragment, (ObjectType) type, iter_expr, expr);
669 } else {
670 Report.error (type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (type.to_string ()));