[glib/wip/ernestask/bz-693576-annotations] task: Add return/propagate API for GValue



commit 2efbf49ddd32f763c6789952ff45066d26b06fdf
Author: Garrett Regier <garrettregier gmail com>
Date:   Tue Nov 5 09:54:01 2019 +0100

    task: Add return/propagate API for GValue
    
    This is useful for bindings.
    
    Related: https://gitlab.gnome.org/GNOME/glib/issues/668

 gio/gtask.c      | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gio/gtask.h      |  7 +++++
 gio/tests/task.c | 42 +++++++++++++++++++++++++
 3 files changed, 145 insertions(+)
---
diff --git a/gio/gtask.c b/gio/gtask.c
index 06f63e7b1..332066501 100644
--- a/gio/gtask.c
+++ b/gio/gtask.c
@@ -27,6 +27,8 @@
 
 #include "glibintl.h"
 
+#include <string.h>
+
 /**
  * SECTION:gtask
  * @short_description: Cancellable synchronous or asynchronous task
@@ -1959,6 +1961,100 @@ g_task_had_error (GTask *task)
   return FALSE;
 }
 
+static void
+value_free (gpointer value)
+{
+  g_value_unset (value);
+  g_free (value);
+}
+
+/**
+ * g_task_return_value:
+ * @task: a #GTask
+ * @result: (nullable) (transfer none): the #GValue result of
+ *                                      a task function
+ *
+ * Sets @task's result to @result (by copying it) and completes the task.
+ *
+ * If @result is %NULL then a #GValue of type #G_TYPE_POINTER
+ * with a value of %NULL will be used for the result.
+ *
+ * This is a very generic low-level method intended primarily for use
+ * by language bindings; for C code, g_task_return_pointer() and the
+ * like will normally be much easier to use.
+ *
+ * Since: 2.64
+ */
+void
+g_task_return_value (GTask  *task,
+                     GValue *result)
+{
+  GValue *value;
+
+  g_return_if_fail (G_IS_TASK (task));
+  g_return_if_fail (!task->ever_returned);
+
+  value = g_new0 (GValue, 1);
+
+  if (result == NULL)
+    {
+      g_value_init (value, G_TYPE_POINTER);
+      g_value_set_pointer (value, NULL);
+    }
+  else
+    {
+      g_value_init (value, G_VALUE_TYPE (result));
+      g_value_copy (result, value);
+    }
+
+  g_task_return_pointer (task, value, value_free);
+}
+
+/**
+ * g_task_propagate_value:
+ * @task: a #GTask
+ * @value: (out) (caller-allocates): return location for the #GValue
+ * @error: return location for a #GError
+ *
+ * Gets the result of @task as a #GValue, and transfers ownership of
+ * that value to the caller. As with g_task_return_value(), this is
+ * a generic low-level method; g_task_propagate_pointer() and the like
+ * will usually be more useful for C code.
+ *
+ * If the task resulted in an error, or was cancelled, then this will
+ * instead set @error and return %FALSE.
+ *
+ * Since this method transfers ownership of the return value (or
+ * error) to the caller, you may only call it once.
+ *
+ * Returns: (skip): %TRUE if @task succeeded, %FALSE on error.
+ *
+ * Since: 2.64
+ */
+gboolean
+g_task_propagate_value (GTask   *task,
+                        GValue  *value,
+                        GError **error)
+{
+  g_return_val_if_fail (G_IS_TASK (task), FALSE);
+  g_return_val_if_fail (value != NULL, FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (g_task_propagate_error (task, error))
+    return FALSE;
+
+  g_return_val_if_fail (task->result_set, FALSE);
+  g_return_val_if_fail (task->result_destroy == value_free, FALSE);
+
+  memcpy (value, task->result.pointer, sizeof (GValue));
+  g_free (task->result.pointer);
+
+  task->result_destroy = NULL;
+  task->result_set = FALSE;
+
+  return TRUE;
+}
+
 /**
  * g_task_get_completed:
  * @task: a #GTask.
diff --git a/gio/gtask.h b/gio/gtask.h
index 4fc1c859e..73a31e157 100644
--- a/gio/gtask.h
+++ b/gio/gtask.h
@@ -142,6 +142,9 @@ void          g_task_return_new_error          (GTask           *task,
                                                 gint             code,
                                                 const char      *format,
                                                 ...) G_GNUC_PRINTF (4, 5);
+GLIB_AVAILABLE_IN_2_64
+void          g_task_return_value              (GTask           *task,
+                                                GValue          *result);
 
 GLIB_AVAILABLE_IN_2_36
 gboolean      g_task_return_error_if_cancelled (GTask           *task);
@@ -155,6 +158,10 @@ gboolean      g_task_propagate_boolean         (GTask           *task,
 GLIB_AVAILABLE_IN_2_36
 gssize        g_task_propagate_int             (GTask           *task,
                                                 GError         **error);
+GLIB_AVAILABLE_IN_2_64
+gboolean      g_task_propagate_value           (GTask           *task,
+                                                GValue          *value,
+                                                GError         **error);
 GLIB_AVAILABLE_IN_2_36
 gboolean      g_task_had_error                 (GTask           *task);
 GLIB_AVAILABLE_IN_2_44
diff --git a/gio/tests/task.c b/gio/tests/task.c
index 0caed4403..cca05ced1 100644
--- a/gio/tests/task.c
+++ b/gio/tests/task.c
@@ -2009,6 +2009,47 @@ test_return_pointer (void)
   g_assert_null (task);
 }
 
+static void
+test_return_value (void)
+{
+  GObject *object;
+  GValue value = G_VALUE_INIT;
+  GValue ret = G_VALUE_INIT;
+  GTask *task;
+  GError *error = NULL;
+
+  object = (GObject *)g_dummy_object_new ();
+  g_assert_cmpint (object->ref_count, ==, 1);
+  g_object_add_weak_pointer (object, (gpointer *)&object);
+
+  g_value_init (&value, G_TYPE_OBJECT);
+  g_value_set_object (&value, object);
+  g_assert_cmpint (object->ref_count, ==, 2);
+
+  task = g_task_new (NULL, NULL, NULL, NULL);
+  g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task);
+  g_task_return_value (task, &value);
+  g_assert_cmpint (object->ref_count, ==, 3);
+
+  g_assert_true (g_task_propagate_value (task, &ret, &error));
+  g_assert_no_error (error);
+  g_assert_true (g_value_get_object (&ret) == object);
+  g_assert_cmpint (object->ref_count, ==, 3);
+
+  g_object_unref (task);
+  g_assert_nonnull (task);
+  wait_for_completed_notification (task);
+  g_assert_null (task);
+
+  g_assert_cmpint (object->ref_count, ==, 3);
+  g_value_unset (&ret);
+  g_assert_cmpint (object->ref_count, ==, 2);
+  g_value_unset (&value);
+  g_assert_cmpint (object->ref_count, ==, 1);
+  g_object_unref (object);
+  g_assert_null (object);
+}
+
 /* test_object_keepalive: GTask takes a ref on its source object */
 
 static GObject *keepalive_object;
@@ -2348,6 +2389,7 @@ main (int argc, char **argv)
   g_test_add_func ("/gtask/return-on-cancel-sync", test_return_on_cancel_sync);
   g_test_add_func ("/gtask/return-on-cancel-atomic", test_return_on_cancel_atomic);
   g_test_add_func ("/gtask/return-pointer", test_return_pointer);
+  g_test_add_func ("/gtask/return-value", test_return_value);
   g_test_add_func ("/gtask/object-keepalive", test_object_keepalive);
   g_test_add_func ("/gtask/legacy-error", test_legacy_error);
   g_test_add_func ("/gtask/return/in-idle/error-first", test_return_in_idle_error_first);


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