/* util-reference-semantics.c generated by valac 0.56.3, the Vala compiler
 * generated from util-reference-semantics.vala, do not modify */

/* Copyright 2016 Software Freedom Conservancy Inc.
 *
 * 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>

enum  {
	GEARY_REFERENCE_SEMANTICS_RELEASE_NOW_SIGNAL,
	GEARY_REFERENCE_SEMANTICS_FREED_SIGNAL,
	GEARY_REFERENCE_SEMANTICS_NUM_SIGNALS
};
static guint geary_reference_semantics_signals[GEARY_REFERENCE_SEMANTICS_NUM_SIGNALS] = {0};
enum  {
	GEARY_SMART_REFERENCE_0_PROPERTY,
	GEARY_SMART_REFERENCE_NUM_PROPERTIES
};
static GParamSpec* geary_smart_reference_properties[GEARY_SMART_REFERENCE_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
enum  {
	GEARY_SMART_REFERENCE_REFERENCE_BROKEN_SIGNAL,
	GEARY_SMART_REFERENCE_NUM_SIGNALS
};
static guint geary_smart_reference_signals[GEARY_SMART_REFERENCE_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 _GearySmartReferencePrivate {
	GearyReferenceSemantics* reffed;
};

static gint GearySmartReference_private_offset;
static gpointer geary_smart_reference_parent_class = NULL;

VALA_EXTERN void geary_reference_semantics_claim (GearyReferenceSemantics* self);
VALA_EXTERN void geary_reference_semantics_release (GearyReferenceSemantics* self);
static GType geary_reference_semantics_get_type_once (void);
static void geary_smart_reference_real_reference_broken (GearySmartReference* self);
static void geary_smart_reference_on_release_now (GearySmartReference* self);
static void _geary_smart_reference_on_release_now_geary_reference_semantics_release_now (GearyReferenceSemantics* _sender,
                                                                                  gpointer self);
static void geary_smart_reference_finalize (GObject * obj);
static GType geary_smart_reference_get_type_once (void);

gint
geary_reference_semantics_get_manual_ref_count (GearyReferenceSemantics* self)
{
	GearyReferenceSemanticsIface* _iface_;
	g_return_val_if_fail (GEARY_IS_REFERENCE_SEMANTICS (self), 0);
	_iface_ = GEARY_REFERENCE_SEMANTICS_GET_INTERFACE (self);
	if (_iface_->get_manual_ref_count) {
		return _iface_->get_manual_ref_count (self);
	}
	return -1;
}

void
geary_reference_semantics_set_manual_ref_count (GearyReferenceSemantics* self,
                                                gint value)
{
	GearyReferenceSemanticsIface* _iface_;
	g_return_if_fail (GEARY_IS_REFERENCE_SEMANTICS (self));
	_iface_ = GEARY_REFERENCE_SEMANTICS_GET_INTERFACE (self);
	if (_iface_->set_manual_ref_count) {
		_iface_->set_manual_ref_count (self, value);
	}
}

void
geary_reference_semantics_claim (GearyReferenceSemantics* self)
{
	gint _tmp0_;
	gint _tmp1_;
	_tmp0_ = geary_reference_semantics_get_manual_ref_count (self);
	_tmp1_ = _tmp0_;
	geary_reference_semantics_set_manual_ref_count (self, _tmp1_ + 1);
}

void
geary_reference_semantics_release (GearyReferenceSemantics* self)
{
	gint _tmp0_;
	gint _tmp1_;
	gint _tmp2_;
	gint _tmp3_;
	gint _tmp4_;
	_tmp0_ = geary_reference_semantics_get_manual_ref_count (self);
	_tmp1_ = _tmp0_;
	_vala_assert (_tmp1_ > 0, "manual_ref_count > 0");
	_tmp2_ = geary_reference_semantics_get_manual_ref_count (self);
	_tmp3_ = _tmp2_;
	_tmp3_ = _tmp3_ - 1;
	_tmp4_ = _tmp3_;
	geary_reference_semantics_set_manual_ref_count (self, _tmp4_);
	if (_tmp4_ == 0) {
		g_signal_emit (self, geary_reference_semantics_signals[GEARY_REFERENCE_SEMANTICS_FREED_SIGNAL], 0);
	}
}

gboolean
geary_reference_semantics_is_freed (GearyReferenceSemantics* self)
{
	gint _tmp0_;
	gint _tmp1_;
	gboolean result;
	_tmp0_ = geary_reference_semantics_get_manual_ref_count (self);
	_tmp1_ = _tmp0_;
	result = _tmp1_ == 0;
	return result;
}

static void
geary_reference_semantics_default_init (GearyReferenceSemanticsIface * iface,
                                        gpointer iface_data)
{
	g_object_interface_install_property (iface, g_param_spec_int ("manual-ref-count", "manual-ref-count", "manual-ref-count", G_MININT, G_MAXINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	/**
	     * A ReferenceSemantics object can fire this signal for force all SmartReferences to drop their
	     * reference to it.
	     */
	geary_reference_semantics_signals[GEARY_REFERENCE_SEMANTICS_RELEASE_NOW_SIGNAL] = g_signal_new ("release-now", GEARY_TYPE_REFERENCE_SEMANTICS, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
	/**
	     * This signal is fired when all SmartReferences to the ReferenceSemantics object have dropped
	     * their reference.
	     */
	geary_reference_semantics_signals[GEARY_REFERENCE_SEMANTICS_FREED_SIGNAL] = g_signal_new ("freed", GEARY_TYPE_REFERENCE_SEMANTICS, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

/**
 * ReferenceSemantics solves a problem due to a limitation of GObject and the current
 * implementation of Vala.
 *
 * What would be handy in GObject is a signal or callback to let an observer know when all the
 * references to an Object have been released and is about to be destroyed.  It does have this
 * feature (via WeakPointers), but Vala does not implement the weak keyword in this way currently
 * and does not (today) have semantics to be notified when the weak reference has turned to null.
 *
 * Additionally, there are situations where an Object may be held in some primary table inside an
 * object and references to it are handed out to one or more callers.  The primary class would like
 * to know when all those references have been dropped although (of course) Object has not been
 * destroyed (even with a proper weak ref) because it's held in a table.  Even if a
 * WeakReferenceTable is somehow implemented and used, there are situations where it's necessary to
 * be able to use the destroying object and clean up (close connections, change contexts, close
 * files, etc.)
 *
 * ReferenceSemantics manually implements such a scheme.  The Object (held in a table or with a
 * simple ref) implements the ReferenceSemantics interface.  (Note that the only required field to
 * implement is manual_ref_count.)  The objects that are distributed to callers are subclasses
 * of SmartReference.  When all the SmartReferences are destroyed, the ReferenceSemantics
 * "freed" signal will fire.  Any final references to the underlying Object can be dropped and/or
 * clean up can then occur.
 *
 * If the ReferenceSemantics object needs all the SmartReferences to drop their reference to it,
 * fire the "release-now" signal.  Although the SmartReferences will still be active in the system,
 * they will fire their own "reference-broken" signal.  Subclasses or observers should trap or
 * override this signal and move the object to a closed or broken state, or merely drop their own
 * reference to the SmartReference.
 */
 G_GNUC_NO_INLINE static GType
geary_reference_semantics_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearyReferenceSemanticsIface), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_reference_semantics_default_init, (GClassFinalizeFunc) NULL, NULL, 0, 0, (GInstanceInitFunc) NULL, NULL };
	GType geary_reference_semantics_type_id;
	geary_reference_semantics_type_id = g_type_register_static (G_TYPE_INTERFACE, "GearyReferenceSemantics", &g_define_type_info, 0);
	g_type_interface_add_prerequisite (geary_reference_semantics_type_id, GEARY_TYPE_BASE_OBJECT);
	return geary_reference_semantics_type_id;
}

