/* nonblocking-queue.c generated by valac 0.56.19, the Vala compiler
 * generated from nonblocking-queue.vala, do not modify */

/*
 * Copyright 2016 Software Freedom Conservancy Inc.
 * Copyright 2017 Michael Gratton <mike@vee.net>
 *
 * This software is licensed under the GNU Lesser General Public License
 * (version 2.1 or later).  See the COPYING file in this distribution.
 */

#include "geary-engine.h"
#include <glib.h>
#include <gee.h>
#include <glib-object.h>
#include <gio/gio.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

enum  {
	GEARY_NONBLOCKING_QUEUE_0_PROPERTY,
	GEARY_NONBLOCKING_QUEUE_G_TYPE,
	GEARY_NONBLOCKING_QUEUE_G_DUP_FUNC,
	GEARY_NONBLOCKING_QUEUE_G_DESTROY_FUNC,
	GEARY_NONBLOCKING_QUEUE_SIZE_PROPERTY,
	GEARY_NONBLOCKING_QUEUE_IS_EMPTY_PROPERTY,
	GEARY_NONBLOCKING_QUEUE_ALLOW_DUPLICATES_PROPERTY,
	GEARY_NONBLOCKING_QUEUE_REQUEUE_DUPLICATE_PROPERTY,
	GEARY_NONBLOCKING_QUEUE_IS_PAUSED_PROPERTY,
	GEARY_NONBLOCKING_QUEUE_NUM_PROPERTIES
};
static GParamSpec* geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
typedef struct _GearyNonblockingQueueReceiveData GearyNonblockingQueueReceiveData;
typedef struct _GearyNonblockingQueuePeekData GearyNonblockingQueuePeekData;

struct _GearyNonblockingQueuePrivate {
	GType g_type;
	GBoxedCopyFunc g_dup_func;
	GDestroyNotify g_destroy_func;
	gboolean _allow_duplicates;
	gboolean _requeue_duplicate;
	gboolean _is_paused;
	GeeQueue* queue;
	GearyNonblockingSpinlock* spinlock;
};

struct _GearyNonblockingQueueReceiveData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	GearyNonblockingQueue* self;
	GCancellable* cancellable;
	gpointer result;
	gboolean _tmp0_;
	gboolean _tmp1_;
	GeeQueue* _tmp2_;
	gint _tmp3_;
	gint _tmp4_;
	gboolean _tmp5_;
	gboolean _tmp6_;
	GeeQueue* _tmp7_;
	gpointer _tmp8_;
	GearyNonblockingSpinlock* _tmp9_;
	GError* _inner_error0_;
};

struct _GearyNonblockingQueuePeekData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	GearyNonblockingQueue* self;
	GCancellable* cancellable;
	gpointer result;
	gboolean _tmp0_;
	gboolean _tmp1_;
	GeeQueue* _tmp2_;
	gint _tmp3_;
	gint _tmp4_;
	gboolean _tmp5_;
	gboolean _tmp6_;
	GeeQueue* _tmp7_;
	gpointer _tmp8_;
	GearyNonblockingSpinlock* _tmp9_;
	GError* _inner_error0_;
};

static gint GearyNonblockingQueue_private_offset;
static gpointer geary_nonblocking_queue_parent_class = NULL;

static void geary_nonblocking_queue_receive_data_free (gpointer _data);
static gboolean geary_nonblocking_queue_receive_co (GearyNonblockingQueueReceiveData* _data_);
static void geary_nonblocking_queue_receive_ready (GObject* source_object,
                                            GAsyncResult* _res_,
                                            gpointer _user_data_);
static void geary_nonblocking_queue_peek_data_free (gpointer _data);
static gboolean geary_nonblocking_queue_peek_co (GearyNonblockingQueuePeekData* _data_);
static void geary_nonblocking_queue_peek_ready (GObject* source_object,
                                         GAsyncResult* _res_,
                                         gpointer _user_data_);
static void geary_nonblocking_queue_finalize (GObject * obj);
static GType geary_nonblocking_queue_get_type_once (void);
static void _vala_geary_nonblocking_queue_get_property (GObject * object,
                                                 guint property_id,
                                                 GValue * value,
                                                 GParamSpec * pspec);
static void _vala_geary_nonblocking_queue_set_property (GObject * object,
                                                 guint property_id,
                                                 const GValue * value,
                                                 GParamSpec * pspec);
static void _vala_array_destroy (gpointer array,
                          gssize array_length,
                          GDestroyNotify destroy_func);
static void _vala_array_free (gpointer array,
                       gssize array_length,
                       GDestroyNotify destroy_func);

static inline gpointer
geary_nonblocking_queue_get_instance_private (GearyNonblockingQueue* self)
{
	return G_STRUCT_MEMBER_P (self, GearyNonblockingQueue_private_offset);
}

