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

/*
 * Copyright 2016 Software Freedom Conservancy Inc.
 * Copyright 2018 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 <gio/gio.h>
#include <gee.h>
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>

#define GEARY_NONBLOCKING_LOCK_TYPE_PENDING (geary_nonblocking_lock_pending_get_type ())
#define GEARY_NONBLOCKING_LOCK_PENDING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEARY_NONBLOCKING_LOCK_TYPE_PENDING, GearyNonblockingLockPending))
#define GEARY_NONBLOCKING_LOCK_PENDING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEARY_NONBLOCKING_LOCK_TYPE_PENDING, GearyNonblockingLockPendingClass))
#define GEARY_NONBLOCKING_LOCK_IS_PENDING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEARY_NONBLOCKING_LOCK_TYPE_PENDING))
#define GEARY_NONBLOCKING_LOCK_IS_PENDING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEARY_NONBLOCKING_LOCK_TYPE_PENDING))
#define GEARY_NONBLOCKING_LOCK_PENDING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEARY_NONBLOCKING_LOCK_TYPE_PENDING, GearyNonblockingLockPendingClass))

typedef struct _GearyNonblockingLockPending GearyNonblockingLockPending;
typedef struct _GearyNonblockingLockPendingClass GearyNonblockingLockPendingClass;
enum  {
	GEARY_NONBLOCKING_LOCK_0_PROPERTY,
	GEARY_NONBLOCKING_LOCK_CAN_PASS_PROPERTY,
	GEARY_NONBLOCKING_LOCK_IS_CANCELLED_PROPERTY,
	GEARY_NONBLOCKING_LOCK_NUM_PROPERTIES
};
static GParamSpec* geary_nonblocking_lock_properties[GEARY_NONBLOCKING_LOCK_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
typedef struct _GearyNonblockingLockPendingPrivate GearyNonblockingLockPendingPrivate;
typedef struct _GearyNonblockingLockWaitAsyncData GearyNonblockingLockWaitAsyncData;
enum  {
	GEARY_NONBLOCKING_LOCK_PENDING_0_PROPERTY,
	GEARY_NONBLOCKING_LOCK_PENDING_NUM_PROPERTIES
};
static GParamSpec* geary_nonblocking_lock_pending_properties[GEARY_NONBLOCKING_LOCK_PENDING_NUM_PROPERTIES];
enum  {
	GEARY_NONBLOCKING_LOCK_PENDING_CANCELLED_SIGNAL,
	GEARY_NONBLOCKING_LOCK_PENDING_NUM_SIGNALS
};
static guint geary_nonblocking_lock_pending_signals[GEARY_NONBLOCKING_LOCK_PENDING_NUM_SIGNALS] = {0};
#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 _GearyNonblockingLockPrivate {
	gboolean broadcast;
	gboolean autoreset;
	GCancellable* cancellable;
	gboolean passed;
	GeeList* pending_queue;
};

struct _GearyNonblockingLockPending {
	GearyBaseObject parent_instance;
	GSourceFunc cb;
	gpointer cb_target;
	GCancellable* cancellable;
	gboolean passed;
	gboolean scheduled;
	GearyNonblockingLockPendingPrivate * priv;
};

struct _GearyNonblockingLockPendingClass {
	GearyBaseObjectClass parent_class;
};

struct _GearyNonblockingLockWaitAsyncData {
	int _state_;
	GObject* _source_object_;
	GAsyncResult* _res_;
	GTask* _async_result;
	GearyNonblockingLock* self;
	GCancellable* cancellable;
	gboolean _tmp0_;
	GearyNonblockingLockPending* pending;
	GearyNonblockingLockPending* _tmp1_;
	GearyNonblockingLockPending* _tmp2_;
	GeeList* _tmp3_;
	GearyNonblockingLockPending* _tmp4_;
	GearyNonblockingLockPending* _tmp5_;
	guint _tmp6_;
	GearyNonblockingLockPending* _tmp7_;
	GError* _inner_error0_;
};

static gint GearyNonblockingLock_private_offset;
static gpointer geary_nonblocking_lock_parent_class = NULL;
static gpointer geary_nonblocking_lock_pending_parent_class = NULL;

static GType geary_nonblocking_lock_pending_get_type (void) G_GNUC_CONST  G_GNUC_UNUSED ;
static void geary_nonblocking_lock_on_pending_cancelled (GearyNonblockingLock* self,
                                                  GearyNonblockingLockPending* pending);
static void _geary_nonblocking_lock_on_pending_cancelled_geary_nonblocking_lock_pending_cancelled (GearyNonblockingLockPending* _sender,
                                                                                            gpointer self);
static void geary_nonblocking_lock_on_cancelled (GearyNonblockingLock* self);
static void _geary_nonblocking_lock_on_cancelled_g_cancellable_cancelled (GCancellable* _sender,
                                                                   gpointer self);
static void geary_nonblocking_lock_trigger (GearyNonblockingLock* self,
                                     gboolean all);
static void geary_nonblocking_lock_pending_schedule (GearyNonblockingLockPending* self,
                                              gboolean passed);
static void geary_nonblocking_lock_real_notify (GearyNonblockingLock* self,
                                         GError** error);
static void geary_nonblocking_lock_check_cancelled (GearyNonblockingLock* self,
                                             GError** error);
static void geary_nonblocking_lock_real_wait_async_data_free (gpointer _data);
static void geary_nonblocking_lock_real_wait_async (GearyNonblockingLock* self,
                                             GCancellable* cancellable,
                                             GAsyncReadyCallback _callback_,
                                             gpointer _user_data_);
static gboolean geary_nonblocking_lock_real_wait_async_co (GearyNonblockingLockWaitAsyncData* _data_);
static void geary_nonblocking_lock_check_user_cancelled (GCancellable* cancellable,
                                                  GError** error);
static gboolean _geary_nonblocking_lock_real_wait_async_co_gsource_func (gpointer self);
static GearyNonblockingLockPending* geary_nonblocking_lock_pending_new (GSourceFunc cb,
                                                                 gpointer cb_target,
                                                                 GCancellable* cancellable);
static GearyNonblockingLockPending* geary_nonblocking_lock_pending_construct (GType object_type,
                                                                       GSourceFunc cb,
                                                                       gpointer cb_target,
                                                                       GCancellable* cancellable);
static void geary_nonblocking_lock_real_reset (GearyNonblockingLock* self);
static void geary_nonblocking_lock_pending_on_cancelled (GearyNonblockingLockPending* self);
static void _geary_nonblocking_lock_pending_on_cancelled_g_cancellable_cancelled (GCancellable* _sender,
                                                                           gpointer self);
static void geary_nonblocking_lock_pending_finalize (GObject * obj);
static GType geary_nonblocking_lock_pending_get_type_once (void);
static void geary_nonblocking_lock_finalize (GObject * obj);
static GType geary_nonblocking_lock_get_type_once (void);
static void _vala_geary_nonblocking_lock_get_property (GObject * object,
                                                guint property_id,
                                                GValue * value,
                                                GParamSpec * pspec);

static inline gpointer
geary_nonblocking_lock_get_instance_private (GearyNonblockingLock* self)
{
	return G_STRUCT_MEMBER_P (self, GearyNonblockingLock_private_offset);
}

static void
_geary_nonblocking_lock_on_pending_cancelled_geary_nonblocking_lock_pending_cancelled (GearyNonblockingLockPending* _sender,
                                                                                       gpointer self)
{
	geary_nonblocking_lock_on_pending_cancelled ((GearyNonblockingLock*) self, _sender);
}

static void
_geary_nonblocking_lock_on_cancelled_g_cancellable_cancelled (GCancellable* _sender,
                                                              gpointer self)
{
	geary_nonblocking_lock_on_cancelled ((GearyNonblockingLock*) self);
}

gboolean
geary_nonblocking_lock_get_can_pass (GearyNonblockingLock* self)
{
	gboolean result;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_LOCK (self), FALSE);
	result = self->priv->passed;
	return result;
}

gboolean
geary_nonblocking_lock_get_is_cancelled (GearyNonblockingLock* self)
{
	gboolean result;
	gboolean _tmp0_ = FALSE;
	GCancellable* _tmp1_;
	g_return_val_if_fail (GEARY_NONBLOCKING_IS_LOCK (self), FALSE);
	_tmp1_ = self->priv->cancellable;
	if (_tmp1_ != NULL) {
		GCancellable* _tmp2_;
		_tmp2_ = self->priv->cancellable;
		_tmp0_ = g_cancellable_is_cancelled (_tmp2_);
	} else {
		_tmp0_ = FALSE;
	}
	result = _tmp0_;
	return result;
}

/**
     * Constructs a new lock that is initially not able to be passed.
     */
