[perl-Glib] Add Glib::Variant and Glib::VariantType



commit d0c52b8bb864a3377403623589f1c0cd8482717b
Author: Torsten Schönfeld <kaffeetisch gmx de>
Date:   Sun Jan 4 18:05:05 2015 +0100

    Add Glib::Variant and Glib::VariantType
    
    Wrapping the majority of the GVariant and GVariantType API.

 GError.xs      |    6 +
 GVariant.xs    |  685 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Glib.xs        |    3 +
 Makefile.PL    |    4 +
 gperl-gtypes.c |   39 ++++
 gperl-gtypes.h |    5 +
 gperl.h        |   16 ++-
 lib/Glib.pm    |  149 ++++++++++++
 t/variant.t    |  338 ++++++++++++++++++++++++++++
 typemap        |    8 +
 10 files changed, 1252 insertions(+), 1 deletions(-)
---
diff --git a/GError.xs b/GError.xs
index d358704..1de5306 100644
--- a/GError.xs
+++ b/GError.xs
@@ -369,6 +369,12 @@ BOOT:
        gperl_register_error_domain (G_THREAD_ERROR,
                                     GPERL_TYPE_THREAD_ERROR,
                                     "Glib::Thread::Error");
+#if GLIB_CHECK_VERSION (2, 24, 0)
+       /* gvariant.h */
+       gperl_register_error_domain (G_VARIANT_PARSE_ERROR,
+                                    GPERL_TYPE_VARIANT_PARSE_ERROR,
+                                    "Glib::Variant::ParseError");
+#endif
 
        PERL_UNUSED_VAR (file);
 