gint
geary_nonblocking_queue_get_size (GearyNonblockingQueue* self)
{
	gint result;
	GeeQueue* _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), -1);
	_tmp0_ = self->priv->queue;
	_tmp1_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp2_ = _tmp1_;
	result = _tmp2_;
	return result;
}

gboolean
geary_nonblocking_queue_get_is_empty (GearyNonblockingQueue* self)
{
	gboolean result;
	GeeQueue* _tmp0_;
	gboolean _tmp1_;
	gboolean _tmp2_;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), FALSE);
	_tmp0_ = self->priv->queue;
	_tmp1_ = gee_collection_get_is_empty (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp2_ = _tmp1_;
	result = _tmp2_;
	return result;
}

gboolean
geary_nonblocking_queue_get_allow_duplicates (GearyNonblockingQueue* self)
{
	gboolean result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), FALSE);
	result = self->priv->_allow_duplicates;
	return result;
}

void
geary_nonblocking_queue_set_allow_duplicates (GearyNonblockingQueue* self,
                                              gboolean value)
{
	gboolean old_value;
	g_return_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self));
	old_value = geary_nonblocking_queue_get_allow_duplicates (self);
	if (old_value != value) {
		self->priv->_allow_duplicates = value;
		g_object_notify_by_pspec ((GObject *) self, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_ALLOW_DUPLICATES_PROPERTY]);
	}
}

gboolean
geary_nonblocking_queue_get_requeue_duplicate (GearyNonblockingQueue* self)
{
	gboolean result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), FALSE);
	result = self->priv->_requeue_duplicate;
	return result;
}

void
geary_nonblocking_queue_set_requeue_duplicate (GearyNonblockingQueue* self,
                                               gboolean value)
{
	gboolean old_value;
	g_return_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self));
	old_value = geary_nonblocking_queue_get_requeue_duplicate (self);
	if (old_value != value) {
		self->priv->_requeue_duplicate = value;
		g_object_notify_by_pspec ((GObject *) self, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_REQUEUE_DUPLICATE_PROPERTY]);
	}
}

gboolean
geary_nonblocking_queue_get_is_paused (GearyNonblockingQueue* self)
{
	gboolean result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), FALSE);
	result = self->priv->_is_paused;
	return result;
}

void
geary_nonblocking_queue_set_is_paused (GearyNonblockingQueue* self,
                                       gboolean value)
{
	gboolean _tmp0_ = FALSE;
	g_return_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self));
	if (self->priv->_is_paused) {
		_tmp0_ = !value;
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		GearyNonblockingSpinlock* _tmp1_;
		_tmp1_ = self->priv->spinlock;
		geary_nonblocking_lock_blind_notify (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock));
	}
	self->priv->_is_paused = value;
	g_object_notify_by_pspec ((GObject *) self, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_IS_PAUSED_PROPERTY]);
}

/**
     * Constructs a new first-in first-out (FIFO) queue.
     *
     * If `equalator` is not null it will be used to determine the
     * identity of objects in the queue, else the items' natural
     * identity will be used.
     */
GearyNonblockingQueue*
geary_nonblocking_queue_construct_fifo (GType object_type,
                                        GType g_type,
                                        GBoxedCopyFunc g_dup_func,
                                        GDestroyNotify g_destroy_func,
                                        GeeEqualDataFunc equalator,
                                        gpointer equalator_target,
                                        GDestroyNotify equalator_target_destroy_notify)
{
	GearyNonblockingQueue * self = NULL;
	GeeEqualDataFunc _tmp0_;
	gpointer _tmp0__target;
	GDestroyNotify _tmp0__target_destroy_notify;
	GeeLinkedList* _tmp1_;
	GeeLinkedList* _tmp2_;
	_tmp0_ = equalator;
	_tmp0__target = equalator_target;
	_tmp0__target_destroy_notify = equalator_target_destroy_notify;
	equalator = NULL;
	equalator_target = NULL;
	equalator_target_destroy_notify = NULL;
	_tmp1_ = gee_linked_list_new (g_type, (GBoxedCopyFunc) g_dup_func, (GDestroyNotify) g_destroy_func, _tmp0_, _tmp0__target, _tmp0__target_destroy_notify);
	_tmp2_ = _tmp1_;
	self = (GearyNonblockingQueue*) geary_nonblocking_queue_construct (object_type, g_type, g_dup_func, g_destroy_func, G_TYPE_CHECK_INSTANCE_CAST (_tmp2_, GEE_TYPE_QUEUE, GeeQueue));
	self->priv->g_type = g_type;
	self->priv->g_dup_func = g_dup_func;
	self->priv->g_destroy_func = g_destroy_func;
	_g_object_unref0 (_tmp2_);
	(equalator_target_destroy_notify == NULL) ? NULL : (equalator_target_destroy_notify (equalator_target), NULL);
	equalator = NULL;
	equalator_target = NULL;
	equalator_target_destroy_notify = NULL;
	return self;
}