static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

GearyNonblockingLock*
geary_nonblocking_lock_construct (GType object_type,
                                  gboolean broadcast,
                                  gboolean autoreset,
                                  GCancellable* cancellable)
{
	GearyNonblockingLock * self = NULL;
	GCancellable* _tmp0_;
	g_return_val_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()), NULL);
	self = (GearyNonblockingLock*) geary_base_object_construct (object_type);
	self->priv->broadcast = broadcast;
	self->priv->autoreset = autoreset;
	_tmp0_ = _g_object_ref0 (cancellable);
	_g_object_unref0 (self->priv->cancellable);
	self->priv->cancellable = _tmp0_;
	if (cancellable != NULL) {
		g_signal_connect_object (cancellable, "cancelled", (GCallback) _geary_nonblocking_lock_on_cancelled_g_cancellable_cancelled, self, 0);
	}
	return self;
}

static void
geary_nonblocking_lock_trigger (GearyNonblockingLock* self,
                                gboolean all)
{
	GeeList* _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	g_return_if_fail (GEARY_NONBLOCKING_IS_LOCK (self));
	_tmp0_ = self->priv->pending_queue;
	_tmp1_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp2_ = _tmp1_;
	if (_tmp2_ == 0) {
		return;
	}
	if (all) {
		GeeList* _tmp12_;
		{
			GeeList* _pending_list = NULL;
			GeeList* _tmp3_;
			gint _pending_size = 0;
			GeeList* _tmp4_;
			gint _tmp5_;
			gint _tmp6_;
			gint _pending_index = 0;
			_tmp3_ = self->priv->pending_queue;
			_pending_list = _tmp3_;
			_tmp4_ = _pending_list;
			_tmp5_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp4_, GEE_TYPE_COLLECTION, GeeCollection));
			_tmp6_ = _tmp5_;
			_pending_size = _tmp6_;
			_pending_index = -1;
			while (TRUE) {
				gint _tmp7_;
				gint _tmp8_;
				GearyNonblockingLockPending* pending = NULL;
				GeeList* _tmp9_;
				gpointer _tmp10_;
				GearyNonblockingLockPending* _tmp11_;
				_pending_index = _pending_index + 1;
				_tmp7_ = _pending_index;
				_tmp8_ = _pending_size;
				if (!(_tmp7_ < _tmp8_)) {
					break;
				}
				_tmp9_ = _pending_list;
				_tmp10_ = gee_list_get (_tmp9_, _pending_index);
				pending = (GearyNonblockingLockPending*) _tmp10_;
				_tmp11_ = pending;
				geary_nonblocking_lock_pending_schedule (_tmp11_, self->priv->passed);
				_g_object_unref0 (pending);
			}
		}
		_tmp12_ = self->priv->pending_queue;
		gee_collection_clear (G_TYPE_CHECK_INSTANCE_CAST (_tmp12_, GEE_TYPE_COLLECTION, GeeCollection));
	} else {
		GearyNonblockingLockPending* pending = NULL;
		GeeList* _tmp13_;
		gpointer _tmp14_;
		GearyNonblockingLockPending* _tmp15_;
		_tmp13_ = self->priv->pending_queue;
		_tmp14_ = gee_list_remove_at (_tmp13_, 0);
		pending = (GearyNonblockingLockPending*) _tmp14_;
		_tmp15_ = pending;
		geary_nonblocking_lock_pending_schedule (_tmp15_, self->priv->passed);
		_g_object_unref0 (pending);
	}
}

