]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
gvariant: Box and unbox nullable basic types
authorSergey Bugaev <bugaevc@gmail.com>
Sat, 7 Jun 2025 20:10:50 +0000 (23:10 +0300)
committerRico Tzschichholz <ricotz@ubuntu.com>
Sat, 16 May 2026 12:12:58 +0000 (14:12 +0200)
Just like we already do for other structs. As a side effect, we no
longer need to do this explicitly when generating a "silent" cast.

codegen/valagvariantmodule.vala
tests/Makefile.am
tests/basic-types/gvariants-hashtable-boxed.c-expected [new file with mode: 0644]
tests/basic-types/gvariants-hashtable-boxed.vala [new file with mode: 0644]
tests/basic-types/gvariants-unboxing-safe.c-expected

index 8e70ac16883ecf66cdbdb5d7d7ecf491846d9566..66db6aa3e48a921804a093911cdba1331acbfcc7 100644 (file)
@@ -195,13 +195,7 @@ public class Vala.GVariantModule : GValueModule {
                                        type_free.add_argument (type_expr);
                                        ccode.add_expression (type_free);
                                }
-                               var temp_type = expr.target_type.copy ();
-                               if (!expr.target_type.is_real_struct_type ()) {
-                                       temp_type.nullable = false;
-                               }
-                               var temp_value = create_temp_value (temp_type, false, expr);
-                               store_value (temp_value, new GLibValue (temp_type, func_result), expr.source_reference);
-                               ccode.add_return (get_cvalue_ (transform_value (temp_value, expr.target_type, expr)));
+                               ccode.add_return (func_result);
                        }
                        ccode.add_else ();
                        if (!is_basic_type) {
@@ -550,6 +544,28 @@ public class Vala.GVariantModule : GValueModule {
                return new CCodeIdentifier (temp_name);
        }
 
+       private CCodeExpression memdup_value_type (ValueType type, owned CCodeExpression expr) {
+               var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+               csizeof.add_argument (new CCodeIdentifier (get_ccode_name (type.type_symbol)));
+               CCodeFunctionCall cdup;
+               if (context.require_glib_version (2, 68)) {
+                       cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
+               } else {
+                       requires_memdup2 = true;
+                       cdup = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
+               }
+               if (!(expr is CCodeIdentifier)) {
+                       string temp_name = "_tmp%d_".printf (next_temp_var_id++);
+                       ccode.add_declaration (get_ccode_name (type.type_symbol), new CCodeVariableDeclarator (temp_name));
+                       var cident = new CCodeIdentifier (temp_name);
+                       ccode.add_assignment (cident, expr);
+                       expr = (owned) cident;
+               }
+               cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
+               cdup.add_argument (csizeof);
+               return cdup;
+       }
+
        public override CCodeExpression? deserialize_expression (DataType type, CCodeExpression variant_expr, CCodeExpression? expr, CCodeExpression? error_expr = null, out bool may_fail = null) {
                BasicTypeInfo basic_type;
                CCodeExpression result = null;
@@ -559,26 +575,21 @@ public class Vala.GVariantModule : GValueModule {
                        result = deserialize_basic (basic_type, variant_expr, true);
                        result = generate_enum_value_from_string (type as EnumValueType, result, error_expr);
                        may_fail = true;
+                       if (type.nullable) {
+                               result = memdup_value_type ((ValueType) type, (owned) result);
+                       }
                } else if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
                        result = deserialize_basic (basic_type, variant_expr);
+                       if (!basic_type.is_string && type.nullable) {
+                               result = memdup_value_type ((ValueType) type, (owned) result);
+                       }
                } else if (type is ArrayType) {
                        result = deserialize_array ((ArrayType) type, variant_expr, expr);
                } else if (type.type_symbol is Struct) {
                        unowned Struct st = (Struct) type.type_symbol;
                        result = deserialize_struct (st, variant_expr);
                        if (result != null && type.nullable) {
-                               var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
-                               csizeof.add_argument (new CCodeIdentifier (get_ccode_name (st)));
-                               CCodeFunctionCall cdup;
-                               if (context.require_glib_version (2, 68)) {
-                                       cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
-                               } else {
-                                       requires_memdup2 = true;
-                                       cdup = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
-                               }
-                               cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
-                               cdup.add_argument (csizeof);
-                               result = cdup;
+                               result = memdup_value_type ((ValueType) type, (owned) result);
                        }
                } else if (type is ObjectType) {
                        if (type.type_symbol.get_full_name () == "GLib.Variant") {
@@ -899,10 +910,18 @@ public class Vala.GVariantModule : GValueModule {
                CCodeExpression result = null;
                if (is_string_marshalled_enum (type.type_symbol)) {
                        get_basic_type_info ("s", out basic_type);
-                       result = generate_enum_value_to_string (type as EnumValueType, expr);
+                       var enum_expr = expr;
+                       if (type.nullable) {
+                               enum_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, enum_expr);
+                       }
+                       result = generate_enum_value_to_string (type as EnumValueType, enum_expr);
                        result = serialize_basic (basic_type, result);
                } else if (get_basic_type_info (type.get_type_signature (), out basic_type)) {
-                       result = serialize_basic (basic_type, expr);
+                       var b_expr = expr;
+                       if (!basic_type.is_string && type.nullable) {
+                               b_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
+                       }
+                       result = serialize_basic (basic_type, b_expr);
                } else if (type is ArrayType) {
                        result = serialize_array ((ArrayType) type, expr);
                } else if (type.type_symbol is Struct) {
index 9275a270c5d623c3adc7429f036b340ebf53641f..d89a82fe4e989830d10459b0ed08b538ad4bb8f9 100644 (file)
@@ -85,6 +85,7 @@ TESTS = \
        basic-types/glists_remove.vala \
        basic-types/gptrarray.vala \
        basic-types/gvariants.vala \
+       basic-types/gvariants-hashtable-boxed.vala \
        basic-types/gvariants-hashtable-deserialize-missing-type-arguments.test \
        basic-types/gvariants-hashtable-serialize-missing-type-arguments.test \
        basic-types/gvariants-unboxing-safe.vala \
diff --git a/tests/basic-types/gvariants-hashtable-boxed.c-expected b/tests/basic-types/gvariants-hashtable-boxed.c-expected
new file mode 100644 (file)
index 0000000..28ac3b4
--- /dev/null
@@ -0,0 +1,546 @@
+/* basic_types_gvariants_hashtable_boxed.c generated by valac, the Vala compiler
+ * generated from basic_types_gvariants_hashtable_boxed.vala, do not modify */
+
+#include <glib-object.h>
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+#include <math.h>
+
+#if !defined(VALA_STRICT_C)
+#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)
+#pragma GCC diagnostic warning "-Wincompatible-pointer-types"
+#elif defined(__clang__) && (__clang_major__ >= 16)
+#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types"
+#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
+#endif
+#endif
+#if !defined(VALA_EXTERN)
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
+#define TYPE_FOO (foo_get_type ())
+typedef struct _Foo Foo;
+
+#define TYPE_BAR (bar_get_type ())
+typedef struct _Bar Bar;
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _g_hash_table_unref0(var) ((var == NULL) ? NULL : (var = (g_hash_table_unref (var), NULL)))
+#define _g_variant_unref0(var) ((var == NULL) ? NULL : (var = (g_variant_unref (var), NULL)))
+#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
+#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
+#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
+
+struct _Foo {
+       gint manam;
+};
+
+struct _Bar {
+       gint baz;
+};
+
+VALA_EXTERN gint bar_irrelevant;
+gint bar_irrelevant = 0;
+
+VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ;
+VALA_EXTERN Foo* foo_dup (const Foo* self);
+VALA_EXTERN void foo_free (Foo* self);
+VALA_EXTERN GType bar_get_type (void) G_GNUC_CONST ;
+VALA_EXTERN Bar* bar_dup (const Bar* self);
+VALA_EXTERN void bar_free (Bar* self);
+VALA_EXTERN void test1 (void);
+static void _g_free0_ (gpointer var);
+static void _foo_free0_ (gpointer var);
+static guint64* _uint64_dup (guint64* self);
+static GVariant* _variant_new1 (GHashTable* value);
+static GHashTable* _variant_get1 (GVariant* value);
+VALA_EXTERN void test2 (void);
+static gboolean* _bool_dup (gboolean* self);
+static GVariant* _variant_new2 (GHashTable* value);
+static GHashTable* _variant_get2 (GVariant* value);
+VALA_EXTERN void test3 (void);
+static void _bar_free0_ (gpointer var);
+static gdouble* _double_dup (gdouble* self);
+static GVariant* _variant_new3 (GHashTable* value);
+static GHashTable* _variant_get3 (GVariant* value);
+static void _vala_main (void);
+static inline gpointer _vala_memdup2 (gconstpointer mem,
+                        gsize byte_size);
+
+Foo*
+foo_dup (const Foo* self)
+{
+       Foo* dup;
+       dup = g_new0 (Foo, 1);
+       memcpy (dup, self, sizeof (Foo));
+       return dup;
+}
+
+void
+foo_free (Foo* self)
+{
+       g_free (self);
+}
+
+static GType
+foo_get_type_once (void)
+{
+       GType foo_type_id;
+       foo_type_id = g_boxed_type_register_static ("Foo", (GBoxedCopyFunc) foo_dup, (GBoxedFreeFunc) foo_free);
+       return foo_type_id;
+}
+
+GType
+foo_get_type (void)
+{
+       static volatile gsize foo_type_id__once = 0;
+       if (g_once_init_enter (&foo_type_id__once)) {
+               GType foo_type_id;
+               foo_type_id = foo_get_type_once ();
+               g_once_init_leave (&foo_type_id__once, foo_type_id);
+       }
+       return foo_type_id__once;
+}
+
+Bar*
+bar_dup (const Bar* self)
+{
+       Bar* dup;
+       dup = g_new0 (Bar, 1);
+       memcpy (dup, self, sizeof (Bar));
+       return dup;
+}
+
+void
+bar_free (Bar* self)
+{
+       g_free (self);
+}
+
+static GType
+bar_get_type_once (void)
+{
+       GType bar_type_id;
+       bar_type_id = g_boxed_type_register_static ("Bar", (GBoxedCopyFunc) bar_dup, (GBoxedFreeFunc) bar_free);
+       return bar_type_id;
+}
+
+GType
+bar_get_type (void)
+{
+       static volatile gsize bar_type_id__once = 0;
+       if (g_once_init_enter (&bar_type_id__once)) {
+               GType bar_type_id;
+               bar_type_id = bar_get_type_once ();
+               g_once_init_leave (&bar_type_id__once, bar_type_id);
+       }
+       return bar_type_id__once;
+}
+
+static void
+_g_free0_ (gpointer var)
+{
+       (var == NULL) ? NULL : (var = (g_free (var), NULL));
+}
+
+static void
+_foo_free0_ (gpointer var)
+{
+       (var == NULL) ? NULL : (var = (foo_free (var), NULL));
+}
+
+static guint64*
+_uint64_dup (guint64* self)
+{
+       guint64* dup;
+       dup = g_new0 (guint64, 1);
+       memcpy (dup, self, sizeof (guint64));
+       return dup;
+}
+
+static gpointer
+__uint64_dup0 (gpointer self)
+{
+       return self ? _uint64_dup (self) : NULL;
+}
+
+static gpointer
+_foo_dup0 (gpointer self)
+{
+       return self ? foo_dup (self) : NULL;
+}
+
+static GVariant*
+_variant_new1 (GHashTable* value)
+{
+       GVariantBuilder _tmp7_;
+       GHashTableIter _tmp8_;
+       gpointer _tmp9_;
+       gpointer _tmp10_;
+       g_hash_table_iter_init (&_tmp8_, value);
+       g_variant_builder_init (&_tmp7_, G_VARIANT_TYPE ("a{t(i)}"));
+       while (g_hash_table_iter_next (&_tmp8_, &_tmp9_, &_tmp10_)) {
+               guint64* _key;
+               Foo* _value;
+               GVariantBuilder _tmp11_;
+               _key = (guint64*) _tmp9_;
+               _value = (Foo*) _tmp10_;
+               g_variant_builder_init (&_tmp11_, G_VARIANT_TYPE_TUPLE);
+               g_variant_builder_add_value (&_tmp11_, g_variant_new_int32 ((*_value).manam));
+               g_variant_builder_add (&_tmp7_, "{?*}", g_variant_new_uint64 (*_key), g_variant_builder_end (&_tmp11_));
+       }
+       return g_variant_ref_sink (g_variant_builder_end (&_tmp7_));
+}
+
+static GHashTable*
+_variant_get1 (GVariant* value)
+{
+       GHashTable* _tmp0_;
+       GVariantIter _tmp1_;
+       GVariant* _tmp2_;
+       GVariant* _tmp3_;
+       _tmp0_ = g_hash_table_new_full (g_int64_hash, g_int64_equal, (GDestroyNotify) g_free, (GDestroyNotify) bar_free);
+       g_variant_iter_init (&_tmp1_, value);
+       while (g_variant_iter_loop (&_tmp1_, "{?*}", &_tmp2_, &_tmp3_)) {
+               guint64 _tmp4_;
+               Bar _tmp5_;
+               GVariantIter _tmp6_;
+               GVariant* _tmp7_;
+               _tmp4_ = g_variant_get_uint64 (_tmp2_);
+               g_variant_iter_init (&_tmp6_, _tmp3_);
+               _tmp7_ = g_variant_iter_next_value (&_tmp6_);
+               _tmp5_.baz = g_variant_get_int32 (_tmp7_);
+               g_variant_unref (_tmp7_);
+               g_hash_table_insert (_tmp0_, _vala_memdup2 (&_tmp4_, sizeof (guint64)), _vala_memdup2 (&_tmp5_, sizeof (Bar)));
+       }
+       return _tmp0_;
+}
+
+void
+test1 (void)
+{
+       GHashTable* ht = NULL;
+       GHashFunc _tmp0_;
+       GEqualFunc _tmp1_;
+       GHashTable* _tmp2_;
+       guint64 _tmp3_;
+       guint64* _tmp4_;
+       Foo _tmp5_ = {0};
+       Foo* _tmp6_;
+       GVariant* v = NULL;
+       GVariant* _tmp12_;
+       const gchar* _tmp13_;
+       gchar* _tmp14_;
+       gchar* _tmp15_;
+       GHashTable* ht2 = NULL;
+       GHashTable* _tmp16_;
+       guint _tmp17_;
+       guint _tmp18_;
+       guint64 _tmp19_;
+       gconstpointer _tmp20_;
+       _tmp0_ = g_int64_hash;
+       _tmp1_ = g_int64_equal;
+       _tmp2_ = g_hash_table_new_full (_tmp0_, _tmp1_, _g_free0_, _foo_free0_);
+       ht = _tmp2_;
+       _tmp3_ = (guint64) 123;
+       _tmp4_ = __uint64_dup0 (&_tmp3_);
+       _tmp5_.manam = 42;
+       _tmp6_ = _foo_dup0 (&_tmp5_);
+       g_hash_table_insert (ht, _tmp4_, _tmp6_);
+       _tmp12_ = _variant_new1 (ht);
+       v = _tmp12_;
+       _tmp13_ = g_variant_get_type_string (v);
+       _vala_assert (g_strcmp0 (_tmp13_, "a{t(i)}") == 0, "v.get_type_string () == \"a{t(i)}\"");
+       _tmp14_ = g_variant_print (v, TRUE);
+       _tmp15_ = _tmp14_;
+       _vala_assert (g_strcmp0 (_tmp15_, "{uint64 123: (42,)}") == 0, "v.print (true) == \"{uint64 123: (42,)}\"");
+       _g_free0 (_tmp15_);
+       _tmp16_ = _variant_get1 (v);
+       ht2 = _tmp16_;
+       _tmp17_ = g_hash_table_size (ht2);
+       _tmp18_ = _tmp17_;
+       _vala_assert (_tmp18_ == ((guint) 1), "ht2.length == 1");
+       _tmp19_ = (guint64) 123;
+       _tmp20_ = g_hash_table_lookup (ht2, &_tmp19_);
+       _vala_assert ((*((Bar*) _tmp20_)).baz == 42, "ht2[123].baz == 42");
+       _g_hash_table_unref0 (ht2);
+       _g_variant_unref0 (v);
+       _g_hash_table_unref0 (ht);
+}
+
+static gboolean*
+_bool_dup (gboolean* self)
+{
+       gboolean* dup;
+       dup = g_new0 (gboolean, 1);
+       memcpy (dup, self, sizeof (gboolean));
+       return dup;
+}
+
+static gpointer
+__bool_dup0 (gpointer self)
+{
+       return self ? _bool_dup (self) : NULL;
+}
+
+static GVariant*
+_variant_new2 (GHashTable* value)
+{
+       GVariantBuilder _tmp9_;
+       GHashTableIter _tmp10_;
+       gpointer _tmp11_;
+       gpointer _tmp12_;
+       g_hash_table_iter_init (&_tmp10_, value);
+       g_variant_builder_init (&_tmp9_, G_VARIANT_TYPE ("a{sb}"));
+       while (g_hash_table_iter_next (&_tmp10_, &_tmp11_, &_tmp12_)) {
+               gchar* _key;
+               gboolean* _value;
+               _key = (gchar*) _tmp11_;
+               _value = (gboolean*) _tmp12_;
+               g_variant_builder_add (&_tmp9_, "{?*}", g_variant_new_string (_key), g_variant_new_boolean (*_value));
+       }
+       return g_variant_ref_sink (g_variant_builder_end (&_tmp9_));
+}
+
+static GHashTable*
+_variant_get2 (GVariant* value)
+{
+       GHashTable* _tmp0_;
+       GVariantIter _tmp1_;
+       GVariant* _tmp2_;
+       GVariant* _tmp3_;
+       _tmp0_ = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) NULL);
+       g_variant_iter_init (&_tmp1_, value);
+       while (g_variant_iter_loop (&_tmp1_, "{?*}", &_tmp2_, &_tmp3_)) {
+               g_hash_table_insert (_tmp0_, g_variant_dup_string (_tmp2_, NULL), (gpointer) ((gintptr) g_variant_get_boolean (_tmp3_)));
+       }
+       return _tmp0_;
+}
+
+void
+test2 (void)
+{
+       GHashTable* ht = NULL;
+       GHashFunc _tmp0_;
+       GEqualFunc _tmp1_;
+       GHashTable* _tmp2_;
+       gchar* _tmp3_;
+       gboolean _tmp4_;
+       gboolean* _tmp5_;
+       gchar* _tmp6_;
+       gboolean _tmp7_;
+       gboolean* _tmp8_;
+       GVariant* v = NULL;
+       GVariant* _tmp13_;
+       const gchar* _tmp14_;
+       GHashTable* ht2 = NULL;
+       GHashTable* _tmp15_;
+       guint _tmp16_;
+       guint _tmp17_;
+       gconstpointer _tmp18_;
+       gconstpointer _tmp19_;
+       _tmp0_ = g_str_hash;
+       _tmp1_ = g_str_equal;
+       _tmp2_ = g_hash_table_new_full (_tmp0_, _tmp1_, _g_free0_, _g_free0_);
+       ht = _tmp2_;
+       _tmp3_ = g_strdup ("foo");
+       _tmp4_ = TRUE;
+       _tmp5_ = __bool_dup0 (&_tmp4_);
+       g_hash_table_insert (ht, _tmp3_, _tmp5_);
+       _tmp6_ = g_strdup ("bar");
+       _tmp7_ = FALSE;
+       _tmp8_ = __bool_dup0 (&_tmp7_);
+       g_hash_table_insert (ht, _tmp6_, _tmp8_);
+       _tmp13_ = _variant_new2 (ht);
+       v = _tmp13_;
+       _tmp14_ = g_variant_get_type_string (v);
+       _vala_assert (g_strcmp0 (_tmp14_, "a{sb}") == 0, "v.get_type_string () == \"a{sb}\"");
+       _tmp15_ = _variant_get2 (v);
+       ht2 = _tmp15_;
+       _tmp16_ = g_hash_table_size (ht2);
+       _tmp17_ = _tmp16_;
+       _vala_assert (_tmp17_ == ((guint) 2), "ht2.length == 2");
+       _tmp18_ = g_hash_table_lookup (ht2, "foo");
+       _vala_assert (((gboolean) ((gintptr) _tmp18_)) == TRUE, "ht2[\"foo\"] == true");
+       _tmp19_ = g_hash_table_lookup (ht2, "bar");
+       _vala_assert (((gboolean) ((gintptr) _tmp19_)) == FALSE, "ht2[\"bar\"] == false");
+       _g_hash_table_unref0 (ht2);
+       _g_variant_unref0 (v);
+       _g_hash_table_unref0 (ht);
+}
+
+static void
+_bar_free0_ (gpointer var)
+{
+       (var == NULL) ? NULL : (var = (bar_free (var), NULL));
+}
+
+static gdouble*
+_double_dup (gdouble* self)
+{
+       gdouble* dup;
+       dup = g_new0 (gdouble, 1);
+       memcpy (dup, self, sizeof (gdouble));
+       return dup;
+}
+
+static gpointer
+__double_dup0 (gpointer self)
+{
+       return self ? _double_dup (self) : NULL;
+}
+
+static gpointer
+_bar_dup0 (gpointer self)
+{
+       return self ? bar_dup (self) : NULL;
+}
+
+static GVariant*
+_variant_new3 (GHashTable* value)
+{
+       GVariantBuilder _tmp15_;
+       GHashTableIter _tmp16_;
+       gpointer _tmp17_;
+       gpointer _tmp18_;
+       g_hash_table_iter_init (&_tmp16_, value);
+       g_variant_builder_init (&_tmp15_, G_VARIANT_TYPE ("a{d(i)}"));
+       while (g_hash_table_iter_next (&_tmp16_, &_tmp17_, &_tmp18_)) {
+               gdouble* _key;
+               Bar* _value;
+               GVariantBuilder _tmp19_;
+               _key = (gdouble*) _tmp17_;
+               _value = (Bar*) _tmp18_;
+               g_variant_builder_init (&_tmp19_, G_VARIANT_TYPE_TUPLE);
+               g_variant_builder_add_value (&_tmp19_, g_variant_new_int32 ((*_value).baz));
+               g_variant_builder_add (&_tmp15_, "{?*}", g_variant_new_double (*_key), g_variant_builder_end (&_tmp19_));
+       }
+       return g_variant_ref_sink (g_variant_builder_end (&_tmp15_));
+}
+
+static GHashTable*
+_variant_get3 (GVariant* value)
+{
+       GHashTable* _tmp0_;
+       GVariantIter _tmp1_;
+       GVariant* _tmp2_;
+       GVariant* _tmp3_;
+       _tmp0_ = g_hash_table_new_full (g_double_hash, g_double_equal, (GDestroyNotify) g_free, (GDestroyNotify) foo_free);
+       g_variant_iter_init (&_tmp1_, value);
+       while (g_variant_iter_loop (&_tmp1_, "{?*}", &_tmp2_, &_tmp3_)) {
+               gdouble _tmp4_;
+               Foo _tmp5_;
+               GVariantIter _tmp6_;
+               GVariant* _tmp7_;
+               _tmp4_ = g_variant_get_double (_tmp2_);
+               g_variant_iter_init (&_tmp6_, _tmp3_);
+               _tmp7_ = g_variant_iter_next_value (&_tmp6_);
+               _tmp5_.manam = g_variant_get_int32 (_tmp7_);
+               g_variant_unref (_tmp7_);
+               g_hash_table_insert (_tmp0_, _vala_memdup2 (&_tmp4_, sizeof (gdouble)), _vala_memdup2 (&_tmp5_, sizeof (Foo)));
+       }
+       return _tmp0_;
+}
+
+void
+test3 (void)
+{
+       GHashTable* ht = NULL;
+       GHashFunc _tmp0_;
+       GEqualFunc _tmp1_;
+       GHashTable* _tmp2_;
+       gdouble _tmp3_;
+       gdouble* _tmp4_;
+       Bar _tmp5_ = {0};
+       Bar* _tmp6_;
+       gdouble _tmp7_;
+       gdouble* _tmp8_;
+       Bar _tmp9_ = {0};
+       Bar* _tmp10_;
+       gdouble _tmp11_;
+       gdouble* _tmp12_;
+       Bar _tmp13_ = {0};
+       Bar* _tmp14_;
+       GVariant* v = NULL;
+       GVariant* _tmp20_;
+       const gchar* _tmp21_;
+       GHashTable* ht2 = NULL;
+       GHashTable* _tmp22_;
+       guint _tmp23_;
+       guint _tmp24_;
+       gdouble _tmp25_;
+       gconstpointer _tmp26_;
+       _tmp0_ = g_double_hash;
+       _tmp1_ = g_double_equal;
+       _tmp2_ = g_hash_table_new_full (_tmp0_, _tmp1_, _g_free0_, _bar_free0_);
+       ht = _tmp2_;
+       _tmp3_ = 0.0;
+       _tmp4_ = __double_dup0 (&_tmp3_);
+       _tmp5_.baz = 0;
+       _tmp6_ = _bar_dup0 (&_tmp5_);
+       g_hash_table_insert (ht, _tmp4_, _tmp6_);
+       _tmp7_ = 42.0;
+       _tmp8_ = __double_dup0 (&_tmp7_);
+       _tmp9_.baz = 1;
+       _tmp10_ = _bar_dup0 (&_tmp9_);
+       g_hash_table_insert (ht, _tmp8_, _tmp10_);
+       _tmp11_ = 3.14;
+       _tmp12_ = __double_dup0 (&_tmp11_);
+       _tmp13_.baz = 2;
+       _tmp14_ = _bar_dup0 (&_tmp13_);
+       g_hash_table_insert (ht, _tmp12_, _tmp14_);
+       _tmp20_ = _variant_new3 (ht);
+       v = _tmp20_;
+       _tmp21_ = g_variant_get_type_string (v);
+       _vala_assert (g_strcmp0 (_tmp21_, "a{d(i)}") == 0, "v.get_type_string () == \"a{d(i)}\"");
+       _tmp22_ = _variant_get3 (v);
+       ht2 = _tmp22_;
+       _tmp23_ = g_hash_table_size (ht2);
+       _tmp24_ = _tmp23_;
+       _vala_assert (_tmp24_ == ((guint) 3), "ht2.length == 3");
+       _tmp25_ = 3.14;
+       _tmp26_ = g_hash_table_lookup (ht2, &_tmp25_);
+       _vala_assert ((*((Foo*) _tmp26_)).manam == 2, "ht2[3.14].manam == 2");
+       _g_hash_table_unref0 (ht2);
+       _g_variant_unref0 (v);
+       _g_hash_table_unref0 (ht);
+}
+
+static void
+_vala_main (void)
+{
+       test1 ();
+       test2 ();
+       test3 ();
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
+static inline gpointer
+_vala_memdup2 (gconstpointer mem,
+               gsize byte_size)
+{
+       gpointer new_mem;
+       if (mem && byte_size != 0) {
+               new_mem = g_malloc (byte_size);
+               memcpy (new_mem, mem, byte_size);
+       } else {
+               new_mem = NULL;
+       }
+       return new_mem;
+}
+
diff --git a/tests/basic-types/gvariants-hashtable-boxed.vala b/tests/basic-types/gvariants-hashtable-boxed.vala
new file mode 100644 (file)
index 0000000..66f7dc0
--- /dev/null
@@ -0,0 +1,52 @@
+struct Foo {
+       int manam;
+}
+
+struct Bar {
+       int baz;
+       static int irrelevant;
+}
+
+void test1 () {
+       var ht = new HashTable<uint64?, Foo?> (int64_hash, int64_equal);
+       ht[123] = { 42 };
+       Variant v = ht;
+       assert (v.get_type_string () == "a{t(i)}");
+       assert (v.print (true) == "{uint64 123: (42,)}");
+
+       var ht2 = (HashTable<uint64?, Bar?>) v;
+       assert (ht2.length == 1);
+       assert (ht2[123].baz == 42);
+}
+
+void test2 () {
+       var ht = new HashTable<string, bool?> (str_hash, str_equal);
+       ht["foo"] = true;
+       ht["bar"] = false;
+       Variant v = ht;
+       assert (v.get_type_string () == "a{sb}");
+
+       var ht2 = (HashTable<string?, bool>) v;
+       assert (ht2.length == 2);
+       assert (ht2["foo"] == true);
+       assert (ht2["bar"] == false);
+}
+
+void test3 () {
+       var ht = new HashTable<double?, Bar?> (double_hash, double_equal);
+       ht[0.0] = { 0 };
+       ht[42.0] = { 1 };
+       ht[3.14] = { 2 };
+       Variant v = ht;
+       assert (v.get_type_string () == "a{d(i)}");
+
+       var ht2 = (HashTable<double?, Foo?>) v;
+       assert (ht2.length == 3);
+       assert (ht2[3.14].manam == 2);
+}
+
+void main () {
+       test1 ();
+       test2 ();
+       test3 ();
+}
index ffc46698632b942af6190ffd49bebe5a4d331d2e..acad937e3c9eafacb72a07daa983ae1016ad6dda 100644 (file)
@@ -49,11 +49,8 @@ VALA_EXTERN void foo_copy (const Foo* self,
 VALA_EXTERN void foo_destroy (Foo* self);
 G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (Foo, foo_destroy)
 static void _vala_main (void);
-static gboolean* _bool_dup (gboolean* self);
 static gboolean* _variant_get1 (GVariant* value);
-static gint16* _int16_dup (gint16* self);
 static gint16* _variant_get2 (GVariant* value);
-static gint32* _int32_dup (gint32* self);
 static gint32* _variant_get3 (GVariant* value);
 static gboolean _int32_equal (const gint32 * s1,
                        const gint32 * s2);
@@ -137,88 +134,37 @@ foo_get_type (void)
        return foo_type_id__once;
 }
 
-static gboolean*
-_bool_dup (gboolean* self)
-{
-       gboolean* dup;
-       dup = g_new0 (gboolean, 1);
-       memcpy (dup, self, sizeof (gboolean));
-       return dup;
-}
-
-static gpointer
-__bool_dup0 (gpointer self)
-{
-       return self ? _bool_dup (self) : NULL;
-}
-
 static gboolean*
 _variant_get1 (GVariant* value)
 {
        if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) {
                gboolean _tmp0_;
-               gboolean* _tmp1_;
                _tmp0_ = g_variant_get_boolean (value);
-               _tmp1_ = __bool_dup0 (&_tmp0_);
-               return _tmp1_;
+               return _vala_memdup2 (&_tmp0_, sizeof (gboolean));
        } else {
                return NULL;
        }
 }
 
-static gint16*
-_int16_dup (gint16* self)
-{
-       gint16* dup;
-       dup = g_new0 (gint16, 1);
-       memcpy (dup, self, sizeof (gint16));
-       return dup;
-}
-
-static gpointer
-__int16_dup0 (gpointer self)
-{
-       return self ? _int16_dup (self) : NULL;
-}
-
 static gint16*
 _variant_get2 (GVariant* value)
 {
        if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_INT16)) {
                gint16 _tmp0_;
-               gint16* _tmp1_;
                _tmp0_ = g_variant_get_int16 (value);
-               _tmp1_ = __int16_dup0 (&_tmp0_);
-               return _tmp1_;
+               return _vala_memdup2 (&_tmp0_, sizeof (gint16));
        } else {
                return NULL;
        }
 }
 