GearyNonblockingQueue*
geary_nonblocking_queue_new_fifo (GType g_type,
                                  GBoxedCopyFunc g_dup_func,
                                  GDestroyNotify g_destroy_func,
                                  GeeEqualDataFunc equalator,
                                  gpointer equalator_target,
                                  GDestroyNotify equalator_target_destroy_notify)
{
	return geary_nonblocking_queue_construct_fifo (GEARY_NONBLOCKING_TYPE_QUEUE, g_type, g_dup_func, g_destroy_func, equalator, equalator_target, equalator_target_destroy_notify);
}

/**
     * Constructs a new priority queue.
     *
     * If `comparator` is not null it will be used to determine the
     * ordering of objects in the queue, else the items' natural
     * ordering will be used.
     */
GearyNonblockingQueue*
geary_nonblocking_queue_construct_priority (GType object_type,
                                            GType g_type,
                                            GBoxedCopyFunc g_dup_func,
                                            GDestroyNotify g_destroy_func,
                                            GCompareDataFunc comparator,
                                            gpointer comparator_target,
                                            GDestroyNotify comparator_target_destroy_notify)
{
	GearyNonblockingQueue * self = NULL;
	GCompareDataFunc _tmp0_;
	gpointer _tmp0__target;
	GDestroyNotify _tmp0__target_destroy_notify;
	GeePriorityQueue* _tmp1_;
	GeePriorityQueue* _tmp2_;
	_tmp0_ = comparator;
	_tmp0__target = comparator_target;
	_tmp0__target_destroy_notify = comparator_target_destroy_notify;
	comparator = NULL;
	comparator_target = NULL;
	comparator_target_destroy_notify = NULL;
	_tmp1_ = gee_priority_queue_new (g_type, (GBoxedCopyFunc) g_dup_func, (GDestroyNotify) g_destroy_func, _tmp0_, _tmp0__target, _tmp0__target_destroy_notify);
	_tmp2_ = _tmp1_;
	self = (GearyNonblockingQueue*) geary_nonblocking_queue_construct (object_type, g_type, g_dup_func, g_destroy_func, G_TYPE_CHECK_INSTANCE_CAST (_tmp2_, GEE_TYPE_QUEUE, GeeQueue));
	self->priv->g_type = g_type;
	self->priv->g_dup_func = g_dup_func;
	self->priv->g_destroy_func = g_destroy_func;
	_g_object_unref0 (_tmp2_);
	(comparator_target_destroy_notify == NULL) ? NULL : (comparator_target_destroy_notify (comparator_target), NULL);
	comparator = NULL;
	comparator_target = NULL;
	comparator_target_destroy_notify = NULL;
	return self;
}

GearyNonblockingQueue*
geary_nonblocking_queue_new_priority (GType g_type,
                                      GBoxedCopyFunc g_dup_func,
                                      GDestroyNotify g_destroy_func,
                                      GCompareDataFunc comparator,
                                      gpointer comparator_target,
                                      GDestroyNotify comparator_target_destroy_notify)
{
	return geary_nonblocking_queue_construct_priority (GEARY_NONBLOCKING_TYPE_QUEUE, g_type, g_dup_func, g_destroy_func, comparator, comparator_target, comparator_target_destroy_notify);
}

/**
     * Constructs a new queue.
     */
static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

GearyNonblockingQueue*
geary_nonblocking_queue_construct (GType object_type,
                                   GType g_type,
                                   GBoxedCopyFunc g_dup_func,
                                   GDestroyNotify g_destroy_func,
                                   GeeQueue* queue)
{
	GearyNonblockingQueue * self = NULL;
	GeeQueue* _tmp0_;
	g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (queue, GEE_TYPE_QUEUE), NULL);
	self = (GearyNonblockingQueue*) geary_base_object_construct (object_type);
	self->priv->g_type = g_type;
	self->priv->g_dup_func = g_dup_func;
	self->priv->g_destroy_func = g_destroy_func;
	_tmp0_ = _g_object_ref0 (queue);
	_g_object_unref0 (self->priv->queue);
	self->priv->queue = _tmp0_;
	return self;
}

GearyNonblockingQueue*
geary_nonblocking_queue_new (GType g_type,
                             GBoxedCopyFunc g_dup_func,
                             GDestroyNotify g_destroy_func,
                             GeeQueue* queue)
{
	return geary_nonblocking_queue_construct (GEARY_NONBLOCKING_TYPE_QUEUE, g_type, g_dup_func, g_destroy_func, queue);
}

/**
     * Adds an item to the queue.
     *
     * If the queue is a priority queue, it is added according to its
     * relative priority, else it is added to the end.
     *
     * Returns `true` if the item was added to the queue.
     */