GType
geary_reference_semantics_get_type (void)
{
	static gsize geary_reference_semantics_type_id__once = 0;
	if (g_once_init_enter (&geary_reference_semantics_type_id__once)) {
		GType geary_reference_semantics_type_id;
		geary_reference_semantics_type_id = geary_reference_semantics_get_type_once ();
		g_once_init_leave (&geary_reference_semantics_type_id__once, geary_reference_semantics_type_id);
	}
	return geary_reference_semantics_type_id__once;
}

static inline gpointer
geary_smart_reference_get_instance_private (GearySmartReference* self)
{
	return G_STRUCT_MEMBER_P (self, GearySmartReference_private_offset);
}

static void
geary_smart_reference_real_reference_broken (GearySmartReference* self)
{
}

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

static void
_geary_smart_reference_on_release_now_geary_reference_semantics_release_now (GearyReferenceSemantics* _sender,
                                                                             gpointer self)
{
	geary_smart_reference_on_release_now ((GearySmartReference*) self);
}

GearySmartReference*
geary_smart_reference_construct (GType object_type,
                                 GearyReferenceSemantics* reffed)
{
	GearySmartReference * self = NULL;
	GearyReferenceSemantics* _tmp0_;
	g_return_val_if_fail (GEARY_IS_REFERENCE_SEMANTICS (reffed), NULL);
	self = (GearySmartReference*) geary_base_object_construct (object_type);
	_tmp0_ = _g_object_ref0 (reffed);
	_g_object_unref0 (self->priv->reffed);
	self->priv->reffed = _tmp0_;
	g_signal_connect_object (reffed, "release-now", (GCallback) _geary_smart_reference_on_release_now_geary_reference_semantics_release_now, self, 0);
	geary_reference_semantics_claim (reffed);
	return self;
}