-static gint32*
-_int32_dup (gint32* self)
-{
-       gint32* dup;
-       dup = g_new0 (gint32, 1);
-       memcpy (dup, self, sizeof (gint32));
-       return dup;
-}
-
-static gpointer
-__int32_dup0 (gpointer self)
-{
-       return self ? _int32_dup (self) : NULL;
-}
-
 static gint32*
 _variant_get3 (GVariant* value)
 {
        if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) {
                gint32 _tmp0_;
-               gint32* _tmp1_;
                _tmp0_ = g_variant_get_int32 (value);
-               _tmp1_ = __int32_dup0 (&_tmp0_);
-               return _tmp1_;
+               return _vala_memdup2 (&_tmp0_, sizeof (gint32));
        } else {
                return NULL;
        }
@@ -255,10 +201,8 @@ _variant_get5 (GVariant* value)
 {
        if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) {
                gboolean _tmp0_;
-               gboolean* _tmp1_;
                _tmp0_ = g_variant_get_boolean (value);
-               _tmp1_ = __bool_dup0 (&_tmp0_);
-               return _tmp1_;
+               return _vala_memdup2 (&_tmp0_, sizeof (gboolean));
        } else {
                return NULL;
        }
@@ -285,10 +229,8 @@ _variant_get6 (GVariant* value)
 {
        if (value && g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) {
                gint32 _tmp0_;
-               gint32* _tmp1_;
                _tmp0_ = g_variant_get_int32 (value);
-               _tmp1_ = __int32_dup0 (&_tmp0_);
-               return _tmp1_;
+               return _vala_memdup2 (&_tmp0_, sizeof (gint32));
        } else {
                return NULL;
        }
@@ -307,8 +249,6 @@ _variant_get7 (GVariant* value,
                gint _tmp1__length1;
                GVariantIter _tmp2_;
                GVariant* _tmp3_;
-               gchar** _tmp4_;
-               gint _tmp4__length1;
                _tmp1_ = g_new (gchar*, 5);
                _tmp1__length = 0;
                _tmp1__size = 4;
@@ -325,9 +265,7 @@ _variant_get7 (GVariant* value,
                *result_length1 = _tmp1__length1;
                _tmp1_[_tmp1__length] = NULL;
                g_variant_type_free (_tmp0_);
-               _tmp4_ = _tmp1_;
-               _tmp4__length1 = -1;
-               return _tmp4_;
+               return _tmp1_;
        } else {
                g_variant_type_free (_tmp0_);
                return NULL;
@@ -378,7 +316,6 @@ _variant_get9 (GVariant* value)
                GVariant* _tmp3_;
                GVariant* _tmp4_;
                GVariant* _tmp5_;
-               Foo* _tmp6_;
                g_variant_iter_init (&_tmp2_, value);
                _tmp3_ = g_variant_iter_next_value (&_tmp2_);
                _tmp1_.s = g_variant_dup_string (_tmp3_, NULL);
@@ -390,8 +327,7 @@ _variant_get9 (GVariant* value)
                _tmp1_.b = g_variant_get_boolean (_tmp5_);
                g_variant_unref (_tmp5_);
                g_variant_type_free (_tmp0_);
-               _tmp6_ = _vala_memdup2 (&_tmp1_, sizeof (Foo));
-               return _tmp6_;
+               return _vala_memdup2 (&_tmp1_, sizeof (Foo));
        } else {
                g_variant_type_free (_tmp0_);
                return NULL;
@@ -433,15 +369,13 @@ _variant_get10 (GVariant* value)
                GVariantIter _tmp2_;
                GVariant* _tmp3_;
                GVariant* _tmp4_;
-               GHashTable* _tmp5_;
                _tmp1_ = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free);
                g_variant_iter_init (&_tmp2_, value);
                while (g_variant_iter_loop (&_tmp2_, "{?*}", &_tmp3_, &_tmp4_)) {
                        g_hash_table_insert (_tmp1_, g_variant_dup_string (_tmp3_, NULL), g_variant_dup_string (_tmp4_, NULL));
                }
                g_variant_type_free (_tmp0_);
-               _tmp5_ = _tmp1_;
-               return _tmp5_;
+               return _tmp1_;
        } else {
                g_variant_type_free (_tmp0_);
                return NULL;
@@ -458,15 +392,13 @@ _variant_get11 (GVariant* value)
                GVariantIter _tmp2_;
                GVariant* _tmp3_;
                GVariant* _tmp4_;
-               GHashTable* _tmp5_;
                _tmp1_ = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) NULL, (GDestroyNotify) g_free);
                g_variant_iter_init (&_tmp2_, value);
                while (g_variant_iter_loop (&_tmp2_, "{?*}", &_tmp3_, &_tmp4_)) {
                        g_hash_table_insert (_tmp1_, (gpointer) ((gintptr) g_variant_get_int32 (_tmp3_)), g_variant_dup_string (_tmp4_, NULL));
                }
                g_variant_type_free (_tmp0_);
-               _tmp5_ = _tmp1_;
-               return _tmp5_;
+               return _tmp1_;
        } else {
                g_variant_type_free (_tmp0_);
                return NULL;