/**
     * Marks the lock as being safe to pass.
     *
     * Asynchronous tasks waiting on this lock via a call to {@link
     * wait_async} are resumed when this method is called. If this
     * lock is broadcasting then all pending tasks are released,
     * otherwise only the first in the queue is released.
     *
     * @throws GLib.IOError.CANCELLED if either the lock is cancelled
     * or the caller's `cancellable` argument is cancelled.
     */
static void
geary_nonblocking_lock_real_notify (GearyNonblockingLock* self,
                                    GError** error)
{
	GError* _inner_error0_ = NULL;
	geary_nonblocking_lock_check_cancelled (self, &_inner_error0_);
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		g_propagate_error (error, _inner_error0_);
		return;
	}
	self->priv->passed = TRUE;
	geary_nonblocking_lock_trigger (self, self->priv->broadcast);
	if (self->priv->autoreset) {
		geary_nonblocking_lock_reset (self);
	}
}

void
geary_nonblocking_lock_notify (GearyNonblockingLock* self,
                               GError** error)
{
	GearyNonblockingLockClass* _klass_;
	g_return_if_fail (GEARY_NONBLOCKING_IS_LOCK (self));
	_klass_ = GEARY_NONBLOCKING_LOCK_GET_CLASS (self);
	if (_klass_->notify) {
		_klass_->notify (self, error);
	}
}

/**
     * Calls {@link notify} without throwing an exception.
     *
     * If an error is thrown, it is logged but otherwise ignored.
     */