gboolean
geary_nonblocking_queue_send (GearyNonblockingQueue* self,
                              gconstpointer msg)
{
	gboolean _tmp0_ = FALSE;
	gboolean _tmp1_;
	GeeQueue* _tmp5_;
	gboolean _tmp6_;
	gboolean _tmp7_;
	gboolean result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), FALSE);
	_tmp1_ = self->priv->_allow_duplicates;
	if (!_tmp1_) {
		GeeQueue* _tmp2_;
		_tmp2_ = self->priv->queue;
		_tmp0_ = gee_collection_contains (G_TYPE_CHECK_INSTANCE_CAST (_tmp2_, GEE_TYPE_COLLECTION, GeeCollection), msg);
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		gboolean _tmp3_;
		_tmp3_ = self->priv->_requeue_duplicate;
		if (_tmp3_) {
			GeeQueue* _tmp4_;
			_tmp4_ = self->priv->queue;
			gee_collection_remove (G_TYPE_CHECK_INSTANCE_CAST (_tmp4_, GEE_TYPE_COLLECTION, GeeCollection), msg);
		} else {
			result = FALSE;
			return result;
		}
	}
	_tmp5_ = self->priv->queue;
	if (!gee_queue_offer (_tmp5_, msg)) {
		result = FALSE;
		return result;
	}
	_tmp6_ = geary_nonblocking_queue_get_is_paused (self);
	_tmp7_ = _tmp6_;
	if (!_tmp7_) {
		GearyNonblockingSpinlock* _tmp8_;
		_tmp8_ = self->priv->spinlock;
		geary_nonblocking_lock_blind_notify (G_TYPE_CHECK_INSTANCE_CAST (_tmp8_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock));
	}
	result = TRUE;
	return result;
}

static void
geary_nonblocking_queue_receive_data_free (gpointer _data)
{
	GearyNonblockingQueueReceiveData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->cancellable);
	((_data_->result == NULL) || (_data_->self->priv->g_destroy_func == NULL)) ? NULL : (_data_->result = (_data_->self->priv->g_destroy_func (_data_->result), NULL));
	_g_object_unref0 (_data_->self);
	g_slice_free (GearyNonblockingQueueReceiveData, _data_);
}

void
geary_nonblocking_queue_receive (GearyNonblockingQueue* self,
                                 GCancellable* cancellable,
                                 GAsyncReadyCallback _callback_,
                                 gpointer _user_data_)
{
	GearyNonblockingQueueReceiveData* _data_;
	GearyNonblockingQueue* _tmp0_;
	GCancellable* _tmp1_;
	g_return_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self));
	g_return_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()));
	_data_ = g_slice_new0 (GearyNonblockingQueueReceiveData);
	_data_->_async_result = g_task_new (G_OBJECT (self), cancellable, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, geary_nonblocking_queue_receive_data_free);
	_tmp0_ = _g_object_ref0 (self);
	_data_->self = _tmp0_;
	_tmp1_ = _g_object_ref0 (cancellable);
	_g_object_unref0 (_data_->cancellable);
	_data_->cancellable = _tmp1_;
	geary_nonblocking_queue_receive_co (_data_);
}

gpointer
geary_nonblocking_queue_receive_finish (GearyNonblockingQueue* self,
                                        GAsyncResult* _res_,
                                        GError** error)
{
	gpointer result;
	GearyNonblockingQueueReceiveData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), error);
	if (NULL == _data_) {
		return NULL;
	}
	result = _data_->result;
	_data_->result = NULL;
	return result;
}

/**
     * Removes and returns the next queued item, blocking until available.
     *
     * If the queue is paused, this will continue to wait until
     * unpaused and an item is ready. If `cancellable` is non-null,
     * when used will cancel this call.
     */
static void
geary_nonblocking_queue_receive_ready (GObject* source_object,
                                       GAsyncResult* _res_,
                                       gpointer _user_data_)
{
	GearyNonblockingQueueReceiveData* _data_;
	_data_ = _user_data_;
	_data_->_source_object_ = source_object;
	_data_->_res_ = _res_;
	geary_nonblocking_queue_receive_co (_data_);
}