diff --git a/GVariant.xs b/GVariant.xs
new file mode 100644
index 0000000..e359829
--- /dev/null
+++ b/GVariant.xs
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2014 by the gtk2-perl team (see the file AUTHORS for the full
+ * list)
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "gperl.h"
+
+/* --- GVariant --------------------------------------------------------------*/
+
+/* --- basic wrappers --- */
+
+static SV *
+variant_to_sv (GVariant * variant, gboolean own)
+{
+       SV * sv;
+       SV * rv;
+       HV * stash;
+
+       if (!variant)
+               return &PL_sv_undef;
+
+       sv = newSV (0);
+       _gperl_attach_mg (sv, variant);
+
+       if (own) {
+#if GLIB_CHECK_VERSION (2, 30, 0)
+               g_variant_take_ref (variant);
+#else
+               if (g_variant_is_floating (variant)) {
+                       g_variant_ref_sink (variant);
+               }
+#endif
+       } else {
+               g_variant_ref (variant);
+       }
+
+       rv = newRV_noinc (sv);
+       stash = gv_stashpv ("Glib::Variant", TRUE);
+       sv_bless (rv, stash);
+
+       return rv;
+}
+
+static GVariant *
+sv_to_variant (SV * sv)
+{
+       MAGIC * mg;
+       if (!gperl_sv_is_ref (sv) || !(mg = _gperl_find_mg (SvRV (sv))))
+               return NULL;
+       return (GVariant *) mg->mg_ptr;
+}
+
+/* --- GValue wrappers --- */
+
+static SV *
+wrap_variant (const GValue * value)
+{
+       return variant_to_sv (g_value_get_variant (value), FALSE);
+}
+
+static void
+unwrap_variant (GValue * value, SV * sv)
+{
+       g_value_set_variant (value, sv_to_variant (sv));
+}
+
+static GPerlValueWrapperClass variant_wrapper_class = { wrap_variant, unwrap_variant };
+
+/* --- typemap glue --- */
+
+SV *
+newSVGVariant (GVariant * variant)
+{
+       return variant_to_sv (variant, FALSE);
+}
+
+SV *
+newSVGVariant_noinc (GVariant * variant)
+{
+       return variant_to_sv (variant, TRUE);
+}
+
+GVariant *
+SvGVariant (SV * sv)
+{
+       return sv_to_variant (sv);
+}
+
+/* --- GVariantType --------------------------------------------------------- */
+
+/* --- boxed wrappers ---*/
+
+static GPerlBoxedWrapperClass default_boxed_wrapper_class;
+static GPerlBoxedWrapperClass variant_type_wrapper_class;
+
+static gpointer
+unwrap_variant_type (GType gtype, const char * package, SV * sv)
+{
+       if (!gperl_sv_is_ref (sv)) {
+               GVariantType * vtype;
+               vtype = g_variant_type_new (SvPV_nolen (sv));
+               sv = default_boxed_wrapper_class.wrap (gtype, package, vtype, TRUE);
+               /* fall through */
+       }
+       return default_boxed_wrapper_class.unwrap (gtype, package, sv);
+}
+
+/* --- typemap glue --- */
+
+SV *
+newSVGVariantType (const GVariantType * type)
+{
+       if (!type)
+               return &PL_sv_undef;
+       return gperl_new_boxed ((gpointer) type, G_TYPE_VARIANT_TYPE, FALSE);
+}
+
+SV *
+newSVGVariantType_own (const GVariantType * type)
+{
+       return gperl_new_boxed ((gpointer) type, G_TYPE_VARIANT_TYPE, TRUE);
+}
+
+const GVariantType *
+SvGVariantType (SV * sv)
+{
+       if (!gperl_sv_is_defined (sv))
+               return NULL;
+       return gperl_get_boxed_check (sv, G_TYPE_VARIANT_TYPE);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* --- helpers ---*/
+
+static void
+sv_to_variant_array (SV * sv, GVariant *** array_p, gsize * n_p)
+{
+       AV * av;
+       gsize i;
+       if (!gperl_sv_is_array_ref (sv))
+               croak ("Expected an array reference for 'children'");
+       av = (AV *) SvRV (sv);
+       *n_p = av_len (av) + 1;
+       *array_p = g_new0 (GVariant *, *n_p);
+       for (i = 0; i < *n_p; i++) {
+               SV ** svp = av_fetch (av, i, 0);
+               if (svp)
+                       (*array_p)[i] = SvGVariant (*svp);
+       }
+}
+
+static void
+sv_to_variant_type_array (SV * sv, const GVariantType *** array_p, gint * n_p)
+{
+       AV * av;
+       gint i;
+       if (!gperl_sv_is_array_ref (sv))
+               croak ("Expected an array reference for 'items'");
+       av = (AV *) SvRV (sv);
+       *n_p = av_len (av) + 1;
+       *array_p = g_new0 (const GVariantType *, *n_p);
+       for (i = 0; i < *n_p; i++) {
+               SV ** svp = av_fetch (av, i, 0);
+               if (svp)
+                       (*array_p)[i] = SvGVariantType (*svp);
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+MODULE = Glib::Variant PACKAGE = Glib::Variant PREFIX = g_variant_
+
+=for object Glib::Variant strongly typed value datatype
+=cut
+
+=for position SYNOPSIS
+
+=head1 SYNOPSIS
+
+  my $v = Glib::Variant->new ('as', ['GTK+', 'Perl']);
+  my $aref = $v->get ('as');
+
+=for position DESCRIPTION
+
+=head1 DESCRIPTION
+
+There are two sets of APIs for creating and dealing with C<Glib::Variant>s: the
+low-level API described below under L</METHODS>, and the convenience API
+described in this section.
+
+=head2 CONVENIENCE API
+
+=over
+
+=item variant = Glib::Variant->new ($format_string, $value)
+
+=item (variant1, ...) = Glib::Variant->new ($format_string, $value1, ...)
+
+Constructs a variant from C<$format_string> and C<$value>.  Also supports
+constructing multiple variants when the format string is a concatenation of
+multiple types.
+
+=item value = $variant->get ($format_string)
+
+Deconstructs C<$variant> according to C<$format_string>.
+
+=back
+
+The following symbols are currently supported in format strings:
+
+  +------------------------------+---------------------------------+
+  |            Symbol            |             Meaning             |
+  +------------------------------+---------------------------------+
+  | b, y, n, q, i, u, x, t, h, d | Boolean, byte and numeric types |
+  | s, o, g                      | String types                    |
+  | v                            | Variant types                   |
+  | a                            | Arrays                          |
+  | m                            | Maybe types                     |
+  | ()                           | Tuples                          |
+  | {}                           | Dictionary entries              |
+  +------------------------------+---------------------------------+
+
+Note that if a format string specifies an array, a tuple or a dictionary entry
+("a", "()" or "{}"), then array references are expected by C<new> and produced
+by C<get>.  For arrays of dictionary entries ("a{}"), hash references are also
+supported by C<new> and handled as you would expect.
+
+For a complete specification, see the documentation at
+
+=over
+
+=item L<https://developer.gnome.org/glib/stable/glib-GVariantType.html>
+
+=item L<https://developer.gnome.org/glib/stable/glib-GVariant.html>
+
+=item L<https://developer.gnome.org/glib/stable/gvariant-format-strings.html>
+
+=item L<https://developer.gnome.org/glib/stable/gvariant-text.html>
+
+=back
+
+=cut
+
+=for see_also Glib::VariantType
+=cut
+
+BOOT:
+       gperl_register_fundamental_full (G_TYPE_VARIANT, "Glib::Variant",
+                                        &variant_wrapper_class);
+       default_boxed_wrapper_class = variant_type_wrapper_class =
+               * gperl_default_boxed_wrapper_class ();
+       variant_type_wrapper_class.unwrap = unwrap_variant_type;
+       gperl_register_boxed (G_TYPE_VARIANT_TYPE, "Glib::VariantType",
+                             &variant_type_wrapper_class);
+
+const GVariantType * g_variant_get_type (GVariant *value);
+
+const gchar * g_variant_get_type_string (GVariant *value);
+
+gboolean g_variant_is_of_type (GVariant *value, const GVariantType *type);
+
+gboolean g_variant_is_container (GVariant *value);
+
+const char * g_variant_classify (GVariant *value);
+    PREINIT:
+       GVariantClass vclass;
+    CODE:
+       vclass = g_variant_classify (value);
+       RETVAL = (const char *) &vclass;
+    OUTPUT:
+       RETVAL
+
+GVariant_noinc * g_variant_new_boolean (class, gboolean value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_byte (class, guchar value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_int16 (class, gint16 value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_uint16 (class, guint16 value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_int32 (class, gint32 value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_uint32 (class, guint32 value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_int64 (class, gint64 value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_uint64 (class, guint64 value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_handle (class, gint32 value);
+    C_ARGS:
+       value
+
+GVariant_noinc * g_variant_new_double (class, gdouble value);
+    C_ARGS:
+       value
+
+# GVariant * g_variant_new_take_string (gchar *string);
+GVariant_noinc * g_variant_new_string (class, const gchar *string);
+    C_ARGS:
+       string
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_38
+# GVariant * g_variant_new_printf (const gchar *format_string, ...) G_GNUC_PRINTF (1, 2);
+
+GVariant_noinc * g_variant_new_object_path (class, const gchar *object_path);
+    C_ARGS:
+       object_path
+
+gboolean g_variant_is_object_path (const gchar *string);
+
+GVariant_noinc * g_variant_new_signature (class, const gchar *signature);
+    C_ARGS:
+       signature
+
+gboolean g_variant_is_signature (const gchar *string);
+
+GVariant_noinc * g_variant_new_variant (class, GVariant *value);
+    C_ARGS:
+       value
+
+# FIXME:
+# GVariant * g_variant_new_strv (const gchar * const *strv, gssize length);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_30
+# GVariant * g_variant_new_objv (const gchar * const *strv, gssize length);
+
+#if GLIB_CHECK_VERSION (2, 26, 0)
+
+GVariant_noinc * g_variant_new_bytestring (class, const char_byte * string);
+    C_ARGS:
+       string
+
+# FIXME:
+# GVariant * g_variant_new_bytestring_array (const gchar * const *strv, gssize length);
+
+#endif
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_32
+# GVariant * g_variant_new_fixed_array (const GVariantType *element_type, gconstpointer elements, gsize 
n_elements, gsize element_size);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_36
+# GVariant * g_variant_new_from_bytes (const GVariantType *type, GBytes *bytes, gboolean trusted);
+
+# FIXME:
+# GVariant * g_variant_new_from_data (const GVariantType *type, gconstpointer data, gsize size, gboolean 
trusted, GDestroyNotify notify, gpointer user_data);
+
+gboolean g_variant_get_boolean (GVariant *value);
+
+guchar g_variant_get_byte (GVariant *value);
+
+gint16 g_variant_get_int16 (GVariant *value);
+
+guint16 g_variant_get_uint16 (GVariant *value);
+
+gint32 g_variant_get_int32 (GVariant *value);
+
+guint32 g_variant_get_uint32 (GVariant *value);
+
+gint64 g_variant_get_int64 (GVariant *value);
+
+guint64 g_variant_get_uint64 (GVariant *value);
+
+gint32 g_variant_get_handle (GVariant *value);
+
+gdouble g_variant_get_double (GVariant *value);
+
+GVariant_noinc * g_variant_get_variant (GVariant *value);
+
+# gchar * g_variant_dup_string (GVariant *value, gsize *length);
+const gchar * g_variant_get_string (GVariant *value);
+    C_ARGS:
+       value, NULL
+
+# FIXME:
+# gchar ** g_variant_dup_strv (GVariant *value, gsize *length);
+# const gchar ** g_variant_get_strv (GVariant *value, gsize *length);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_30
+# gchar ** g_variant_dup_objv (GVariant *value, gsize *length);
+# const gchar ** g_variant_get_objv (GVariant *value, gsize *length);
+
+#if GLIB_CHECK_VERSION (2, 26, 0)
+
+# gchar * g_variant_dup_bytestring (GVariant *value, gsize *length);
+const char * g_variant_get_bytestring (GVariant *value);
+
+# FIXME:
+# gchar ** g_variant_dup_bytestring_array (GVariant *value, gsize *length);
+# const gchar ** g_variant_get_bytestring_array (GVariant *value, gsize *length);
+
+#endif
+
+GVariant_noinc * g_variant_new_maybe (class, const GVariantType *child_type, GVariant *child);
+    C_ARGS:
+       child_type, child
+
+GVariant * g_variant_new_array (class, const GVariantType *child_type, SV *children);
+    PREINIT:
+       GVariant ** children_c;
+       gsize n_children;
+    CODE:
+       sv_to_variant_array (children, &children_c, &n_children);
+       RETVAL = g_variant_new_array (child_type, children_c, n_children);
+       g_free (children_c);
+    OUTPUT:
+       RETVAL
+
+GVariant * g_variant_new_tuple (class, SV *children);
+    PREINIT:
+       GVariant ** children_c;
+       gsize n_children;
+    CODE:
+       sv_to_variant_array (children, &children_c, &n_children);
+       RETVAL = g_variant_new_tuple (children_c, n_children);
+       g_free (children_c);
+    OUTPUT:
+       RETVAL
+
+GVariant_noinc * g_variant_new_dict_entry (class, GVariant *key, GVariant *value);
+    C_ARGS:
+       key, value
+
+GVariant_noinc * g_variant_get_maybe (GVariant *value);
+
+gsize g_variant_n_children (GVariant *value);
+
+# void g_variant_get_child (GVariant *value, gsize index_, const gchar *format_string, ...);
+
+GVariant_noinc * g_variant_get_child_value (GVariant *value, gsize index_);
+
+# gboolean g_variant_lookup (GVariant *dictionary, const gchar *key, const gchar *format_string, ...);
+GVariant_noinc * g_variant_lookup_value (GVariant *dictionary, const gchar *key, const GVariantType 
*expected_type);
+
+# FIXME:
+# gconstpointer g_variant_get_fixed_array (GVariant *value, gsize *n_elements, gsize element_size);
+
+gsize g_variant_get_size (GVariant *value);
+
+# FIXME:
+# gconstpointer g_variant_get_data (GVariant *value);
+# GLIB_AVAILABLE_IN_2_36
+# GBytes * g_variant_get_data_as_bytes (GVariant *value);
+# void g_variant_store (GVariant *value, gpointer data);
+
+# GString * g_variant_print_string (GVariant *value, GString *string, gboolean type_annotate);
+gchar_own * g_variant_print (GVariant *value, gboolean type_annotate);
+
+guint g_variant_hash (const GVariant * value);
+
+gboolean g_variant_equal (const GVariant * one, const GVariant * two);
+
+#if GLIB_CHECK_VERSION (2, 26, 0)
+
+gint g_variant_compare (const GVariant * one, const GVariant * two);
+
+#endif
+
+GVariant_noinc * g_variant_get_normal_form (GVariant *value);
+
+gboolean g_variant_is_normal_form (GVariant *value);
+
+GVariant_noinc * g_variant_byteswap (GVariant *value);
+
+# FIXME:
+# GLIB_AVAILABLE_IN_2_36
+# GVariant * g_variant_new_from_bytes (const GVariantType *type, GBytes *bytes, gboolean trusted);
+
+# FIXME:
+# GVariant * g_variant_new_from_data (const GVariantType *type, gconstpointer data, gsize size, gboolean 
trusted, GDestroyNotify notify, gpointer user_data);
+
+void
+DESTROY (GVariant * variant)
+    CODE:
+       g_variant_unref (variant);
+
+# --------------------------------------------------------------------------- #
+
+# GVariantIter * g_variant_iter_new (GVariant *value);
+# gsize g_variant_iter_init (GVariantIter *iter, GVariant *value);
+# GVariantIter * g_variant_iter_copy (GVariantIter *iter);
+# gsize g_variant_iter_n_children (GVariantIter *iter);
+# void g_variant_iter_free (GVariantIter *iter);
+# GVariant * g_variant_iter_next_value (GVariantIter *iter);
+# gboolean g_variant_iter_next (GVariantIter *iter, const gchar *format_string, ...);
+# gboolean g_variant_iter_loop (GVariantIter *iter, const gchar *format_string, ...);
+
+# --------------------------------------------------------------------------- #
+
+# GLIB_AVAILABLE_IN_2_40 {
+#   GVariantDict * g_variant_dict_new (GVariant *from_asv);
+#   void g_variant_dict_init (GVariantDict *dict, GVariant *from_asv);
+#   gboolean g_variant_dict_lookup (GVariantDict *dict, const gchar *key, const gchar *format_string, ...);
+#   GVariant * g_variant_dict_lookup_value (GVariantDict *dict, const gchar *key, const GVariantType 
*expected_type);
+#   gboolean g_variant_dict_contains (GVariantDict *dict, const gchar *key);
+#   void g_variant_dict_insert (GVariantDict *dict, const gchar *key, const gchar *format_string, ...);
+#   void g_variant_dict_insert_value (GVariantDict *dict, const gchar *key, GVariant *value);
+#   gboolean g_variant_dict_remove (GVariantDict *dict, const gchar *key);
+#   void g_variant_dict_clear (GVariantDict *dict);
+#   GVariant * g_variant_dict_end (GVariantDict *dict);
+#   GVariantDict * g_variant_dict_ref (GVariantDict *dict);
+#   void g_variant_dict_unref (GVariantDict *dict);
+# }
+
+# --------------------------------------------------------------------------- #
+
+# GVariantBuilder * g_variant_builder_new (const GVariantType *type);
+# void g_variant_builder_unref (GVariantBuilder *builder);
+# GVariantBuilder * g_variant_builder_ref (GVariantBuilder *builder);
+# void g_variant_builder_init (GVariantBuilder *builder, const GVariantType *type);
+# GVariant * g_variant_builder_end (GVariantBuilder *builder);
+# void g_variant_builder_clear (GVariantBuilder *builder);
+# void g_variant_builder_open (GVariantBuilder *builder, const GVariantType *type);
+# void g_variant_builder_close (GVariantBuilder *builder);
+# void g_variant_builder_add_value (GVariantBuilder *builder, GVariant *value);
+# void g_variant_builder_add (GVariantBuilder *builder, const gchar *format_string, ...);
+# void g_variant_builder_add_parsed (GVariantBuilder *builder, const gchar *format, ...);
+
+# --------------------------------------------------------------------------- #
+
+# These are re-created in lib/Glib.pm.
+# GVariant * g_variant_new (const gchar *format_string, ...);
+# GVariant * g_variant_new_va (const gchar *format_string, const gchar **endptr, va_list *app);
+# void g_variant_get (GVariant *value, const gchar *format_string, ...);
+# void g_variant_get_va (GVariant *value, const gchar *format_string, const gchar **endptr, va_list *app);
+# GLIB_AVAILABLE_IN_2_34
+# gboolean g_variant_check_format_string (GVariant *value, const gchar *format_string, gboolean copy_only);
+
+# --------------------------------------------------------------------------- #
+
+=for apidoc __function__ __gerror__
+=cut
+GVariant_noinc *
+g_variant_parse (const GVariantType *type, const gchar *text)
+    PREINIT:
+       GError *error = NULL;
+    CODE:
+       RETVAL = g_variant_parse (type, text, NULL, NULL, &error);
+       if (error)
+               gperl_croak_gerror (NULL, error);
+    OUTPUT:
+       RETVAL
+
+# GVariant * g_variant_new_parsed (const gchar *format, ...);
+# GVariant * g_variant_new_parsed_va (const gchar *format, va_list *app);
+# GLIB_AVAILABLE_IN_2_40
+# gchar * g_variant_parse_error_print_context (GError *error, const gchar *source_str);
+
+# --------------------------------------------------------------------------- #
+
+MODULE = Glib::Variant PACKAGE = Glib::VariantType     PREFIX = g_variant_type_
+
+=for see_also Glib::Variant
+=cut
+
+=for apidoc __function__
+=cut
+gboolean g_variant_type_string_is_valid (const gchar *type_string);
+
+=for apidoc
+=for signature (type_string, rest) = Glib::VariantType::string_scan ($string)
+Scans the start of C<$string> for a complete type string and extracts it.  If
+no type string can be found, an exception is thrown.
+=cut
+# gboolean g_variant_type_string_scan (const gchar *string, const gchar *limit, const gchar **endptr);
+void
+g_variant_type_string_scan (const char *string)
+    PREINIT:
+       const char *limit = NULL;
+       const char *endptr = NULL;
+    PPCODE:
+       if (!g_variant_type_string_scan (string, limit, &endptr))
+               croak ("Could not find type string at the start of '%s'",
+                      string);
+       PUSHs (sv_2mortal (newSVpvn (string, endptr-string)));
+        if (endptr && *endptr)
+               XPUSHs (sv_2mortal (newSVpv (endptr, 0)));
+
+GVariantType_own * g_variant_type_new (class, const gchar *type_string);
+    C_ARGS:
+       type_string
+
+# const gchar * g_variant_type_peek_string (const GVariantType *type);
+# gchar * g_variant_type_dup_string (const GVariantType  *type);
+SV * g_variant_type_get_string (const GVariantType *type)
+    PREINIT:
+       const char * string;
+    CODE:
+       string = g_variant_type_peek_string (type);
+       RETVAL = newSVpv (string, g_variant_type_get_string_length (type));
+    OUTPUT:
+       RETVAL
+
+gboolean g_variant_type_is_definite (const GVariantType *type);
+
+gboolean g_variant_type_is_container (const GVariantType *type);
+
+gboolean g_variant_type_is_basic (const GVariantType *type);
+
+gboolean g_variant_type_is_maybe (const GVariantType *type);
+
+gboolean g_variant_type_is_array (const GVariantType *type);
+
+gboolean g_variant_type_is_tuple (const GVariantType *type);
+
+gboolean g_variant_type_is_dict_entry (const GVariantType *type);
+
+gboolean g_variant_type_is_variant (const GVariantType *type);
+
+guint g_variant_type_hash (const GVariantType *type);
+
+gboolean g_variant_type_equal (const GVariantType *type1, const GVariantType *type2);
+
+gboolean g_variant_type_is_subtype_of (const GVariantType *type, const GVariantType *supertype);
+
+const GVariantType * g_variant_type_element (const GVariantType *type);
+
+const GVariantType * g_variant_type_first (const GVariantType *type);
+
+const GVariantType * g_variant_type_next (const GVariantType *type);
+
+gsize g_variant_type_n_items (const GVariantType *type);
+
+const GVariantType * g_variant_type_key (const GVariantType *type);
+
+const GVariantType * g_variant_type_value (const GVariantType *type);
+
+GVariantType_own * g_variant_type_new_array (class, const GVariantType *element);
+    C_ARGS:
+       element
+
+GVariantType_own * g_variant_type_new_maybe (class, const GVariantType *element);
+    C_ARGS:
+       element
+
+GVariantType_own * g_variant_type_new_tuple (class, SV *items);
+    PREINIT:
+       const GVariantType ** items_c;
+       gint n_items;
+    CODE:
+       sv_to_variant_type_array (items, &items_c, &n_items);
+       RETVAL = g_variant_type_new_tuple (items_c, n_items);
+       g_free (items_c);
+    OUTPUT:
+       RETVAL
+
+GVariantType_own * g_variant_type_new_dict_entry (class, const GVariantType *key, const GVariantType *value);
+    C_ARGS:
+       key, value
diff --git a/Glib.xs b/Glib.xs
index 8466bb7..8d54088 100644
--- a/Glib.xs
+++ b/Glib.xs
@@ -470,6 +470,9 @@ BOOT:
 #if GLIB_CHECK_VERSION (2, 12, 0)
        GPERL_CALL_BOOT (boot_Glib__BookmarkFile);
 #endif /* GLIB_CHECK_VERSION (2, 12, 0) */
+#if GLIB_CHECK_VERSION (2, 24, 0)
+       GPERL_CALL_BOOT (boot_Glib__Variant);
+#endif /* GLIB_CHECK_VERSION (2, 24, 0) */
        /* make sure that we're running/linked against a version at least as 
         * new as we built against, otherwise bad things will happen. */
        if ((((int)glib_major_version) < GLIB_MAJOR_VERSION)
diff --git a/Makefile.PL b/Makefile.PL
index 6a3936d..bf99935 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -89,6 +89,10 @@ if (ExtUtils::PkgConfig->atleast_version ('glib-2.0', '2.12.0')) {
        push @xs_files, 'GBookmarkFile.xs';
 }
 
+if (ExtUtils::PkgConfig->atleast_version ('glib-2.0', '2.24.0')) {
+       push @xs_files, 'GVariant.xs';
+}
+
 my %meta_merge = (
         q(meta-spec)          => {
             version => '2',
diff --git a/gperl-gtypes.c b/gperl-gtypes.c
index ff09c81..79ec9f6 100644
--- a/gperl-gtypes.c
+++ b/gperl-gtypes.c
@@ -510,3 +510,42 @@ gperl_thread_error_get_type (void)
 
 #define GPERL_TYPE_THREAD_ERROR gperl_thread_error_get_type()
 GType gperl_thread_error_get_type (void);
+
+/* -------------------------------------------------------------------------- */
+
+#if GLIB_CHECK_VERSION (2, 24, 0)
+
+GType
+gperl_variant_parse_error_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type) {
+    static const GEnumValue values[] = {
+      { G_VARIANT_PARSE_ERROR_FAILED, "G_VARIANT_PARSE_ERROR_FAILED", "failed" },
+      { G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED, "G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED", 
"basic-type-expected" },
+      { G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE, "G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE", 
"cannot-infer-type" },
+      { G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED, "G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED", 
"definite-type-expected" },
+      { G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END, "G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END", "input-not-at-end" 
},
+      { G_VARIANT_PARSE_ERROR_INVALID_CHARACTER, "G_VARIANT_PARSE_ERROR_INVALID_CHARACTER", 
"invalid-character" },
+      { G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING, "G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING", 
"invalid-format-string" },
+      { G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH, "G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH", 
"invalid-object-path" },
+      { G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE, "G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE", 
"invalid-signature" },
+      { G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING, "G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING", 
"invalid-type-string" },
+      { G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE, "G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE", "no-common-type" },
+      { G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE, "G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE", 
"number-out-of-range" },
+      { G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG, "G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG", "number-too-big" },
+      { G_VARIANT_PARSE_ERROR_TYPE_ERROR, "G_VARIANT_PARSE_ERROR_TYPE_ERROR", "type-error" },
+      { G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN, "G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN", "unexpected-token" 
},
+      { G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD, "G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD", "unknown-keyword" },
+      { G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT, 
"G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT", "unterminated-string-constant" },
+      { G_VARIANT_PARSE_ERROR_VALUE_EXPECTED, "G_VARIANT_PARSE_ERROR_VALUE_EXPECTED", "value-expected" },
+      { 0, NULL, NULL }
+    };
+    type = g_enum_register_static ("GVariantParseError", values);
+  }
+
+  return type;
+}
+
+#endif
diff --git a/gperl-gtypes.h b/gperl-gtypes.h
index b51f448..7c5573e 100644
--- a/gperl-gtypes.h
+++ b/gperl-gtypes.h
@@ -79,6 +79,11 @@ GType gperl_spawn_error_get_type (void) G_GNUC_CONST;
 #define GPERL_TYPE_THREAD_ERROR gperl_thread_error_get_type ()
 GType gperl_thread_error_get_type (void) G_GNUC_CONST;
 
+#if GLIB_CHECK_VERSION (2, 24, 0)
+#define GPERL_TYPE_VARIANT_PARSE_ERROR gperl_variant_parse_error_get_type ()
+GType gperl_variant_parse_error_get_type (void);
+#endif
+
 G_END_DECLS
 
 #endif /* __GPERL_GTYPES_H__ */
diff --git a/gperl.h b/gperl.h
index 2f060a9..7074dcc 100644
--- a/gperl.h
+++ b/gperl.h
@@ -362,8 +362,22 @@ SV * newSVGUserDirectory (GUserDirectory dir);
 #endif
 
 /*
- * miscellaneous
+ * -- GVariant ----------------------------------------------------------------
  */
+#if GLIB_CHECK_VERSION (2, 24, 0)
+
+typedef GVariant GVariant_noinc;
+SV * newSVGVariant (GVariant * variant);
+SV * newSVGVariant_noinc (GVariant * variant);
+GVariant * SvGVariant (SV * sv);
+
+typedef GVariantType GVariantType_own;
+SV * newSVGVariantType (const GVariantType * type);
+SV * newSVGVariantType_own (const GVariantType * type);
+const GVariantType * SvGVariantType (SV * sv);
+
+#endif /* 2.24.0 */
+
 /*
  * --- miscellaneous ----------------------------------------------------------
  */
diff --git a/lib/Glib.pm b/lib/Glib.pm
index 5cb267d..db3ebeb 100644
--- a/lib/Glib.pm
+++ b/lib/Glib.pm
@@ -216,6 +216,155 @@ sub AUTOLOAD {
        return $object_or_type->$method (@_);
 }
 
+package Glib::Variant;
+
+my %LEAF_HANDLERS = (
+  b => ['new_boolean', 'get_boolean'],
+  y => ['new_byte', 'get_byte'],
+  n => ['new_int16', 'get_int16'],
+  q => ['new_uint16', 'get_uint16'],
+  i => ['new_int32', 'get_int32'],
+  u => ['new_uint32', 'get_uint32'],
+  x => ['new_int64', 'get_int64'],
+  t => ['new_uint64', 'get_uint64'],
+  h => ['new_handle', 'get_handle'],
+  d => ['new_double', 'get_double'],
+  s => ['new_string', 'get_string'],
+  o => ['new_object_path', 'get_string'],
+  g => ['new_signature', 'get_string'],
+);
+
+# Documented in GVariant.xs.
+sub new {
+  my ($class, $format, @values) = @_;
+  if (!defined $format || $format eq '') {
+    return;
+  }
+
+  my ($ts, $format_rest) = Glib::VariantType::string_scan ($format);
+  my ($value, @values_rest) = @values;
+  my $t = Glib::VariantType->new ($ts);
+  my $v;
+
+  if ($t->is_basic) {
+    my $ctor = $LEAF_HANDLERS{$t->get_string}->[0];
+    $v = Glib::Variant->$ctor ($value);
+  }
+
+  elsif ($t->is_variant) {
+    $v = Glib::Variant->new_variant ($value);
+  }
+
+  elsif ($t->is_array) {
+    my $et = $t->element;
+    my @children;
+    if (eval { defined $#$value }) {
+      @children = map { Glib::Variant->new ($et->get_string, $_) } @$value;
+    } elsif ($et->is_dict_entry && eval { defined scalar %$value }) {
+      while (my ($ek, $ev) = each %$value) {
+        push @children, Glib::Variant->new ($et->get_string, [$ek, $ev]);
+      }
+    } else {
+      Carp::croak ('Expected an array ref');
+    }
+    $v = Glib::Variant->new_array ($et, \ children);
+  }
+
+  elsif ($t->is_maybe) {
+    my $et = $t->element;
+    my $child = defined $value ? Glib::Variant->new ($et->get_string, $value) : undef;
+    $v = Glib::Variant->new_maybe ($et, $child);
+  }
+
+  elsif ($t->is_tuple) {
+    my $n = $t->n_items;
+    if ($n && !eval { $#$value+1 == $n }) {
+      Carp::croak ("Expected an array ref with $n elements");
+    }
+    my @children;
+    for (my ($i, $et) = (0, $t->first); $et; $i++, $et = $et->next) {
+      push @children, Glib::Variant->new ($et->get_string, $value->[$i]);
+    }
+    $v = Glib::Variant->new_tuple (\ children);
+  }
+
+  elsif ($t->is_dict_entry) {
+    my $kt = $t->first;
+    my $vt = $kt->next;
+    my $kv = Glib::Variant->new ($kt->get_string, $value->[0]);
+    my $vv = Glib::Variant->new ($vt->get_string, $value->[1]);
+    $v = Glib::Variant->new_dict_entry ($kv, $vv);
+  }
+
+  else {
+    Carp::croak ("Cannot handle the part '$ts' in the format string '$format'");
+  }
+
+  return wantarray ? ($v, Glib::Variant->new ($format_rest, @values_rest)) : $v;
+}
+
+# Documented in GVariant.xs.
+sub get {
+  my ($v, $format) = @_;
+  if (!defined $format || $format eq '') {
+    return;
+  }
+
+  my ($ts, $format_rest) = Glib::VariantType::string_scan ($format);
+  if (defined $format_rest) {
+    Carp::carp ("Unhandled rest of format string detected: '$format_rest'");
+  }
+  my $t = Glib::VariantType->new ($ts);
+  my $value;
+
+  if ($t->is_basic) {
+    my $getter = $LEAF_HANDLERS{$t->get_string}->[1];
+    $value = $v->$getter;
+  }
+
+  elsif ($t->is_variant) {
+    $value = $v->get_variant;
+  }
+
+  elsif ($t->is_array) {
+    my $et = $t->element;
+    my @children;
+    foreach my $i (1 .. $v->n_children) {
+      push @children, $v->get_child_value ($i-1)->get ($et->get_string);
+    }
+    $value = \ children;
+  }
+
+  elsif ($t->is_maybe) {
+    my $et = $t->element;
+    my $wrapper = $v->get_maybe;
+    $value = defined $wrapper ? $wrapper->get ($et->get_string) : undef;
+  }
+
+  elsif ($t->is_tuple) {
+    my $n = $t->n_items;
+    my @children;
+    for (my ($i, $et) = (0, $t->first); $et; $i++, $et = $et->next) {
+      push @children, $v->get_child_value ($i)->get ($et->get_string);
+    }
+    $value = \ children;
+  }
+
+  elsif ($t->is_dict_entry) {
+    my $kt = $t->first;
+    my $vt = $kt->next;
+    my $kv = $v->get_child_value (0)->get ($kt->get_string);
+    my $vv = $v->get_child_value (1)->get ($vt->get_string);
+    $value = [$kv, $vv];
+  }
+
+  else {
+    Carp::croak ("Cannot handle the part '$ts' in the format string '$format'");
+  }
+
+  return $value;
+}
+
 package Glib;
 
 1;
diff --git a/t/variant.t b/t/variant.t
new file mode 100644
index 0000000..8766e5a
--- /dev/null
+++ b/t/variant.t
@@ -0,0 +1,338 @@
+#!perl
+use strict;
+use warnings;
+use utf8;
+use Glib qw/TRUE FALSE/;
+use Test::More;
+
+use constant {
+  MIN_INT64 => "-9223372036854775807",
+  MAX_INT64 => "9223372036854775807",
+
+  MIN_UINT64 => "0",
+  MAX_UINT64 => "18446744073709551615"
+};
+
+if (Glib->CHECK_VERSION (2, 24, 0)) {
+  plan tests => 211;
+} else {
+  plan skip_all => 'Need libglib >= 2.24';
+}
+
+my @leafs = (
+  [ 'new_boolean', 'get_boolean', 'b', TRUE ],
+  [ 'new_byte', 'get_byte', 'y', 2**8-1 ],
+  [ 'new_int16', 'get_int16', 'n', 2**15-1 ],
+  [ 'new_uint16', 'get_uint16', 'q', 2**16-1 ],
+  [ 'new_int32', 'get_int32', 'i', 2**31-1 ],
+  [ 'new_uint32', 'get_uint32', 'u', 2**32-1 ],
+  [ 'new_int64', 'get_int64', 'x', MAX_INT64 ],
+  [ 'new_uint64', 'get_uint64', 't', MAX_UINT64 ],
+  [ 'new_handle', 'get_handle', 'h', 2**31-1 ],
+  [ 'new_double', 'get_double', 'd', 0.25 ],
+  [ 'new_string', 'get_string', 's', 'äöü⁂üöä' ],
+  [ 'new_object_path', 'get_string', 'o', '/a/b/c' ],
+  [ 'new_signature', 'get_string', 'g', 'ii' ],
+);
+
+{
+  foreach my $l (@leafs) {
+    my ($ctor, $getter, $type_string, $value) = @$l;
+    note ($ctor);
+    my $v = Glib::Variant->$ctor ($value);
+    isa_ok ($v, 'Glib::Variant');
+    isa_ok ($v->get_type, 'Glib::VariantType');
+    ok ($v->is_of_type ($v->get_type));
+    is ($v->get_type_string, $type_string);
+    ok (!$v->is_container);
+    is ($v->classify, $type_string);
+    is ($v->$getter, $value);
+  }
+
+  ok (Glib::Variant::is_object_path ('/a/b/c'));
+  ok (Glib::Variant::is_signature ('ii'));
+}
+
+note ('new_variant');
+{
+  {
+    my $child = Glib::Variant->new_byte (23);
+    my $wrapper = Glib::Variant->new_variant ($child);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'v');
+    is ($wrapper->classify, 'v');
+    {
+      my $wrapped_child = $wrapper->get_variant;
+      is ($wrapped_child->get_byte, 23);
+    }
+    undef $child;
+    {
+      my $wrapped_child = $wrapper->get_variant;
+      is ($wrapped_child->get_byte, 23);
+    }
+  }
+  {
+    my $child = Glib::Variant->new_byte (23);
+    my $wrapper = Glib::Variant->new_variant ($child);
+    undef $wrapper;
+    is ($child->get_byte, 23);
+  }
+}
+
+note ('new_bytestring');
+SKIP: {
+  skip 'new_bytestring', 6
+    unless Glib->CHECK_VERSION (2, 26, 0);
+
+  {
+    my $bs = "\x{a3}\x{ff}";
+    my $v = Glib::Variant->new_bytestring ($bs);
+    isa_ok ($v, 'Glib::Variant');
+    is ($v->get_type_string, 'ay');
+    is ($v->classify, 'a');
+    is ($v->get_bytestring, $bs);
+  }
+
+  {
+    my $bs = "\x{a3}\x{ff}";
+    utf8::upgrade ($bs);
+    my $v = Glib::Variant->new_bytestring ($bs);
+    is ($v->get_bytestring, $bs);
+  }
+
+  {
+    my $bs = "\x{a3}\x{ff}";
+    utf8::encode ($bs);
+    my $v = Glib::Variant->new_bytestring ($bs);
+    is ($v->get_bytestring, $bs);
+  }
+}
+
+note ('new_maybe');
+{
+  my $child_type = 'y';
+  my $child = Glib::Variant->new_byte (42);
+  {
+    my $wrapper = Glib::Variant->new_maybe ($child_type, undef);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'my');
+    is ($wrapper->classify, 'm');
+    ok (! defined $wrapper->get_maybe);
+    is ($wrapper->n_children, 0);
+  }
+  {
+    my $wrapper = Glib::Variant->new_maybe (undef, $child);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'my');
+    is ($wrapper->classify, 'm');
+    is ($wrapper->get_maybe->get_byte, $child->get_byte);
+    is ($wrapper->n_children, 1);
+    is ($wrapper->get_child_value (0)->get_byte, 42);
+  }
+  {
+    my $wrapper = Glib::Variant->new_maybe ($child_type, $child);
+    isa_ok ($wrapper, 'Glib::Variant');
+    is ($wrapper->get_type_string, 'my');
+    is ($wrapper->classify, 'm');
+    is ($wrapper->get_maybe->get_byte, $child->get_byte);
+    is ($wrapper->n_children, 1);
+    is ($wrapper->get_child_value (0)->get_byte, $child->get_byte);
+  }
+}
+
+note ('new_array');
+{
+  my $child_type = 'y';
+  my $children = [map { Glib::Variant->new_byte ($_) } (23, 42, 65)];
+  {
+    my $array = Glib::Variant->new_array ($child_type, []);
+    isa_ok ($array, 'Glib::Variant');
+    is ($array->get_type_string, 'ay');
+    is ($array->classify, 'a');
+    is ($array->n_children, 0);
+  }
+  {
+    my $array = Glib::Variant->new_array (undef, $children);
+    isa_ok ($array, 'Glib::Variant');
+    is ($array->get_type_string, 'ay');
+    is ($array->classify, 'a');
+    is ($array->n_children, 3);
+    is ($array->get_child_value (2)->get_byte, $children->[2]->get_byte);
+  }
+  {
+    my $array = Glib::Variant->new_array ($child_type, $children);
+    isa_ok ($array, 'Glib::Variant');
+    is ($array->get_type_string, 'ay');
+    is ($array->classify, 'a');
+    is ($array->n_children, 3);
+    is ($array->get_child_value (2)->get_byte, $children->[2]->get_byte);
+  }
+}
+
+note ('new_tuple');
+{
+  my $children = [Glib::Variant->new_byte (23),
+                  Glib::Variant->new_string ('forty-two'),
+                  Glib::Variant->new_double (0.25)];
+  {
+    my $tuple = Glib::Variant->new_tuple ([]);
+    isa_ok ($tuple, 'Glib::Variant');
+    is ($tuple->get_type_string, '()');
+    is ($tuple->classify, '(');
+    is ($tuple->n_children, 0);
+  }
+  {
+    my $tuple = Glib::Variant->new_tuple ($children);
+    isa_ok ($tuple, 'Glib::Variant');
+    is ($tuple->get_type_string, '(ysd)');
+    is ($tuple->classify, '(');
+    is ($tuple->n_children, 3);
+    is ($tuple->get_child_value (2)->get_double, $children->[2]->get_double);
+  }
+}
+
+note ('new_dict_entry');
+{
+  my $key = Glib::Variant->new_string ('forty-two');
+  my $value = Glib::Variant->new_byte (23);
+  {
+    my $entry = Glib::Variant->new_dict_entry ($key, $value);
+    isa_ok ($entry, 'Glib::Variant');
+    is ($entry->get_type_string, '{sy}');
+    is ($entry->classify, '{');
+    is ($entry->get_child_value (1)->get_byte, $value->get_byte);
+  }
+}
+
+note ('lookup_value');
+{
+  my $entries = [map { Glib::Variant->new_dict_entry (Glib::Variant->new_string ($_->[0]),
+                                                      Glib::Variant->new_byte ($_->[1])) }
+                     (['one' => 1], ['two' => 2], ['four' => 4], ['eight' => 8])];
+  my $array = Glib::Variant->new_array ('{sy}', $entries);
+  is ($array->lookup_value ('one', 'y')->get_byte, 1);
+  is ($array->lookup_value ('two', undef)->get_byte, 2);
+  ok (! defined $array->lookup_value ('fourr', undef));
+}
+
+note ('printing and parsing');
+{
+  {
+    my $a = Glib::Variant->new_byte (23);
+    my $text = $a->print (TRUE);
+    is ($text, 'byte 0x17');
+    is (Glib::Variant::parse (undef, $text)->get_byte, 23);
+    is (Glib::Variant::parse ('y', $text)->get_byte, 23);
+  }
+
+  {
+    my $text = 'byte 0x17';
+    eval { Glib::Variant::parse ('b', $text)->get_byte };
+    ok (Glib::Error::matches ($@, 'Glib::Variant::ParseError', 'type-error'));
+  }
+}
+
+note ('misc.');
+{
+  my $a = Glib::Variant->new_byte (23);
+  my $b = Glib::Variant->new_byte (42);
+
+  ok (defined $a->get_size);
+  ok (defined $a->hash);
+  ok ($a->equal ($a));
+  ok (! $a->equal ($b));
+  is ($a->get_normal_form->get_byte, $a->get_byte);
+  ok ($a->is_normal_form);
+  is ($a->byteswap->get_byte, $a->get_byte);
+
+  SKIP: {
+    skip 'compare', 2
+      unless Glib->CHECK_VERSION (2, 26, 0);
+    cmp_ok ($a->compare ($b), '<', 0);
+    cmp_ok ($b->compare ($a), '>', 1);
+  }
+}
+
+note ('convenience constructor and accessor');
+{
+  note (' leafs');
+  foreach my $l (@leafs) {
+    my ($ctor, $getter, $type_string, $value) = @$l;
+    my $v = Glib::Variant->new ($type_string, $value);
+    is ($v->get_type_string, $type_string);
+    is ($v->get ($type_string), $value);
+  }
+
+  note (' list context');
+  {
+    my ($v) = Glib::Variant->new ('i', 23);
+    is ($v->get ('i'), 23);
+
+    my ($v1, $v2, $v3) = Glib::Variant->new ('ids', 23, 0.25, 'äöü');
+    is ($v1->get ('i'), 23);
+    is ($v2->get ('d'), 0.25);
+    is ($v3->get ('s'), 'äöü');
+  }
+
+  note (' variant');
+  {
+    my $child = Glib::Variant->new_byte (23);
+    my $wrapper = Glib::Variant->new ('v', $child);
+    is ($wrapper->get_type_string, 'v');
+    {
+      my $wrapped_child = $wrapper->get ('v');
+      is ($wrapped_child->get_byte, 23);
+    }
+  }
+
+  note (' array');
+  {
+    my $v1 = Glib::Variant->new ('as', ['äöü', 'Perl', '💑']);
+    is_deeply ($v1->get ('as'), ['äöü', 'Perl', '💑']);
+
+    my $v2 = Glib::Variant->new ('aai', [[23, 42], [2, 3], [4, 2]]);
+    is_deeply ($v2->get ('aai'), [[23, 42], [2, 3], [4, 2]]);
+
+    is (Glib::Variant->new ('ai', [])->n_children, 0);
+    is (Glib::Variant->new ('ai', undef)->n_children, 0);
+  }
+
+  note (' maybe');
+  {
+    my $v1 = Glib::Variant->new ('mi', undef);
+    ok (! defined $v1->get ('mi'));
+
+    my $v2 = Glib::Variant->new ('mi', 23);
+    is ($v2->get ('mi'), 23);
+
+    my $v3 = Glib::Variant->new ('mai', undef);
+    ok (! defined $v3->get ('mai'));
+
+    my $v4 = Glib::Variant->new ('mai', [23, 42]);
+    is_deeply ($v4->get ('mai'), [23, 42]);
+  }
+
+  note (' tuple');
+  {
+    my $v1 = Glib::Variant->new ('()');
+    is ($v1->n_children, 0);
+
+    my $v2 = Glib::Variant->new ('(si)', ['äöü', 23]);
+    is_deeply ($v2->get ('(si)'), ['äöü', 23]);
+
+    my $v3 = Glib::Variant->new ('a(si)', [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+    is_deeply ($v3->get ('a(si)'), [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+  }
+
+  note (' dict entry');
+  {
+    my $v1 = Glib::Variant->new ('{si}', ['äöü', 23]);
+    is_deeply ($v1->get ('{si}'), ['äöü', 23]);
+
+    my $v2 = Glib::Variant->new ('a{si}', [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+    is_deeply ($v2->get ('a{si}'), [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+
+    my $v3 = Glib::Variant->new ('a{si}', {'äöü' => 23, 'Perl' => 42, '💑' => 2342});
+    is_deeply ($v2->get ('a{si}'), [['äöü', 23], ['Perl', 42], ['💑', 2342]]);
+  }
+}
diff --git a/typemap b/typemap
index 7307291..5aec2fb 100644
--- a/typemap
+++ b/typemap
@@ -100,6 +100,14 @@ GOptionGroup_own * T_GPERL_GENERIC_WRAPPER
 
 GUserDirectory         T_GPERL_GENERIC_WRAPPER
 
+GVariant *             T_GPERL_GENERIC_WRAPPER
+const GVariant *       T_GPERL_GENERIC_WRAPPER
+GVariant_noinc *       T_GPERL_GENERIC_WRAPPER
+
+GVariantType *         T_GPERL_GENERIC_WRAPPER
+const GVariantType *   T_GPERL_GENERIC_WRAPPER
+GVariantType_own *     T_GPERL_GENERIC_WRAPPER
+
 ###############################################################################
 INPUT
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]