void
geary_nonblocking_lock_blind_notify (GearyNonblockingLock* self)
{
	GError* _inner_error0_ = NULL;
	g_return_if_fail (GEARY_NONBLOCKING_IS_LOCK (self));
	{
		geary_nonblocking_lock_notify (self, &_inner_error0_);
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			goto __catch0_g_error;
		}
	}
	goto __finally0;
	__catch0_g_error:
	{
		GError* err = NULL;
		GError* _tmp0_;
		const gchar* _tmp1_;
		err = _inner_error0_;
		_inner_error0_ = NULL;
		_tmp0_ = err;
		_tmp1_ = _tmp0_->message;
		g_message ("nonblocking-lock.vala:160: Error notifying lock: %s", _tmp1_);
		_g_error_free0 (err);
	}
	__finally0:
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
		g_clear_error (&_inner_error0_);
		return;
	}
}

static void
geary_nonblocking_lock_real_wait_async_data_free (gpointer _data)
{
	GearyNonblockingLockWaitAsyncData* _data_;
	_data_ = _data;
	_g_object_unref0 (_data_->cancellable);
	_g_object_unref0 (_data_->self);
	g_slice_free (GearyNonblockingLockWaitAsyncData, _data_);
}

static void
geary_nonblocking_lock_real_wait_async (GearyNonblockingLock* self,
                                        GCancellable* cancellable,
                                        GAsyncReadyCallback _callback_,
                                        gpointer _user_data_)
{
	GearyNonblockingLockWaitAsyncData* _data_;
	GearyNonblockingLock* _tmp0_;
	GCancellable* _tmp1_;
	g_return_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()));
	_data_ = g_slice_new0 (GearyNonblockingLockWaitAsyncData);
	_data_->_async_result = g_task_new (G_OBJECT (self), cancellable, _callback_, _user_data_);
	g_task_set_task_data (_data_->_async_result, _data_, geary_nonblocking_lock_real_wait_async_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_lock_real_wait_async_co (_data_);
}

static void
geary_nonblocking_lock_real_wait_finish (GearyNonblockingLock* self,
                                         GAsyncResult* _res_,
                                         GError** error)
{
	GearyNonblockingLockWaitAsyncData* _data_;
	_data_ = g_task_propagate_pointer (G_TASK (_res_), error);
	if (NULL == _data_) {
		return;
	}
}

/**
     * Waits for the lock to be marked as being safe to pass.
     *
     * If the lock is already marked as being safe to pass, then this
     * method will return immediately. If not, the call to this method
     * will yield and not resume until the lock as been marked as safe
     * by a call to {@link notify}.
     *
     * @throws GLib.IOError.CANCELLED if either the lock is cancelled or
     * the caller's `cancellable` argument is cancelled.
     */
static gboolean
_geary_nonblocking_lock_real_wait_async_co_gsource_func (gpointer self)
{
	gboolean result;
	result = geary_nonblocking_lock_real_wait_async_co (self);
	return result;
}

static gboolean
geary_nonblocking_lock_real_wait_async_co (GearyNonblockingLockWaitAsyncData* _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;
			geary_nonblocking_lock_check_user_cancelled (_data_->cancellable, &_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;
			}
			geary_nonblocking_lock_check_cancelled (_data_->self, &_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;
			}
			if (_data_->self->priv->passed) {
				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_->_tmp1_ = geary_nonblocking_lock_pending_new (_geary_nonblocking_lock_real_wait_async_co_gsource_func, _data_, _data_->cancellable);
			_data_->pending = _data_->_tmp1_;
			_data_->_tmp2_ = _data_->pending;
			g_signal_connect_object (_data_->_tmp2_, "cancelled", (GCallback) _geary_nonblocking_lock_on_pending_cancelled_geary_nonblocking_lock_pending_cancelled, _data_->self, 0);
			_data_->_tmp3_ = _data_->self->priv->pending_queue;
			_data_->_tmp4_ = _data_->pending;
			gee_collection_add (G_TYPE_CHECK_INSTANCE_CAST (_data_->_tmp3_, GEE_TYPE_COLLECTION, GeeCollection), _data_->_tmp4_);
			_data_->_state_ = 1;
			return FALSE;
			_state_1:
			;
			_data_->_tmp5_ = _data_->pending;
			g_signal_parse_name ("cancelled", GEARY_NONBLOCKING_LOCK_TYPE_PENDING, &_data_->_tmp6_, NULL, FALSE);
			g_signal_handlers_disconnect_matched (_data_->_tmp5_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _data_->_tmp6_, 0, NULL, (GCallback) _geary_nonblocking_lock_on_pending_cancelled_geary_nonblocking_lock_pending_cancelled, _data_->self);
			_data_->_tmp7_ = _data_->pending;
			if (_data_->_tmp7_->passed) {
				geary_nonblocking_lock_check_user_cancelled (_data_->cancellable, &_data_->_inner_error0_);
				if (G_UNLIKELY (_data_->_inner_error0_ != NULL)) {
					g_task_return_error (_data_->_async_result, _data_->_inner_error0_);
					_g_object_unref0 (_data_->pending);
					g_object_unref (_data_->_async_result);
					return FALSE;
				}
				_g_object_unref0 (_data_->pending);
				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;
			}
			_g_object_unref0 (_data_->pending);
		}
	}
	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;
}