static gboolean
geary_nonblocking_queue_receive_co (GearyNonblockingQueueReceiveData* _data_)
{
	switch (_data_->_state_) {
		case 0:
		goto _state_0;
		case 1:
		goto _state_1;
		default:
		g_assert_not_reached ();
	}
	_state_0:
	{
		_data_->_tmp0_ = TRUE;
		while (TRUE) {
			if (!_data_->_tmp0_) {
			}
			_data_->_tmp0_ = FALSE;
			_data_->_tmp2_ = _data_->self->priv->queue;
			_data_->_tmp3_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp2_, GEE_TYPE_COLLECTION, GeeCollection));
			_data_->_tmp4_ = _data_->_tmp3_;
			if (_data_->_tmp4_ > 0) {
				_data_->_tmp5_ = geary_nonblocking_queue_get_is_paused (_data_->self);
				_data_->_tmp6_ = _data_->_tmp5_;
				_data_->_tmp1_ = !_data_->_tmp6_;
			} else {
				_data_->_tmp1_ = FALSE;
			}
			if (_data_->_tmp1_) {
				_data_->_tmp7_ = _data_->self->priv->queue;
				_data_->_tmp8_ = gee_queue_poll (_data_->_tmp7_);
				_data_->result = _data_->_tmp8_;
				g_task_return_pointer (_data_->_async_result, _data_, NULL);
				if (_data_->_state_ != 0) {
					while (!g_task_get_completed (_data_->_async_result)) {
						g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE);
					}
				}
				g_object_unref (_data_->_async_result);
				return FALSE;
			}
			_data_->_tmp9_ = _data_->self->priv->spinlock;
			_data_->_state_ = 1;
			geary_nonblocking_lock_wait_async (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp9_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock), _data_->cancellable, geary_nonblocking_queue_receive_ready, _data_);
			return FALSE;
			_state_1:
			geary_nonblocking_lock_wait_finish (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp9_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock), _data_->_res_, &_data_->_inner_error0_);
			if (G_UNLIKELY (_data_->_inner_error0_ != NULL)) {
				g_task_return_error (_data_->_async_result, _data_->_inner_error0_);
				g_object_unref (_data_->_async_result);
				return FALSE;
			}
		}
	}
}

static void
geary_nonblocking_queue_peek_data_free (gpointer _data)
{
	GearyNonblockingQueuePeekData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->cancellable);
	((_data_->result == NULL) || (_data_->self->priv->g_destroy_func == NULL)) ? NULL : (_data_->result = (_data_->self->priv->g_destroy_func (_data_->result), NULL));
	_g_object_unref0 (_data_->self);
	g_slice_free (GearyNonblockingQueuePeekData, _data_);
}

void
geary_nonblocking_queue_peek (GearyNonblockingQueue* self,
                              GCancellable* cancellable,
                              GAsyncReadyCallback _callback_,
                              gpointer _user_data_)
{
	GearyNonblockingQueuePeekData* _data_;
	GearyNonblockingQueue* _tmp0_;
	GCancellable* _tmp1_;
	g_return_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self));
	g_return_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()));
	_data_ = g_slice_new0 (GearyNonblockingQueuePeekData);
	_data_->_async_result = g_task_new (G_OBJECT (self), cancellable, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, geary_nonblocking_queue_peek_data_free);
	_tmp0_ = _g_object_ref0 (self);
	_data_->self = _tmp0_;
	_tmp1_ = _g_object_ref0 (cancellable);
	_g_object_unref0 (_data_->cancellable);
	_data_->cancellable = _tmp1_;
	geary_nonblocking_queue_peek_co (_data_);
}

gpointer
geary_nonblocking_queue_peek_finish (GearyNonblockingQueue* self,
                                     GAsyncResult* _res_,
                                     GError** error)
{
	gpointer result;
	GearyNonblockingQueuePeekData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), error);
	if (NULL == _data_) {
		return NULL;
	}
	result = _data_->result;
	_data_->result = NULL;
	return result;
}

/**
     * Returns the next queued item without removal, blocking until available.
     *
     * If the queue is paused, this will continue to wait until
     * unpaused and an item is ready. If `cancellable` is non-null,
     * when used will cancel this call.
     */
static void
geary_nonblocking_queue_peek_ready (GObject* source_object,
                                    GAsyncResult* _res_,
                                    gpointer _user_data_)
{
	GearyNonblockingQueuePeekData* _data_;
	_data_ = _user_data_;
	_data_->_source_object_ = source_object;
	_data_->_res_ = _res_;
	geary_nonblocking_queue_peek_co (_data_);
}

static gboolean
geary_nonblocking_queue_peek_co (GearyNonblockingQueuePeekData* _data_)
{
	switch (_data_->_state_) {
		case 0:
		goto _state_0;
		case 1:
		goto _state_1;
		default:
		g_assert_not_reached ();
	}
	_state_0:
	{
		_data_->_tmp0_ = TRUE;
		while (TRUE) {
			if (!_data_->_tmp0_) {
			}
			_data_->_tmp0_ = FALSE;
			_data_->_tmp2_ = _data_->self->priv->queue;
			_data_->_tmp3_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp2_, GEE_TYPE_COLLECTION, GeeCollection));
			_data_->_tmp4_ = _data_->_tmp3_;
			if (_data_->_tmp4_ > 0) {
				_data_->_tmp5_ = geary_nonblocking_queue_get_is_paused (_data_->self);
				_data_->_tmp6_ = _data_->_tmp5_;
				_data_->_tmp1_ = !_data_->_tmp6_;
			} else {
				_data_->_tmp1_ = FALSE;
			}
			if (_data_->_tmp1_) {
				_data_->_tmp7_ = _data_->self->priv->queue;
				_data_->_tmp8_ = gee_queue_peek (_data_->_tmp7_);
				_data_->result = _data_->_tmp8_;
				g_task_return_pointer (_data_->_async_result, _data_, NULL);
				if (_data_->_state_ != 0) {
					while (!g_task_get_completed (_data_->_async_result)) {
						g_main_context_iteration (g_task_get_context (_data_->_async_result), TRUE);
					}
				}
				g_object_unref (_data_->_async_result);
				return FALSE;
			}
			_data_->_tmp9_ = _data_->self->priv->spinlock;
			_data_->_state_ = 1;
			geary_nonblocking_lock_wait_async (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp9_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock), _data_->cancellable, geary_nonblocking_queue_peek_ready, _data_);
			return FALSE;
			_state_1:
			geary_nonblocking_lock_wait_finish (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp9_, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock), _data_->_res_, &_data_->_inner_error0_);
			if (G_UNLIKELY (_data_->_inner_error0_ != NULL)) {
				g_task_return_error (_data_->_async_result, _data_->_inner_error0_);
				g_object_unref (_data_->_async_result);
				return FALSE;
			}
		}
	}
}