GearyReferenceSemantics*
geary_smart_reference_get_reference (GearySmartReference* self)
{
	GearyReferenceSemantics* _tmp0_;
	GearyReferenceSemantics* _tmp1_;
	GearyReferenceSemantics* result;
	g_return_val_if_fail (GEARY_IS_SMART_REFERENCE (self), NULL);
	_tmp0_ = self->priv->reffed;
	_tmp1_ = _g_object_ref0 (_tmp0_);
	result = _tmp1_;
	return result;
}

static void
geary_smart_reference_on_release_now (GearySmartReference* self)
{
	GearyReferenceSemantics* _tmp0_;
	g_return_if_fail (GEARY_IS_SMART_REFERENCE (self));
	_tmp0_ = self->priv->reffed;
	geary_reference_semantics_release (_tmp0_);
	_g_object_unref0 (self->priv->reffed);
	self->priv->reffed = NULL;
	g_signal_emit (self, geary_smart_reference_signals[GEARY_SMART_REFERENCE_REFERENCE_BROKEN_SIGNAL], 0);
}

static void
geary_smart_reference_class_init (GearySmartReferenceClass * klass,
                                  gpointer klass_data)
{
	geary_smart_reference_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GearySmartReference_private_offset);
	((GearySmartReferenceClass *) klass)->reference_broken = geary_smart_reference_real_reference_broken;
	G_OBJECT_CLASS (klass)->finalize = geary_smart_reference_finalize;
	/**
	     * This signal is fired when the SmartReference drops its reference to a ReferenceSemantics
	     * object due to it firing "release-now".
	     *
	     * This signal is *not* fired when SmartReference drops its reference in its destructor.
	     */
	geary_smart_reference_signals[GEARY_SMART_REFERENCE_REFERENCE_BROKEN_SIGNAL] = g_signal_new ("reference-broken", GEARY_TYPE_SMART_REFERENCE, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GearySmartReferenceClass, reference_broken), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}

static void
geary_smart_reference_instance_init (GearySmartReference * self,
                                     gpointer klass)
{
	self->priv = geary_smart_reference_get_instance_private (self);
}

static void
geary_smart_reference_finalize (GObject * obj)
{
	GearySmartReference * self;
	GearyReferenceSemantics* _tmp0_;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GEARY_TYPE_SMART_REFERENCE, GearySmartReference);
	_tmp0_ = self->priv->reffed;
	if (_tmp0_ != NULL) {
		GearyReferenceSemantics* _tmp1_;
		_tmp1_ = self->priv->reffed;
		geary_reference_semantics_release (_tmp1_);
	}
	_g_object_unref0 (self->priv->reffed);
	G_OBJECT_CLASS (geary_smart_reference_parent_class)->finalize (obj);
}

/**
 * A SmartReference holds a reference to a ReferenceSemantics object.  See that class for more
 * information on the operation of these two classes.
 */
 G_GNUC_NO_INLINE static GType
geary_smart_reference_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GearySmartReferenceClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) geary_smart_reference_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GearySmartReference), 0, (GInstanceInitFunc) geary_smart_reference_instance_init, NULL };
	GType geary_smart_reference_type_id;
	geary_smart_reference_type_id = g_type_register_static (GEARY_TYPE_BASE_OBJECT, "GearySmartReference", &g_define_type_info, G_TYPE_FLAG_ABSTRACT);
	GearySmartReference_private_offset = g_type_add_instance_private (geary_smart_reference_type_id, sizeof (GearySmartReferencePrivate));
	return geary_smart_reference_type_id;
}

GType
geary_smart_reference_get_type (void)
{
	static gsize geary_smart_reference_type_id__once = 0;
	if (g_once_init_enter (&geary_smart_reference_type_id__once)) {
		GType geary_smart_reference_type_id;
		geary_smart_reference_type_id = geary_smart_reference_get_type_once ();
		g_once_init_leave (&geary_smart_reference_type_id__once, geary_smart_reference_type_id);
	}
	return geary_smart_reference_type_id__once;
}