void
geary_nonblocking_lock_wait_async (GearyNonblockingLock* self,
                                   GCancellable* cancellable,
                                   GAsyncReadyCallback _callback_,
                                   gpointer _user_data_)
{
	GearyNonblockingLockClass* _klass_;
	_klass_ = GEARY_NONBLOCKING_LOCK_GET_CLASS (self);
	if (_klass_->wait_async) {
		_klass_->wait_async (self, cancellable, _callback_, _user_data_);
	}
}

void
geary_nonblocking_lock_wait_finish (GearyNonblockingLock* self,
                                    GAsyncResult* _res_,
                                    GError** error)
{
	GearyNonblockingLockClass* _klass_;
	_klass_ = GEARY_NONBLOCKING_LOCK_GET_CLASS (self);
	if (_klass_->wait_finish) {
		_klass_->wait_finish (self, _res_, error);
	}
}

/**
     * Marks this lock as being unsafe to pass.
     */
static void
geary_nonblocking_lock_real_reset (GearyNonblockingLock* self)
{
	self->priv->passed = FALSE;
}

void
geary_nonblocking_lock_reset (GearyNonblockingLock* self)
{
	GearyNonblockingLockClass* _klass_;
	g_return_if_fail (GEARY_NONBLOCKING_IS_LOCK (self));
	_klass_ = GEARY_NONBLOCKING_LOCK_GET_CLASS (self);
	if (_klass_->reset) {
		_klass_->reset (self);
	}
}

static void
geary_nonblocking_lock_check_cancelled (GearyNonblockingLock* self,
                                        GError** error)
{
	gboolean _tmp0_;
	gboolean _tmp1_;
	GError* _inner_error0_ = NULL;
	g_return_if_fail (GEARY_NONBLOCKING_IS_LOCK (self));
	_tmp0_ = geary_nonblocking_lock_get_is_cancelled (self);
	_tmp1_ = _tmp0_;
	if (_tmp1_) {
		GError* _tmp2_;
		_tmp2_ = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Lock was cancelled");
		_inner_error0_ = _tmp2_;
		g_propagate_error (error, _inner_error0_);
		return;
	}
}

static void
geary_nonblocking_lock_check_user_cancelled (GCancellable* cancellable,
                                             GError** error)
{
	gboolean _tmp0_ = FALSE;
	GError* _inner_error0_ = NULL;
	g_return_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()));
	if (cancellable != NULL) {
		_tmp0_ = g_cancellable_is_cancelled (cancellable);
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		GError* _tmp1_;
		_tmp1_ = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "User cancelled lock operation");
		_inner_error0_ = _tmp1_;
		g_propagate_error (error, _inner_error0_);
		return;
	}
}

static void
geary_nonblocking_lock_on_pending_cancelled (GearyNonblockingLock* self,
                                             GearyNonblockingLockPending* pending)
{
	gboolean removed = FALSE;
	GeeList* _tmp0_;
	GSourceFunc _tmp1_;
	gpointer _tmp1__target;
	GearySchedulerScheduled* _tmp2_;
	GearySchedulerScheduled* _tmp3_;
	g_return_if_fail (GEARY_NONBLOCKING_IS_LOCK (self));
	g_return_if_fail (GEARY_NONBLOCKING_LOCK_IS_PENDING (pending));
	if (pending->scheduled) {
		return;
	}
	_tmp0_ = self->priv->pending_queue;
	removed = gee_collection_remove (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection), pending);
	_vala_assert (removed, "removed");
	_tmp1_ = pending->cb;
	_tmp1__target = pending->cb_target;
	_tmp2_ = geary_scheduler_on_idle (_tmp1_, _tmp1__target, G_PRIORITY_DEFAULT_IDLE);
	_tmp3_ = _tmp2_;
	_g_object_unref0 (_tmp3_);
}

static void
geary_nonblocking_lock_on_cancelled (GearyNonblockingLock* self)
{
	g_return_if_fail (GEARY_NONBLOCKING_IS_LOCK (self));
	geary_nonblocking_lock_trigger (self, TRUE);
}

static void
_geary_nonblocking_lock_pending_on_cancelled_g_cancellable_cancelled (GCancellable* _sender,
                                                                      gpointer self)
{
	geary_nonblocking_lock_pending_on_cancelled ((GearyNonblockingLockPending*) self);
}