/**
     * Removes all items in queue, returning the number of removed items.
     */
gint
geary_nonblocking_queue_clear (GearyNonblockingQueue* self)
{
	gint count = 0;
	GeeQueue* _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	gint result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), -1);
	_tmp0_ = self->priv->queue;
	_tmp1_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp2_ = _tmp1_;
	count = _tmp2_;
	if (count != 0) {
		GeeQueue* _tmp3_;
		_tmp3_ = self->priv->queue;
		gee_collection_clear (G_TYPE_CHECK_INSTANCE_CAST (_tmp3_, GEE_TYPE_COLLECTION, GeeCollection));
	}
	result = count;
	return result;
}

/**
     * Removes an item from the queue, returning `true` if removed.
     */
gboolean
geary_nonblocking_queue_revoke (GearyNonblockingQueue* self,
                                gconstpointer msg)
{
	GeeQueue* _tmp0_;
	gboolean result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), FALSE);
	_tmp0_ = self->priv->queue;
	result = gee_collection_remove (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection), msg);
	return result;
}

/**
     * Remove items matching the given predicate, returning those removed.
     */
GeeCollection*
geary_nonblocking_queue_revoke_matching (GearyNonblockingQueue* self,
                                         GeePredicate predicate,
                                         gpointer predicate_target,
                                         GDestroyNotify predicate_target_destroy_notify)
{
	GeeArrayList* removed = NULL;
	GeeArrayList* _tmp0_;
	GeeQueue* _tmp1_;
	gint _tmp2_ = 0;
	gpointer* _tmp3_;
	GeeCollection* result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), NULL);
	_tmp0_ = gee_array_list_new (self->priv->g_type, (GBoxedCopyFunc) self->priv->g_dup_func, (GDestroyNotify) self->priv->g_destroy_func, NULL, NULL, NULL);
	removed = _tmp0_;
	_tmp1_ = self->priv->queue;
	_tmp3_ = gee_collection_to_array (G_TYPE_CHECK_INSTANCE_CAST (_tmp1_, GEE_TYPE_COLLECTION, GeeCollection), &_tmp2_);
	{
		gpointer* msg_collection = NULL;
		gint msg_collection_length1 = 0;
		gint _msg_collection_size_ = 0;
		gint msg_it = 0;
		msg_collection = _tmp3_;
		msg_collection_length1 = _tmp2_;
		for (msg_it = 0; msg_it < msg_collection_length1; msg_it = msg_it + 1) {
			gpointer _tmp4_;
			gpointer msg = NULL;
			_tmp4_ = ((msg_collection[msg_it] != NULL) && (self->priv->g_dup_func != NULL)) ? self->priv->g_dup_func ((gpointer) msg_collection[msg_it]) : ((gpointer) msg_collection[msg_it]);
			msg = _tmp4_;
			{
				gconstpointer _tmp5_;
				_tmp5_ = msg;
				if (predicate (_tmp5_, predicate_target)) {
					GeeQueue* _tmp6_;
					gconstpointer _tmp7_;
					GeeArrayList* _tmp8_;
					gconstpointer _tmp9_;
					_tmp6_ = self->priv->queue;
					_tmp7_ = msg;
					gee_collection_remove (G_TYPE_CHECK_INSTANCE_CAST (_tmp6_, GEE_TYPE_COLLECTION, GeeCollection), _tmp7_);
					_tmp8_ = removed;
					_tmp9_ = msg;
					gee_abstract_collection_add (G_TYPE_CHECK_INSTANCE_CAST (_tmp8_, GEE_TYPE_ABSTRACT_COLLECTION, GeeAbstractCollection), _tmp9_);
				}
				((msg == NULL) || (self->priv->g_destroy_func == NULL)) ? NULL : (msg = (self->priv->g_destroy_func (msg), NULL));
			}
		}
		msg_collection = (_vala_array_free (msg_collection, msg_collection_length1, (GDestroyNotify) self->priv->g_destroy_func), NULL);
	}
	result = G_TYPE_CHECK_INSTANCE_CAST (removed, GEE_TYPE_COLLECTION, GeeCollection);
	(predicate_target_destroy_notify == NULL) ? NULL : (predicate_target_destroy_notify (predicate_target), NULL);
	predicate = NULL;
	predicate_target = NULL;
	predicate_target_destroy_notify = NULL;
	return result;
}

