LCOV - code coverage report
Current view: top level - codegen - valagvariantmodule.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 96.7 % 578 559
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valagvariantmodule.vala
       2              :  *
       3              :  * Copyright (C) 2010-2011  Jürg Billeter
       4              :  *
       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.
       9              : 
      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.
      14              : 
      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
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  */
      22              : 
      23         4371 : public class Vala.GVariantModule : GValueModule {
      24              :         struct BasicTypeInfo {
      25              :                 public unowned string signature;
      26              :                 public unowned string type_name;
      27              :                 public bool is_string;
      28              :         }
      29              : 
      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 }
      43              :         };
      44              : 
      45              :         static bool is_string_marshalled_enum (TypeSymbol? symbol) {
      46          751 :                 if (symbol != null && symbol is Enum) {
      47          260 :                         return symbol.get_attribute_bool ("DBus", "use_string_marshalling");
      48              :                 }
      49          751 :                 return false;
      50              :         }
      51              : 
      52            2 :         string get_dbus_value (EnumValue value, string default_value) {
      53            2 :                 var dbus_value = value.get_attribute_string ("DBus", "value");
      54            2 :                 if (dbus_value != null) {
      55            2 :                         return dbus_value;;
      56              :                 }
      57            4 :                 return default_value;
      58              :         }
      59              : 
      60          306 :         public static string? get_dbus_signature (Symbol symbol) {
      61          306 :                 return symbol.get_attribute_string ("DBus", "signature");
      62              :         }
      63              : 
      64          513 :         bool get_basic_type_info (string? signature, out BasicTypeInfo basic_type) {
      65          513 :                 if (signature != null) {
      66         4625 :                         foreach (BasicTypeInfo info in basic_types) {
      67         4500 :                                 if (info.signature == signature) {
      68          385 :                                         basic_type = info;
      69          385 :                                         return true;
      70              :                                 }
      71              :                         }
      72              :                 }
      73          128 :                 basic_type = BasicTypeInfo ();
      74          128 :                 return false;
      75              :         }
      76              : 
      77           80 :         public override void visit_enum (Enum en) {
      78           80 :                 base.visit_enum (en);
      79              : 
      80           80 :                 if (is_string_marshalled_enum (en)) {
      81              :                         // strcmp
      82            1 :                         cfile.add_include ("string.h");
      83              : 
      84              :                         // for G_DBUS_ERROR
      85            1 :                         cfile.add_include ("gio/gio.h");
      86              : 
      87            1 :                         cfile.add_function (generate_enum_from_string_function (en));
      88            1 :                         cfile.add_function (generate_enum_to_string_function (en));
      89              :                 }
      90              :         }
      91              : 
      92         3836 :         public override bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
      93         3836 :                 if (base.generate_enum_declaration (en, decl_space)) {
      94          168 :                         if (is_string_marshalled_enum (en)) {
      95            3 :                                 decl_space.add_function_declaration (generate_enum_from_string_function_declaration (en));
      96            3 :                                 decl_space.add_function_declaration (generate_enum_to_string_function_declaration (en));
      97              :                         }
      98          168 :                         return true;
      99              :                 }
     100         3836 :                 return false;
     101              :         }
     102              : 
     103         1457 :         int next_variant_function_id = 0;
     104              : 
     105         1880 :         public override void visit_cast_expression (CastExpression expr) {
     106         1905 :                 var value = expr.inner.target_value;
     107         1825 :                 var target_type = expr.type_reference;
     108              : 
     109         1813 :                 if (expr.is_non_null_cast || value.value_type == null || gvariant_type == null || value.value_type.type_symbol != gvariant_type) {
     110         1746 :                         base.visit_cast_expression (expr);
     111         1746 :                         return;
     112              :                 }
     113              : 
     114           67 :                 generate_type_declaration (expr.type_reference, cfile);
     115              : 
     116           67 :                 string variant_func = "_variant_get%d".printf (++next_variant_function_id);
     117              : 
     118           67 :                 var variant = value;
     119           92 :                 if (value.value_type.value_owned) {
     120              :                         // value leaked, destroy it
     121           25 :                         var temp_value = store_temp_value (value, expr);
     122           25 :                         temp_ref_values.insert (0, ((GLibValue) temp_value).copy ());
     123           50 :                         variant = temp_value;
     124              :                 }
     125              : 
     126           67 :                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
     127           67 :                 ccall.add_argument (get_cvalue_ (variant));
     128              : 
     129           67 :                 var needs_init = (target_type is ArrayType);
     130           67 :                 var result = create_temp_value (target_type, needs_init, expr);
     131              : 
     132           67 :                 var cfunc = new CCodeFunction (variant_func);
     133           67 :                 cfunc.modifiers = CCodeModifiers.STATIC;
     134           67 :                 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
     135              : 
     136           67 :                 if (!target_type.is_real_non_null_struct_type ()) {
     137           64 :                         cfunc.return_type = get_ccode_name (target_type);
     138              :                 }
     139              : 
     140           67 :                 if (target_type.is_real_non_null_struct_type ()) {
     141              :                         // structs are returned via out parameter
     142            3 :                         cfunc.add_parameter (new CCodeParameter ("result", "%s *".printf (get_ccode_name (target_type))));
     143            3 :                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (result)));
     144           75 :                 } else if (target_type is ArrayType) {
     145              :                         // return array length if appropriate
     146              :                         // tmp = _variant_get (variant, &tmp_length);
     147           11 :                         unowned ArrayType array_type = (ArrayType) target_type;
     148           11 :                         var length_ctype = get_ccode_array_length_type (array_type);
     149           26 :                         for (int dim = 1; dim <= array_type.rank; dim++) {
     150           15 :                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (result, dim)));
     151           15 :                                 cfunc.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), length_ctype + "*"));
     152              :                         }
     153              :                 }
     154              : 
     155           67 :                 if (!target_type.is_real_non_null_struct_type ()) {
     156           64 :                         ccode.add_assignment (get_cvalue_ (result), ccall);
     157              :                 } else {
     158            3 :                         ccode.add_expression (ccall);
     159              :                 }
     160              : 
     161           67 :                 push_context (new EmitContext ());
     162           67 :                 push_function (cfunc);
     163              : 
     164           67 :                 CCodeExpression type_expr = null;
     165           67 :                 BasicTypeInfo basic_type = {};
     166           67 :                 bool is_basic_type = false;
     167           77 :                 if (expr.is_silent_cast) {
     168           10 :                         var signature = target_type.get_type_signature ();
     169           10 :                         is_basic_type = get_basic_type_info (signature, out basic_type);
     170           10 :                         var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_is_of_type"));
     171           10 :                         ccheck.add_argument (new CCodeIdentifier ("value"));
     172           14 :                         if (is_basic_type) {
     173            6 :                                 type_expr = new CCodeIdentifier ("G_VARIANT_TYPE_" + basic_type.type_name.ascii_up ());
     174              :                         } else {
     175            4 :                                 var gvariant_type_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("VariantType"));
     176            4 :                                 var type_temp = get_temp_variable (gvariant_type_type, true, expr, true);
     177            4 :                                 emit_temp_var (type_temp);
     178            4 :                                 type_expr = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_type_new"));
     179            4 :                                 ((CCodeFunctionCall) type_expr).add_argument (new CCodeIdentifier ("\"%s\"".printf (signature)));
     180            4 :                                 store_value (get_local_cvalue (type_temp), new GLibValue (gvariant_type_type, type_expr), expr.source_reference);
     181            4 :                                 type_expr = get_variable_cexpression (type_temp.name);
     182              :                         }
     183           10 :                         ccheck.add_argument (type_expr);
     184           10 :                         ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("value"), ccheck));
     185              :                 }
     186              : 
     187           67 :                 CCodeExpression func_result = deserialize_expression (target_type, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
     188              : 
     189           67 :                 if (expr.is_silent_cast) {
     190           19 :                         if (is_basic_type && basic_type.is_string) {
     191            1 :                                 ccode.add_return (func_result);
     192              :                         } else {
     193           13 :                                 if (!is_basic_type) {
     194            4 :                                         var type_free = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_type_free"));
     195            4 :                                         type_free.add_argument (type_expr);
     196            4 :                                         ccode.add_expression (type_free);
     197              :                                 }
     198            9 :                                 var temp_type = expr.target_type.copy ();
     199            9 :                                 if (!expr.target_type.is_real_struct_type ()) {
     200            8 :                                         temp_type.nullable = false;
     201              :                                 }
     202            9 :                                 var temp_value = create_temp_value (temp_type, false, expr);
     203            9 :                                 store_value (temp_value, new GLibValue (temp_type, func_result), expr.source_reference);
     204            9 :                                 ccode.add_return (get_cvalue_ (transform_value (temp_value, expr.target_type, expr)));
     205              :                         }
     206           10 :                         ccode.add_else ();
     207           14 :                         if (!is_basic_type) {
     208            4 :                                 var type_free = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_type_free"));
     209            4 :                                 type_free.add_argument (type_expr);
     210            4 :                                 ccode.add_expression (type_free);
     211              :                         }
     212           10 :                         ccode.add_return (new CCodeConstant ("NULL"));
     213           10 :                         ccode.close ();
     214           57 :                 } else if (target_type.is_real_non_null_struct_type ()) {
     215            3 :                         ccode.add_assignment (new CCodeIdentifier ("*result"), func_result);
     216              :                 } else {
     217           54 :                         ccode.add_return (func_result);
     218              :                 }
     219              : 
     220           67 :                 pop_function ();
     221           67 :                 pop_context ();
     222              : 
     223           67 :                 cfile.add_function_declaration (cfunc);
     224           67 :                 cfile.add_function (cfunc);
     225              : 
     226           67 :                 expr.target_value = load_temp_value (result);
     227              :         }
     228              : 
     229           89 :         CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
     230          297 :                 var id = expr as CCodeIdentifier;
     231           89 :                 var ma = expr as CCodeMemberAccess;
     232           89 :                 if (id != null) {
     233           87 :                         return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
     234            2 :                 } else if (ma != null) {
     235            2 :                         if (ma.is_pointer) {
     236            2 :                                 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
     237              :                         } else {
     238            0 :                                 return new CCodeMemberAccess (ma.inner, "%s_length%d".printf (ma.member_name, dim));
     239              :                         }
     240              :                 } else {
     241              :                         // must be NULL-terminated
     242            0 :                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
     243            0 :                         len_call.add_argument (expr);
     244            0 :                         return len_call;
     245              :                 }
     246              :         }
     247              : 
     248            6 :         CCodeExpression? generate_enum_value_from_string (EnumValueType type, CCodeExpression? expr, CCodeExpression? error_expr) {
     249            6 :                 var en = type.type_symbol as Enum;
     250            6 :                 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
     251              : 
     252            6 :                 var from_string_call = new CCodeFunctionCall (new CCodeIdentifier (from_string_name));
     253            6 :                 from_string_call.add_argument (expr);
     254            6 :                 from_string_call.add_argument (error_expr != null ? error_expr : new CCodeConstant ("NULL"));
     255              : 
     256            6 :                 return from_string_call;
     257              :         }
     258              : 
     259            3 :         public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
     260            3 :                 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
     261              : 
     262            3 :                 var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
     263            3 :                 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
     264            3 :                 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
     265            3 :                 from_string_func.modifiers |= CCodeModifiers.EXTERN;
     266            3 :                 requires_vala_extern = true;
     267              : 
     268            3 :                 return from_string_func;
     269              :         }
     270              : 
     271            1 :         public CCodeFunction generate_enum_from_string_function (Enum en) {
     272            1 :                 var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
     273              : 
     274            1 :                 var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
     275            1 :                 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
     276            1 :                 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
     277              : 
     278            1 :                 push_function (from_string_func);
     279              : 
     280            1 :                 ccode.add_declaration (get_ccode_name (en), new CCodeVariableDeclarator.zero ("value", new CCodeConstant ("0")));
     281              : 
     282            1 :                 bool firstif = true;
     283            3 :                 foreach (EnumValue enum_value in en.get_values ()) {
     284            1 :                         string dbus_value = get_dbus_value (enum_value, enum_value.name);
     285            1 :                         var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
     286            1 :                         string_comparison.add_argument (new CCodeIdentifier ("str"));
     287            1 :                         string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
     288            1 :                         var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0"));
     289            1 :                         if (firstif) {
     290            1 :                                 ccode.open_if (cond);
     291            1 :                                 firstif = false;
     292              :                         } else {
     293            0 :                                 ccode.else_if (cond);
     294              :                         }
     295            1 :                         ccode.add_assignment (new CCodeIdentifier ("value"), new CCodeIdentifier (get_ccode_name (enum_value)));
     296              :                 }
     297              : 
     298            1 :                 ccode.add_else ();
     299            1 :                 var set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
     300            1 :                 set_error.add_argument (new CCodeIdentifier ("error"));
     301            1 :                 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR"));
     302            1 :                 set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR_INVALID_ARGS"));
     303            1 :                 set_error.add_argument (new CCodeConstant ("\"Invalid value for enum `%s'\"".printf (get_ccode_name (en))));
     304            1 :                 ccode.add_expression (set_error);
     305            1 :                 ccode.close ();
     306              : 
     307            1 :                 ccode.add_return (new CCodeIdentifier ("value"));
     308              : 
     309            1 :                 pop_function ();
     310            1 :                 return from_string_func;
     311              :         }
     312              : 
     313          185 :         CCodeExpression deserialize_basic (BasicTypeInfo basic_type, CCodeExpression variant_expr, bool transfer = false) {
     314          185 :                 var get_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_" + basic_type.type_name));
     315          185 :                 get_call.add_argument (variant_expr);
     316              : 
     317          185 :                 if (basic_type.is_string) {
     318           85 :                         if (transfer) {
     319            6 :                                 get_call.call = new CCodeIdentifier ("g_variant_get_string");
     320              :                         } else {
     321           79 :                                 get_call.call = new CCodeIdentifier ("g_variant_dup_string");
     322              :                         }
     323           85 :                         get_call.add_argument (new CCodeConstant ("NULL"));
     324              :                 }
     325              : 
     326              :                 return get_call;
     327              :         }
     328              : 
     329           32 :         CCodeExpression deserialize_array (ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
     330           32 :                 if (array_type.rank == 1 && array_type.get_type_signature () == "ay") {
     331            2 :                         return deserialize_buffer_array (array_type, variant_expr, expr);
     332              :                 }
     333              : 
     334           30 :                 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
     335              : 
     336           30 :                 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
     337           30 :                 new_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
     338              :                 // add one extra element for NULL-termination
     339           30 :                 new_call.add_argument (new CCodeConstant ("5"));
     340              : 
     341           30 :                 var length_ctype = get_ccode_array_length_type (array_type);
     342           30 :                 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (temp_name, new_call));
     343           30 :                 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
     344           30 :                 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
     345              : 
     346           30 :                 deserialize_array_dim (array_type, 1, temp_name, variant_expr, expr);
     347              : 
     348           52 :                 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
     349              :                         // NULL terminate array
     350           22 :                         var length = new CCodeIdentifier (temp_name + "_length");
     351           22 :                         var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
     352           22 :                         ccode.add_assignment (element_access, new CCodeConstant ("NULL"));
     353              :                 }
     354              : 
     355           30 :                 return new CCodeIdentifier (temp_name);
     356              :         }
     357              : 
     358           74 :         void deserialize_array_dim (ArrayType array_type, int dim, string temp_name, CCodeExpression variant_expr, CCodeExpression? expr) {
     359           37 :                 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
     360           37 :                 string element_name = "_tmp%d_".printf (next_temp_var_id++);
     361              : 
     362           37 :                 ccode.add_declaration (get_ccode_array_length_type (array_type), new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
     363           37 :                 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
     364           37 :                 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (element_name));
     365              : 
     366           37 :                 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
     367           37 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     368           37 :                 iter_call.add_argument (variant_expr);
     369           37 :                 ccode.add_expression (iter_call);
     370              : 
     371           37 :                 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
     372           37 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     373              : 
     374           37 :                 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeAssignment (new CCodeIdentifier (element_name), iter_call), new CCodeConstant ("NULL"));
     375           37 :                 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
     376           37 :                 ccode.open_for (null, cforcond, cforiter);
     377              : 
     378           67 :                 if (dim < array_type.rank) {
     379            7 :                         deserialize_array_dim (array_type, dim + 1, temp_name, new CCodeIdentifier (element_name), expr);
     380              :                 } else {
     381           30 :                         var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
     382              : 
     383           30 :                         ccode.open_if (size_check);
     384              : 
     385              :                         // tmp_size = (2 * tmp_size);
     386           30 :                         var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
     387           30 :                         ccode.add_assignment (new CCodeIdentifier (temp_name + "_size"), new_size);
     388              : 
     389           30 :                         var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
     390           30 :                         renew_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
     391           30 :                         renew_call.add_argument (new CCodeIdentifier (temp_name));
     392              :                         // add one extra element for NULL-termination
     393           30 :                         renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
     394           30 :                         ccode.add_assignment (new CCodeIdentifier (temp_name), renew_call);
     395              : 
     396           30 :                         ccode.close ();
     397              : 
     398           30 :                         var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
     399           30 :                         var element_expr = deserialize_expression (array_type.element_type, new CCodeIdentifier (element_name), null);
     400           30 :                         ccode.add_assignment (element_access, element_expr);
     401              :                 }
     402              : 
     403           37 :                 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
     404           37 :                 unref.add_argument (new CCodeIdentifier (element_name));
     405           37 :                 ccode.add_expression (unref);
     406              : 
     407           37 :                 ccode.close ();
     408              : 
     409           37 :                 if (expr != null) {
     410           37 :                         ccode.add_assignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)));
     411              :                 }
     412              :         }
     413              : 
     414            2 :         CCodeExpression deserialize_buffer_array (ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
     415            2 :                 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
     416              : 
     417            2 :                 var get_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_data"));
     418            2 :                 get_data_call.add_argument (variant_expr);
     419              : 
     420            2 :                 var get_size_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_size"));
     421            2 :                 get_size_call.add_argument (variant_expr);
     422            2 :                 ccode.add_declaration ("gsize", new CCodeVariableDeclarator (temp_name + "_length", get_size_call));
     423            2 :                 var length = new CCodeIdentifier (temp_name + "_length");
     424              : 
     425              :                 CCodeFunctionCall dup_call;
     426            2 :                 if (context.require_glib_version (2, 68)) {
     427            1 :                         dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
     428              :                 } else {
     429            1 :                         requires_memdup2 = true;
     430            1 :                         dup_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
     431              :                 }
     432            2 :                 dup_call.add_argument (get_data_call);
     433            2 :                 dup_call.add_argument (length);
     434              : 
     435            2 :                 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (temp_name, dup_call));
     436            2 :                 if (expr != null) {
     437            2 :                         ccode.add_assignment (get_array_length (expr, 1), length);
     438              :                 }
     439              : 
     440            2 :                 return new CCodeIdentifier (temp_name);
     441              :         }
     442              : 
     443           12 :         CCodeExpression? deserialize_struct (Struct st, CCodeExpression variant_expr) {
     444           12 :                 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
     445           12 :                 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
     446              : 
     447           12 :                 ccode.add_declaration (get_ccode_name (st), new CCodeVariableDeclarator (temp_name));
     448           12 :                 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
     449              : 
     450           12 :                 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
     451           12 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     452           12 :                 iter_call.add_argument (variant_expr);
     453           12 :                 ccode.add_expression (iter_call);
     454              : 
     455           12 :                 bool field_found = false;;
     456              : 
     457           64 :                 foreach (Field f in st.get_fields ()) {
     458           26 :                         if (f.binding != MemberBinding.INSTANCE) {
     459            0 :                                 continue;
     460              :                         }
     461              : 
     462           26 :                         field_found = true;
     463              : 
     464           26 :                         read_expression (f.variable_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), get_ccode_name (f)), f);
     465              :                 }
     466              : 
     467           12 :                 if (!field_found) {
     468            0 :                         return null;
     469              :                 }
     470              : 
     471           12 :                 return new CCodeIdentifier (temp_name);
     472              :         }
     473              : 
     474            7 :         CCodeExpression? deserialize_hash_table (ObjectType type, CCodeExpression variant_expr) {
     475            7 :                 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
     476            7 :                 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
     477            7 :                 string key_name = "_tmp%d_".printf (next_temp_var_id++);
     478            7 :                 string value_name = "_tmp%d_".printf (next_temp_var_id++);
     479              : 
     480           16 :                 var type_args = type.get_type_arguments ();
     481            7 :                 if (type_args.size != 2) {
     482            1 :                         Report.error (type.source_reference, "Missing type-arguments for GVariant deserialization of `%s'", type.type_symbol.get_full_name ());
     483            1 :                         return new CCodeInvalidExpression ();
     484              :                 }
     485            6 :                 var key_type = type_args.get (0);
     486            6 :                 var value_type = type_args.get (1);
     487              : 
     488            6 :                 ccode.add_declaration ("GHashTable*", new CCodeVariableDeclarator (temp_name));
     489            6 :                 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator (subiter_name));
     490            6 :                 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (key_name));
     491            6 :                 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (value_name));
     492              : 
     493            6 :                 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
     494            6 :                 if (key_type.type_symbol.is_subtype_of (string_type.type_symbol)) {
     495            5 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
     496            5 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
     497            1 :                 } else if (key_type.type_symbol == gvariant_type) {
     498            0 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_variant_hash"));
     499            0 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_variant_equal"));
     500              :                 } else {
     501            1 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
     502            1 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
     503              :                 }
     504              : 
     505            6 :                 if (key_type.type_symbol.is_subtype_of (string_type.type_symbol)) {
     506            5 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
     507            1 :                 } else if (key_type.type_symbol == gvariant_type) {
     508            0 :                         hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
     509            1 :                 } else if (key_type.type_symbol.get_full_name () == "GLib.HashTable") {
     510            0 :                         hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
     511              :                 } else {
     512            1 :                         hash_table_new.add_argument (new CCodeConstant ("NULL"));
     513              :                 }
     514              : 
     515            6 :                 if (value_type.type_symbol.is_subtype_of (string_type.type_symbol)) {
     516            2 :                         hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
     517            4 :                 } else if (value_type.type_symbol == gvariant_type) {
     518            3 :                         hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify"));
     519            1 :                 } else if (value_type.type_symbol.get_full_name () == "GLib.HashTable") {
     520            1 :                         hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify"));
     521              :                 } else {
     522            0 :                         hash_table_new.add_argument (new CCodeConstant ("NULL"));
     523              :                 }
     524            6 :                 ccode.add_assignment (new CCodeIdentifier (temp_name), hash_table_new);
     525              : 
     526            6 :                 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
     527            6 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     528            6 :                 iter_call.add_argument (variant_expr);
     529            6 :                 ccode.add_expression (iter_call);
     530              : 
     531            6 :                 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_loop"));
     532            6 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     533            6 :                 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
     534            6 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
     535            6 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
     536              : 
     537            6 :                 ccode.open_while (iter_call);
     538              : 
     539            6 :                 var key_expr = deserialize_expression (key_type, new CCodeIdentifier (key_name), null);
     540            6 :                 var value_expr = deserialize_expression (value_type, new CCodeIdentifier (value_name), null);
     541            6 :                 if (key_expr == null || value_expr == null) {
     542            0 :                         return null;
     543              :                 }
     544              : 
     545            6 :                 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
     546            6 :                 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
     547            6 :                 hash_table_insert.add_argument (convert_to_generic_pointer (key_expr, key_type));
     548            6 :                 hash_table_insert.add_argument (convert_to_generic_pointer (value_expr, value_type));
     549            6 :                 ccode.add_expression (hash_table_insert);
     550              : 
     551            6 :                 ccode.close ();
     552              : 
     553            6 :                 return new CCodeIdentifier (temp_name);
     554              :         }
     555              : 
     556          241 :         public override CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
     557              :                 BasicTypeInfo basic_type;
     558          241 :                 CCodeExpression result = null;
     559          241 :                 may_fail = false;
     560          241 :                 if (is_string_marshalled_enum (type.type_symbol)) {
     561            6 :                         get_basic_type_info ("s", out basic_type);
     562            6 :                         result = deserialize_basic (basic_type, variant_expr, true);
     563           12 :                         result = generate_enum_value_from_string (type as EnumValueType, result, error_expr);
     564            6 :                         may_fail = true;
     565          235 :                 } else if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
     566          179 :                         result = deserialize_basic (basic_type, variant_expr);
     567           56 :                 } else if (type is ArrayType) {
     568           32 :                         result = deserialize_array ((ArrayType) type, variant_expr, expr);
     569           24 :                 } else if (type.type_symbol is Struct) {
     570           12 :                         unowned Struct st = (Struct) type.type_symbol;
     571           12 :                         result = deserialize_struct (st, variant_expr);
     572           14 :                         if (result != null && type.nullable) {
     573            2 :                                 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
     574            2 :                                 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (st)));
     575              :                                 CCodeFunctionCall cdup;
     576            2 :                                 if (context.require_glib_version (2, 68)) {
     577            1 :                                         cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
     578              :                                 } else {
     579            1 :                                         requires_memdup2 = true;
     580            1 :                                         cdup = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
     581              :                                 }
     582            2 :                                 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
     583            2 :                                 cdup.add_argument (csizeof);
     584            4 :                                 result = cdup;
     585              :                         }
     586           12 :                 } else if (type is ObjectType) {
     587           12 :                         if (type.type_symbol.get_full_name () == "GLib.Variant") {
     588            5 :                                 var variant_get = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_variant"));
     589            5 :                                 variant_get.add_argument (variant_expr);
     590          240 :                                 result = variant_get;
     591            7 :                         } else if (type.type_symbol.get_full_name () == "GLib.HashTable") {
     592            7 :                                 result = deserialize_hash_table ((ObjectType) type, variant_expr);
     593              :                         }
     594              :                 }
     595              : 
     596          241 :                 if (result == null) {
     597            0 :                         Report.error (type.source_reference, "GVariant deserialization of type `%s' is not supported", type.to_string ());
     598            0 :                         return new CCodeInvalidExpression ();
     599              :                 }
     600              : 
     601          241 :                 return result;
     602              :         }
     603              : 
     604          246 :         public void read_expression (DataType type, CCodeExpression iter_expr, CCodeExpression target_expr, Symbol? sym, CCodeExpression? error_expr = null, out bool may_fail = null) {
     605          123 :                 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
     606          123 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
     607              : 
     608          123 :                 if (sym != null && get_dbus_signature (sym) != null) {
     609              :                         // raw GVariant
     610            6 :                         ccode.add_assignment (target_expr, iter_call);
     611            6 :                         may_fail = false;
     612            6 :                         return;
     613              :                 }
     614              : 
     615          117 :                 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
     616              : 
     617          117 :                 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (temp_name));
     618              : 
     619          117 :                 var variant_expr = new CCodeIdentifier (temp_name);
     620              : 
     621          117 :                 ccode.add_assignment (variant_expr, iter_call);
     622              : 
     623          117 :                 var result = deserialize_expression (type, variant_expr, target_expr, error_expr, out may_fail);
     624          117 :                 if (result == null) {
     625              :                         // error already reported
     626            0 :                         return;
     627              :                 }
     628              : 
     629          117 :                 ccode.add_assignment (target_expr, result);
     630              : 
     631          117 :                 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
     632          117 :                 unref.add_argument (variant_expr);
     633          117 :                 ccode.add_expression (unref);
     634              :         }
     635              : 
     636            6 :         CCodeExpression? generate_enum_value_to_string (EnumValueType type, CCodeExpression? expr) {
     637            6 :                 var en = type.type_symbol as Enum;
     638            6 :                 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
     639              : 
     640            6 :                 var to_string_call = new CCodeFunctionCall (new CCodeIdentifier (to_string_name));
     641            6 :                 to_string_call.add_argument (expr);
     642              : 
     643            6 :                 return to_string_call;
     644              :         }
     645              : 
     646            3 :         public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
     647            3 :                 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
     648              : 
     649            3 :                 var to_string_func = new CCodeFunction (to_string_name, "const char*");
     650            3 :                 to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
     651            3 :                 to_string_func.modifiers |= CCodeModifiers.EXTERN;
     652            3 :                 requires_vala_extern = true;
     653              : 
     654            3 :                 return to_string_func;
     655              :         }
     656              : 
     657            1 :         public CCodeFunction generate_enum_to_string_function (Enum en) {
     658            1 :                 var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
     659              : 
     660            1 :                 var to_string_func = new CCodeFunction (to_string_name, "const char*");
     661            1 :                 to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
     662              : 
     663            1 :                 push_function (to_string_func);
     664              : 
     665            1 :                 ccode.add_declaration ("const char *", new CCodeVariableDeclarator ("str"));
     666              : 
     667            1 :                 ccode.open_switch (new CCodeIdentifier ("value"));
     668            3 :                 foreach (EnumValue enum_value in en.get_values ()) {
     669            1 :                         string dbus_value = get_dbus_value (enum_value, enum_value.name);
     670            1 :                         ccode.add_case (new CCodeIdentifier (get_ccode_name (enum_value)));
     671            1 :                         ccode.add_assignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)));
     672            1 :                         ccode.add_break ();
     673              :                 }
     674              : 
     675            1 :                 ccode.close();
     676              : 
     677            1 :                 ccode.add_return (new CCodeIdentifier ("str"));
     678              : 
     679            1 :                 pop_function ();
     680            1 :                 return to_string_func;
     681              :         }
     682              : 
     683          194 :         CCodeExpression? serialize_basic (BasicTypeInfo basic_type, CCodeExpression expr) {
     684          194 :                 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_" + basic_type.type_name));
     685          194 :                 new_call.add_argument (expr);
     686          194 :                 return new_call;
     687              :         }
     688              : 
     689           38 :         CCodeExpression? serialize_array (ArrayType array_type, CCodeExpression array_expr) {
     690           38 :                 if (array_type.rank == 1 && array_type.get_type_signature () == "ay") {
     691            2 :                         return serialize_buffer_array (array_type, array_expr);
     692              :                 }
     693              : 
     694           36 :                 string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
     695              : 
     696           36 :                 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (array_iter_name));
     697           36 :                 ccode.add_assignment (new CCodeIdentifier (array_iter_name), array_expr);
     698              : 
     699           36 :                 return serialize_array_dim (array_type, 1, array_expr, new CCodeIdentifier (array_iter_name));
     700              :         }
     701              : 
     702           46 :         CCodeExpression? serialize_array_dim (ArrayType array_type, int dim, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
     703           46 :                 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
     704           46 :                 string index_name = "_tmp%d_".printf (next_temp_var_id++);
     705              : 
     706           46 :                 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
     707           46 :                 ccode.add_declaration (get_ccode_array_length_type (array_type), new CCodeVariableDeclarator (index_name));
     708              : 
     709           46 :                 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
     710           46 :                 ArrayType array_type_copy = (ArrayType) array_type.copy ();
     711           46 :                 array_type_copy.rank -= dim - 1;
     712           46 :                 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (array_type_copy.get_type_signature ())));
     713              : 
     714           46 :                 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
     715           46 :                 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
     716           46 :                 builder_init.add_argument (gvariant_type);
     717           46 :                 ccode.add_expression (builder_init);
     718              : 
     719           46 :                 var cforinit = new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0"));
     720           46 :                 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim));
     721           46 :                 var cforiter = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name));
     722           46 :                 ccode.open_for (cforinit, cforcond, cforiter);
     723              : 
     724              :                 CCodeExpression element_variant;
     725           82 :                 if (dim < array_type.rank) {
     726           10 :                         element_variant = serialize_array_dim (array_type, dim + 1, array_expr, array_iter_expr);
     727              :                 } else {
     728           36 :                         var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
     729           36 :                         element_variant = serialize_expression (array_type.element_type, element_expr);
     730              :                 }
     731              : 
     732           46 :                 var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
     733           46 :                 builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
     734           46 :                 builder_add.add_argument (element_variant);
     735           46 :                 ccode.add_expression (builder_add);
     736              : 
     737           82 :                 if (dim == array_type.rank) {
     738           36 :                         var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
     739           36 :                         ccode.add_expression (array_iter_incr);
     740              :                 }
     741              : 
     742           46 :                 ccode.close ();
     743              : 
     744           46 :                 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
     745           46 :                 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
     746           46 :                 return builder_end;
     747              :         }
     748              : 
     749            2 :         CCodeExpression serialize_buffer_array (ArrayType array_type, CCodeExpression array_expr) {
     750            2 :                 string buffer_name = "_tmp%d_".printf (next_temp_var_id++);
     751              : 
     752            2 :                 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
     753            2 :                 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (array_type.get_type_signature ())));
     754              : 
     755              :                 CCodeFunctionCall dup_call;
     756            2 :                 if (context.require_glib_version (2, 68)) {
     757            1 :                         dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
     758              :                 } else {
     759            1 :                         requires_memdup2 = true;
     760            1 :                         dup_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
     761              :                 }
     762            2 :                 dup_call.add_argument (array_expr);
     763            2 :                 dup_call.add_argument (get_array_length (array_expr, 1));
     764            2 :                 ccode.add_declaration (get_ccode_name (array_type), new CCodeVariableDeclarator (buffer_name, dup_call));
     765              : 
     766            2 :                 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_from_data"));
     767            2 :                 new_call.add_argument (gvariant_type);
     768            2 :                 new_call.add_argument (new CCodeIdentifier (buffer_name));
     769            2 :                 new_call.add_argument (get_array_length (array_expr, 1));
     770            2 :                 new_call.add_argument (new CCodeConstant ("TRUE"));
     771            2 :                 new_call.add_argument (new CCodeIdentifier ("g_free"));
     772            2 :                 new_call.add_argument (new CCodeIdentifier (buffer_name));
     773              : 
     774            2 :                 return new_call;
     775              :         }
     776              : 
     777           13 :         CCodeExpression? serialize_struct (Struct st, CCodeExpression struct_expr) {
     778           13 :                 string builder_name = "_tmp%d_".printf (next_temp_var_id++);
     779              : 
     780           13 :                 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (builder_name));
     781              : 
     782           13 :                 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
     783           13 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
     784           13 :                 iter_call.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
     785           13 :                 ccode.add_expression (iter_call);
     786              : 
     787           13 :                 bool field_found = false;;
     788              : 
     789           65 :                 foreach (Field f in st.get_fields ()) {
     790           26 :                         if (f.binding != MemberBinding.INSTANCE) {
     791            0 :                                 continue;
     792              :                         }
     793              : 
     794           26 :                         field_found = true;
     795              : 
     796           26 :                         write_expression (f.variable_type, new CCodeIdentifier (builder_name), new CCodeMemberAccess (struct_expr, get_ccode_name (f)), f);
     797              :                 }
     798              : 
     799           13 :                 if (!field_found) {
     800            0 :                         return null;
     801              :                 }
     802              : 
     803           13 :                 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
     804           13 :                 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
     805           13 :                 return builder_end;
     806              :         }
     807              : 
     808            9 :         CCodeExpression? serialize_hash_table (ObjectType type, CCodeExpression hash_table_expr) {
     809            9 :                 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
     810            9 :                 string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
     811            9 :                 string key_name = "_tmp%d_".printf (next_temp_var_id++);
     812            9 :                 string value_name = "_tmp%d_".printf (next_temp_var_id++);
     813              : 
     814            9 :                 var type_args = type.get_type_arguments ();
     815            9 :                 if (type_args.size != 2) {
     816            1 :                         Report.error (type.source_reference, "Missing type-arguments for GVariant serialization of `%s'", type.type_symbol.get_full_name ());
     817            1 :                         return new CCodeInvalidExpression ();
     818              :                 }
     819            8 :                 var key_type = type_args.get (0);
     820            8 :                 var value_type = type_args.get (1);
     821              : 
     822            8 :                 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator (subiter_name));
     823            8 :                 ccode.add_declaration ("GHashTableIter", new CCodeVariableDeclarator (tableiter_name));
     824            8 :                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (key_name));
     825            8 :                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator (value_name));
     826              : 
     827            8 :                 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
     828            8 :                 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
     829            8 :                 iter_init_call.add_argument (hash_table_expr);
     830            8 :                 ccode.add_expression (iter_init_call);
     831              : 
     832            8 :                 var gvariant_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
     833            8 :                 gvariant_type.add_argument (new CCodeConstant ("\"%s\"".printf (type.get_type_signature ())));
     834              : 
     835            8 :                 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
     836            8 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     837            8 :                 iter_call.add_argument (gvariant_type);
     838            8 :                 ccode.add_expression (iter_call);
     839              : 
     840            8 :                 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
     841            8 :                 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
     842            8 :                 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
     843            8 :                 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
     844              : 
     845            8 :                 ccode.open_while (iter_next_call);
     846              : 
     847            8 :                 ccode.add_declaration (get_ccode_name (key_type), new CCodeVariableDeclarator ("_key"));
     848            8 :                 ccode.add_declaration (get_ccode_name (value_type), new CCodeVariableDeclarator ("_value"));
     849              : 
     850            8 :                 ccode.add_assignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type));
     851            8 :                 ccode.add_assignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type));
     852              : 
     853            8 :                 var serialized_key =  serialize_expression (key_type, new CCodeIdentifier ("_key"));
     854            8 :                 var serialized_value = serialize_expression (value_type, new CCodeIdentifier ("_value"));
     855            8 :                 if (serialized_key == null || serialized_value == null) {
     856            0 :                         return null;
     857              :                 }
     858              : 
     859            8 :                 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add"));
     860            8 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     861            8 :                 iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
     862            8 :                 iter_call.add_argument (serialized_key);
     863            8 :                 iter_call.add_argument (serialized_value);
     864            8 :                 ccode.add_expression (iter_call);
     865              : 
     866            8 :                 ccode.close ();
     867              : 
     868            8 :                 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
     869            8 :                 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
     870            8 :                 return iter_call;
     871              :         }
     872              : 
     873          262 :         public override CCodeExpression? serialize_expression (DataType type, CCodeExpression expr) {
     874              :                 BasicTypeInfo basic_type;
     875          262 :                 CCodeExpression result = null;
     876          262 :                 if (is_string_marshalled_enum (type.type_symbol)) {
     877            6 :                         get_basic_type_info ("s", out basic_type);
     878           12 :                         result = generate_enum_value_to_string (type as EnumValueType, expr);
     879            6 :                         result = serialize_basic (basic_type, result);
     880          256 :                 } else if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
     881          188 :                         result = serialize_basic (basic_type, expr);
     882           68 :                 } else if (type is ArrayType) {
     883           38 :                         result = serialize_array ((ArrayType) type, expr);
     884           43 :                 } else if (type.type_symbol is Struct) {
     885           13 :                         var st_expr = expr;
     886           13 :                         if (type.nullable) {
     887            1 :                                 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
     888              :                         }
     889           13 :                         result = serialize_struct ((Struct) type.type_symbol, st_expr);
     890           17 :                 } else if (type is ObjectType) {
     891           16 :                         if (type.type_symbol.get_full_name () == "GLib.Variant") {
     892            7 :                                 var variant_new = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_variant"));
     893            7 :                                 variant_new.add_argument (expr);
     894          262 :                                 result = variant_new;
     895            9 :                         } else if (type.type_symbol.get_full_name () == "GLib.HashTable") {
     896            9 :                                 result = serialize_hash_table ((ObjectType) type, expr);
     897              :                         }
     898              :                 }
     899              : 
     900          262 :                 if (result == null) {
     901            1 :                         Report.error (type.source_reference, "GVariant serialization of type `%s' is not supported", type.to_string ());
     902            1 :                         return new CCodeInvalidExpression ();
     903              :                 }
     904              : 
     905          262 :                 return result;
     906              :         }
     907              : 
     908          346 :         public void write_expression (DataType type, CCodeExpression builder_expr, CCodeExpression expr, Symbol? sym) {
     909          173 :                 var variant_expr = expr;
     910          173 :                 if (sym == null || get_dbus_signature (sym) == null) {
     911              :                         // perform boxing
     912          166 :                         variant_expr = serialize_expression (type, expr);
     913              :                 }
     914          346 :                 if (variant_expr != null) {
     915          173 :                         var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
     916          173 :                         builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, builder_expr));
     917          173 :                         builder_add.add_argument (variant_expr);
     918          173 :                         ccode.add_expression (builder_add);
     919              :                 }
     920              :         }
     921              : }
        

Generated by: LCOV version 2.0-1