static GearyNonblockingLockPending*
geary_nonblocking_lock_pending_construct (GType object_type,
                                          GSourceFunc cb,
                                          gpointer cb_target,
                                          GCancellable* cancellable)
{
	GearyNonblockingLockPending * self = NULL;
	GCancellable* _tmp0_;
	g_return_val_if_fail ((cancellable == NULL) || G_TYPE_CHECK_INSTANCE_TYPE (cancellable, g_cancellable_get_type ()), NULL);
	self = (GearyNonblockingLockPending*) geary_base_object_construct (object_type);
	self->cb = cb;
	self->cb_target = cb_target;
	_tmp0_ = _g_object_ref0 (cancellable);
	_g_object_unref0 (self->cancellable);
	self->cancellable = _tmp0_;
	if (cancellable != NULL) {
		g_signal_connect_object (cancellable, "cancelled", (GCallback) _geary_nonblocking_lock_pending_on_cancelled_g_cancellable_cancelled, self, 0);
	}
	return self;
}

static GearyNonblockingLockPending*
geary_nonblocking_lock_pending_new (GSourceFunc cb,
                                    gpointer cb_target,
                                    GCancellable* cancellable)
{
	return geary_nonblocking_lock_pending_construct (GEARY_NONBLOCKING_LOCK_TYPE_PENDING, cb, cb_target, cancellable);
}

static void
geary_nonblocking_lock_pending_on_cancelled (GearyNonblockingLockPending* self)
{
	g_return_if_fail (GEARY_NONBLOCKING_LOCK_IS_PENDING (self));
	g_signal_emit (self, geary_nonblocking_lock_pending_signals[GEARY_NONBLOCKING_LOCK_PENDING_CANCELLED_SIGNAL], 0);
}

static void
geary_nonblocking_lock_pending_schedule (GearyNonblockingLockPending* self,
                                         gboolean passed)
{
	GSourceFunc _tmp0_;
	gpointer _tmp0__target;
	GearySchedulerScheduled* _tmp1_;
	GearySchedulerScheduled* _tmp2_;
	g_return_if_fail (GEARY_NONBLOCKING_LOCK_IS_PENDING (self));
	_vala_assert (!self->scheduled, "!scheduled");
	self->passed = passed;
	_tmp0_ = self->cb;
	_tmp0__target = self->cb_target;
	_tmp1_ = geary_scheduler_on_idle (_tmp0_, _tmp0__target, G_PRIORITY_DEFAULT_IDLE);
	_tmp2_ = _tmp1_;
	_g_object_unref0 (_tmp2_);
	self->scheduled = TRUE;
}

static void
geary_nonblocking_lock_pending_class_init (GearyNonblockingLockPendingClass * klass,
                                           gpointer klass_data)
{
	geary_nonblocking_lock_pending_parent_class = g_type_class_peek_parent (klass);
	G_OBJECT_CLASS (klass)->finalize = geary_nonblocking_lock_pending_finalize;
	geary_nonblocking_lock_pending_signals[GEARY_NONBLOCKING_LOCK_PENDING_CANCELLED_SIGNAL] = g_signal_new ("cancelled", GEARY_NONBLOCKING_LOCK_TYPE_PENDING, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

static void
geary_nonblocking_lock_pending_instance_init (GearyNonblockingLockPending * self,
                                              gpointer klass)
{
	self->passed = FALSE;
	self->scheduled = FALSE;
}

static void
geary_nonblocking_lock_pending_finalize (GObject * obj)
{
	GearyNonblockingLockPending * self;
	GCancellable* _tmp0_;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GEARY_NONBLOCKING_LOCK_TYPE_PENDING, GearyNonblockingLockPending);
	_tmp0_ = self->cancellable;
	if (_tmp0_ != NULL) {
		GCancellable* _tmp1_;
		guint _tmp2_;
		_tmp1_ = self->cancellable;
		g_signal_parse_name ("cancelled", g_cancellable_get_type (), &_tmp2_, NULL, FALSE);
		g_signal_handlers_disconnect_matched (_tmp1_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp2_, 0, NULL, (GCallback) _geary_nonblocking_lock_pending_on_cancelled_g_cancellable_cancelled, self);
	}
	_g_object_unref0 (self->cancellable);
	G_OBJECT_CLASS (geary_nonblocking_lock_pending_parent_class)->finalize (obj);
}

 G_GNUC_NO_INLINE static GType
geary_nonblocking_lock_pending_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyNonblockingLockPendingClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_nonblocking_lock_pending_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearyNonblockingLockPending), 0, (GInstanceInitFunc) geary_nonblocking_lock_pending_instance_init, NULL };
	GType geary_nonblocking_lock_pending_type_id;
	geary_nonblocking_lock_pending_type_id = g_type_register_static (GEARY_TYPE_BASE_OBJECT, "GearyNonblockingLockPending", &g_define_type_info, 0);
	return geary_nonblocking_lock_pending_type_id;
}