/**
     * Returns a read-only version of the queue queue.
     *
     * Since the queue could potentially alter when the main loop
     * runs, it's important to only examine the queue when not
     * allowing other operations to process.
     */
GeeCollection*
geary_nonblocking_queue_get_all (GearyNonblockingQueue* self)
{
	GeeQueue* _tmp0_;
	GeeCollection* _tmp1_;
	GeeCollection* _tmp2_;
	GeeCollection* result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_QUEUE (self), NULL);
	_tmp0_ = self->priv->queue;
	_tmp1_ = gee_collection_get_read_only_view (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp2_ = _tmp1_;
	result = _tmp2_;
	return result;
}

static void
geary_nonblocking_queue_class_init (GearyNonblockingQueueClass * klass,
                                    gpointer klass_data)
{
	geary_nonblocking_queue_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GearyNonblockingQueue_private_offset);
	G_OBJECT_CLASS (klass)->get_property = _vala_geary_nonblocking_queue_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_geary_nonblocking_queue_set_property;
	G_OBJECT_CLASS (klass)->finalize = geary_nonblocking_queue_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_G_TYPE, g_param_spec_gtype ("g-type", "type", "type", G_TYPE_NONE, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_G_DUP_FUNC, g_param_spec_pointer ("g-dup-func", "dup func", "dup func", G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_G_DESTROY_FUNC, g_param_spec_pointer ("g-destroy-func", "destroy func", "destroy func", G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
	/** Returns the number of items currently in the queue. */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_SIZE_PROPERTY, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_SIZE_PROPERTY] = g_param_spec_int ("size", "size", "size", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/** Determines if any items are in the queue. */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_IS_EMPTY_PROPERTY, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_IS_EMPTY_PROPERTY] = g_param_spec_boolean ("is-empty", "is-empty", "is-empty", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/**
	     * Determines if duplicate items can be added to the queue.
	     *
	     * If a priory queue, this applies to items of the same priority,
	     * otherwise uses the item's natural identity.
	     */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_ALLOW_DUPLICATES_PROPERTY, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_ALLOW_DUPLICATES_PROPERTY] = g_param_spec_boolean ("allow-duplicates", "allow-duplicates", "allow-duplicates", TRUE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	/**
	     * Determines if duplicate items will be added to the queue.
	     *
	     * If {@link allow_duplicates} is `true` and an item is already in
	     * the queue, this determines if it will be added again.
	     */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_REQUEUE_DUPLICATE_PROPERTY, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_REQUEUE_DUPLICATE_PROPERTY] = g_param_spec_boolean ("requeue-duplicate", "requeue-duplicate", "requeue-duplicate", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	/**
	     * Determines if the queue is currently running.
	     */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_QUEUE_IS_PAUSED_PROPERTY, geary_nonblocking_queue_properties[GEARY_NONBLOCKING_QUEUE_IS_PAUSED_PROPERTY] = g_param_spec_boolean ("is-paused", "is-paused", "is-paused", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
}

static void
geary_nonblocking_queue_instance_init (GearyNonblockingQueue * self,
                                       gpointer klass)
{
	GearyNonblockingSpinlock* _tmp0_;
	self->priv = geary_nonblocking_queue_get_instance_private (self);
	self->priv->_allow_duplicates = TRUE;
	self->priv->_requeue_duplicate = FALSE;
	self->priv->_is_paused = FALSE;
	_tmp0_ = geary_nonblocking_spinlock_new (NULL);
	self->priv->spinlock = _tmp0_;
}

static void
geary_nonblocking_queue_finalize (GObject * obj)
{
	GearyNonblockingQueue * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GEARY_NONBLOCKING_TYPE_QUEUE, GearyNonblockingQueue);
	_g_object_unref0 (self->priv->queue);
	_g_object_unref0 (self->priv->spinlock);
	G_OBJECT_CLASS (geary_nonblocking_queue_parent_class)->finalize (obj);
}

/**
 * An asynchronous queue, first-in first-out (FIFO) or priority.
 *
 * This class can be used to asynchronously wait for items to be added
 * to the queue, the asynchronous call blocking until an item is
 * ready. Multiple asynchronous tasks can queue objects via {@link
 * send}, and tasks can wait for items via {@link receive}. If there
 * are multiple tasks waiting for items, the first to wait will
 * receive the next item.
 */
 G_GNUC_NO_INLINE static GType
geary_nonblocking_queue_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyNonblockingQueueClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_nonblocking_queue_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearyNonblockingQueue), 0, (GInstanceInitFunc) geary_nonblocking_queue_instance_init, NULL };
	GType geary_nonblocking_queue_type_id;
	geary_nonblocking_queue_type_id = g_type_register_static (GEARY_TYPE_BASE_OBJECT, "GearyNonblockingQueue", &g_define_type_info, 0);
	GearyNonblockingQueue_private_offset = g_type_add_instance_private (geary_nonblocking_queue_type_id, sizeof (GearyNonblockingQueuePrivate));
	return geary_nonblocking_queue_type_id;
}