static GType
geary_nonblocking_lock_pending_get_type (void)
{
	static gsize geary_nonblocking_lock_pending_type_id__once = 0;
	if (g_once_init_enter (&geary_nonblocking_lock_pending_type_id__once)) {
		GType geary_nonblocking_lock_pending_type_id;
		geary_nonblocking_lock_pending_type_id = geary_nonblocking_lock_pending_get_type_once ();
		g_once_init_leave (&geary_nonblocking_lock_pending_type_id__once, geary_nonblocking_lock_pending_type_id);
	}
	return geary_nonblocking_lock_pending_type_id__once;
}

static void
geary_nonblocking_lock_class_init (GearyNonblockingLockClass * klass,
                                   gpointer klass_data)
{
	geary_nonblocking_lock_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GearyNonblockingLock_private_offset);
	((GearyNonblockingLockClass *) klass)->notify = (void (*) (GearyNonblockingLock*, GError**)) geary_nonblocking_lock_real_notify;
	((GearyNonblockingLockClass *) klass)->wait_async = (void (*) (GearyNonblockingLock*, GCancellable*, GAsyncReadyCallback, gpointer)) geary_nonblocking_lock_real_wait_async;
	((GearyNonblockingLockClass *) klass)->wait_finish = (void (*) (GearyNonblockingLock*, GAsyncResult*, GError**)) geary_nonblocking_lock_real_wait_finish;
	((GearyNonblockingLockClass *) klass)->reset = (void (*) (GearyNonblockingLock*)) geary_nonblocking_lock_real_reset;
	G_OBJECT_CLASS (klass)->get_property = _vala_geary_nonblocking_lock_get_property;
	G_OBJECT_CLASS (klass)->finalize = geary_nonblocking_lock_finalize;
	/** Determines if this lock is marked as safe to pass. */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_LOCK_CAN_PASS_PROPERTY, geary_nonblocking_lock_properties[GEARY_NONBLOCKING_LOCK_CAN_PASS_PROPERTY] = g_param_spec_boolean ("can-pass", "can-pass", "can-pass", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	/** Determines if this lock has been cancelled. */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GEARY_NONBLOCKING_LOCK_IS_CANCELLED_PROPERTY, geary_nonblocking_lock_properties[GEARY_NONBLOCKING_LOCK_IS_CANCELLED_PROPERTY] = g_param_spec_boolean ("is-cancelled", "is-cancelled", "is-cancelled", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
}

static void
geary_nonblocking_lock_instance_init (GearyNonblockingLock * self,
                                      gpointer klass)
{
	GeeLinkedList* _tmp0_;
	self->priv = geary_nonblocking_lock_get_instance_private (self);
	self->priv->passed = FALSE;
	_tmp0_ = gee_linked_list_new (GEARY_NONBLOCKING_LOCK_TYPE_PENDING, (GBoxedCopyFunc) g_object_ref, (GDestroyNotify) g_object_unref, NULL, NULL, NULL);
	self->priv->pending_queue = G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_LIST, GeeList);
}