GType
geary_nonblocking_queue_get_type (void)
{
	static gsize geary_nonblocking_queue_type_id__once = 0;
	if (g_once_init_enter (&geary_nonblocking_queue_type_id__once)) {
		GType geary_nonblocking_queue_type_id;
		geary_nonblocking_queue_type_id = geary_nonblocking_queue_get_type_once ();
		g_once_init_leave (&geary_nonblocking_queue_type_id__once, geary_nonblocking_queue_type_id);
	}
	return geary_nonblocking_queue_type_id__once;
}

static void
_vala_geary_nonblocking_queue_get_property (GObject * object,
                                            guint property_id,
                                            GValue * value,
                                            GParamSpec * pspec)
{
	GearyNonblockingQueue * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GEARY_NONBLOCKING_TYPE_QUEUE, GearyNonblockingQueue);
	switch (property_id) {
		case GEARY_NONBLOCKING_QUEUE_SIZE_PROPERTY:
		g_value_set_int (value, geary_nonblocking_queue_get_size (self));
		break;
		case GEARY_NONBLOCKING_QUEUE_IS_EMPTY_PROPERTY:
		g_value_set_boolean (value, geary_nonblocking_queue_get_is_empty (self));
		break;
		case GEARY_NONBLOCKING_QUEUE_ALLOW_DUPLICATES_PROPERTY:
		g_value_set_boolean (value, geary_nonblocking_queue_get_allow_duplicates (self));
		break;
		case GEARY_NONBLOCKING_QUEUE_REQUEUE_DUPLICATE_PROPERTY:
		g_value_set_boolean (value, geary_nonblocking_queue_get_requeue_duplicate (self));
		break;
		case GEARY_NONBLOCKING_QUEUE_IS_PAUSED_PROPERTY:
		g_value_set_boolean (value, geary_nonblocking_queue_get_is_paused (self));
		break;
		case GEARY_NONBLOCKING_QUEUE_G_TYPE:
		g_value_set_gtype (value, self->priv->g_type);
		break;
		case GEARY_NONBLOCKING_QUEUE_G_DUP_FUNC:
		g_value_set_pointer (value, self->priv->g_dup_func);
		break;
		case GEARY_NONBLOCKING_QUEUE_G_DESTROY_FUNC:
		g_value_set_pointer (value, self->priv->g_destroy_func);
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_geary_nonblocking_queue_set_property (GObject * object,
                                            guint property_id,
                                            const GValue * value,
                                            GParamSpec * pspec)
{
	GearyNonblockingQueue * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GEARY_NONBLOCKING_TYPE_QUEUE, GearyNonblockingQueue);
	switch (property_id) {
		case GEARY_NONBLOCKING_QUEUE_ALLOW_DUPLICATES_PROPERTY:
		geary_nonblocking_queue_set_allow_duplicates (self, g_value_get_boolean (value));
		break;
		case GEARY_NONBLOCKING_QUEUE_REQUEUE_DUPLICATE_PROPERTY:
		geary_nonblocking_queue_set_requeue_duplicate (self, g_value_get_boolean (value));
		break;
		case GEARY_NONBLOCKING_QUEUE_IS_PAUSED_PROPERTY:
		geary_nonblocking_queue_set_is_paused (self, g_value_get_boolean (value));
		break;
		case GEARY_NONBLOCKING_QUEUE_G_TYPE:
		self->priv->g_type = g_value_get_gtype (value);
		break;
		case GEARY_NONBLOCKING_QUEUE_G_DUP_FUNC:
		self->priv->g_dup_func = g_value_get_pointer (value);
		break;
		case GEARY_NONBLOCKING_QUEUE_G_DESTROY_FUNC:
		self->priv->g_destroy_func = g_value_get_pointer (value);
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_array_destroy (gpointer array,
                     gssize array_length,
                     GDestroyNotify destroy_func)
{
	if ((array != NULL) && (destroy_func != NULL)) {
		gssize i;
		for (i = 0; i < array_length; i = i + 1) {
			if (((gpointer*) array)[i] != NULL) {
				destroy_func (((gpointer*) array)[i]);
			}
		}
	}
}

static void
_vala_array_free (gpointer array,
                  gssize array_length,
                  GDestroyNotify destroy_func)
{
	_vala_array_destroy (array, array_length, destroy_func);
	g_free (array);
}