static void
geary_nonblocking_lock_finalize (GObject * obj)
{
	GearyNonblockingLock * self;
	GeeList* _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	GCancellable* _tmp16_;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock);
	_tmp0_ = self->priv->pending_queue;
	_tmp1_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, GEE_TYPE_COLLECTION, GeeCollection));
	_tmp2_ = _tmp1_;
	if (_tmp2_ > 0) {
		GeeList* _tmp3_;
		gint _tmp4_;
		gint _tmp5_;
		_tmp3_ = self->priv->pending_queue;
		_tmp4_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp3_, GEE_TYPE_COLLECTION, GeeCollection));
		_tmp5_ = _tmp4_;
		g_warning ("nonblocking-lock.vala:102: Nonblocking lock destroyed with %d pending " \
"callers", _tmp5_);
		{
			GeeList* _pending_list = NULL;
			GeeList* _tmp6_;
			gint _pending_size = 0;
			GeeList* _tmp7_;
			gint _tmp8_;
			gint _tmp9_;
			gint _pending_index = 0;
			_tmp6_ = self->priv->pending_queue;
			_pending_list = _tmp6_;
			_tmp7_ = _pending_list;
			_tmp8_ = gee_collection_get_size (G_TYPE_CHECK_INSTANCE_CAST (_tmp7_, GEE_TYPE_COLLECTION, GeeCollection));
			_tmp9_ = _tmp8_;
			_pending_size = _tmp9_;
			_pending_index = -1;
			while (TRUE) {
				gint _tmp10_;
				gint _tmp11_;
				GearyNonblockingLockPending* pending = NULL;
				GeeList* _tmp12_;
				gpointer _tmp13_;
				GearyNonblockingLockPending* _tmp14_;
				guint _tmp15_;
				_pending_index = _pending_index + 1;
				_tmp10_ = _pending_index;
				_tmp11_ = _pending_size;
				if (!(_tmp10_ < _tmp11_)) {
					break;
				}
				_tmp12_ = _pending_list;
				_tmp13_ = gee_list_get (_tmp12_, _pending_index);
				pending = (GearyNonblockingLockPending*) _tmp13_;
				_tmp14_ = pending;
				g_signal_parse_name ("cancelled", GEARY_NONBLOCKING_LOCK_TYPE_PENDING, &_tmp15_, NULL, FALSE);
				g_signal_handlers_disconnect_matched (_tmp14_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp15_, 0, NULL, (GCallback) _geary_nonblocking_lock_on_pending_cancelled_geary_nonblocking_lock_pending_cancelled, self);
				_g_object_unref0 (pending);
			}
		}
	}
	_tmp16_ = self->priv->cancellable;
	if (_tmp16_ != NULL) {
		GCancellable* _tmp17_;
		guint _tmp18_;
		_tmp17_ = self->priv->cancellable;
		g_signal_parse_name ("cancelled", g_cancellable_get_type (), &_tmp18_, NULL, FALSE);
		g_signal_handlers_disconnect_matched (_tmp17_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp18_, 0, NULL, (GCallback) _geary_nonblocking_lock_on_cancelled_g_cancellable_cancelled, self);
	}
	_g_object_unref0 (self->priv->cancellable);
	_g_object_unref0 (self->priv->pending_queue);
	G_OBJECT_CLASS (geary_nonblocking_lock_parent_class)->finalize (obj);
}

/**
 * A generic asynchronous lock data type.
 *
 * This class provides an asynchronous, queue-based lock
 * implementation to allow implementing safe access to resources that
 * are shared by asynchronous tasks. An asynchronous task may call
 * {@link wait_async} to wait for the lock to be marked as safe to
 * pass. Another asynchronous task may call {@link notify} to mark the
 * lock as being safe, notifying waiting tasks. Once marked as being
 * safe to pass, a lock may be reset to being unsafe by calling {@link
 * reset}. The lock cannot be passed initially, if this is desired
 * call notify after constructing it.
 *
 * See the specialised sub-classes for concrete implementations,
 * which vary based on two features:
 *
 * //Broadcasting//: Whether all waiting tasks are notified when the
 * lock may be passed, or just the next earliest waiting task.
 *
 * //Autoreset//: Whether the lock is automatically reset after
 * notifying all waiting tasks, or if it must be manually reset by
 * calling {@link reset}.
 *
 * This class is ''not'' thread safe and should only be used by
 * asynchronous tasks.
 */
 G_GNUC_NO_INLINE static GType
geary_nonblocking_lock_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyNonblockingLockClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_nonblocking_lock_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearyNonblockingLock), 0, (GInstanceInitFunc) geary_nonblocking_lock_instance_init, NULL };
	GType geary_nonblocking_lock_type_id;
	geary_nonblocking_lock_type_id = g_type_register_static (GEARY_TYPE_BASE_OBJECT, "GearyNonblockingLock", &g_define_type_info, G_TYPE_FLAG_ABSTRACT);
	GearyNonblockingLock_private_offset = g_type_add_instance_private (geary_nonblocking_lock_type_id, sizeof (GearyNonblockingLockPrivate));
	return geary_nonblocking_lock_type_id;
}

GType
geary_nonblocking_lock_get_type (void)
{
	static gsize geary_nonblocking_lock_type_id__once = 0;
	if (g_once_init_enter (&geary_nonblocking_lock_type_id__once)) {
		GType geary_nonblocking_lock_type_id;
		geary_nonblocking_lock_type_id = geary_nonblocking_lock_get_type_once ();
		g_once_init_leave (&geary_nonblocking_lock_type_id__once, geary_nonblocking_lock_type_id);
	}
	return geary_nonblocking_lock_type_id__once;
}

static void
_vala_geary_nonblocking_lock_get_property (GObject * object,
                                           guint property_id,
                                           GValue * value,
                                           GParamSpec * pspec)
{
	GearyNonblockingLock * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GEARY_NONBLOCKING_TYPE_LOCK, GearyNonblockingLock);
	switch (property_id) {
		case GEARY_NONBLOCKING_LOCK_CAN_PASS_PROPERTY:
		g_value_set_boolean (value, geary_nonblocking_lock_get_can_pass (self));
		break;
		case GEARY_NONBLOCKING_LOCK_IS_CANCELLED_PROPERTY:
		g_value_set_boolean (value, geary_nonblocking_lock_get_is_cancelled (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

