#define G_IMPLEMENT_INLINES
#define __GSK_STORE_C__
#include <string.h>
#include "gskstreammap.h"
#include "../gskstreamtransferrequest.h"
#include "gskstore.h"
static GskStoreFormatEntry *
get_format_entry_for_type (GskStore *store, GType value_type, GError **error)
{
GPtrArray *format_entries = store->format_entries;
guint i;
(void) error;
g_return_val_if_fail (format_entries, NULL);
for (;;)
{
for (i = 0; i < format_entries->len; ++i)
{
GskStoreFormatEntry *entry = g_ptr_array_index (format_entries, i);
if (entry->value_type == value_type)
return entry;
}
if (value_type == G_TYPE_INVALID)
break;
value_type = g_type_parent (value_type);
}
return NULL;
}
static GskStoreFormatEntry *
get_format_entry_for_id (GskStore *store, guint32 format_id, GError **error)
{
GPtrArray *format_entries = store->format_entries;
guint i;
(void) error;
g_return_val_if_fail (format_entries, NULL);
for (i = 0; i < format_entries->len; ++i)
{
GskStoreFormatEntry *entry = g_ptr_array_index (format_entries, i);
if (entry->format_id == format_id)
return entry;
}
return NULL;
}
/*
*
* Save
*
*/
typedef struct _SaveInfo SaveInfo;
struct _SaveInfo
{
GskStreamTransferRequest *xfer_request;
};
/* Signal handler invoked when the GskStreamTransferRequest is done
* transferring the stream of serialized data to the write-stream
* from the GskStreamMap.
*/
static void
save_handle_xfer_request_done (GskRequest *xfer_request, gpointer user_data)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (user_data);
SaveInfo *save_info = (SaveInfo *) store_request->private;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_SAVE);
g_return_if_fail (save_info->xfer_request ==
GSK_STREAM_TRANSFER_REQUEST (xfer_request));
if (gsk_request_had_error (xfer_request))
{
GError *error;
error = g_error_copy (gsk_request_get_error (xfer_request));
gsk_request_set_error (store_request, error);
}
g_object_unref (xfer_request);
save_info->xfer_request = NULL;
gsk_request_done (store_request);
g_object_unref (store_request);
}
static void
save_start (GskStoreRequest *store_request)
{
SaveInfo *save_info = (SaveInfo *) store_request->private;
GskStreamTransferRequest *xfer_request;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_SAVE);
xfer_request = save_info->xfer_request;
g_return_if_fail (xfer_request);
g_object_ref (store_request);
g_signal_connect (xfer_request,
"done",
G_CALLBACK (save_handle_xfer_request_done),
store_request);
gsk_request_start (xfer_request);
}
GskStoreRequest *
gsk_store_save (GskStore *store,
const char *key,
const GValue *value,
GError **error)
{
GskStreamMap *stream_map = store->stream_map;
GskStoreFormatEntry *format_entry;
GskStream *serialize_stream;
GskStream *write_stream;
GskStreamTransferRequest *xfer_request;
GskStoreRequest *store_request;
SaveInfo *save_info;
format_entry = get_format_entry_for_type (store, G_VALUE_TYPE (value), error);
if (format_entry == NULL)
{
g_return_val_if_fail (error == NULL || *error, NULL);
return NULL;
}
g_return_val_if_fail (format_entry->storage_format, NULL);
serialize_stream = gsk_storage_format_serialize (format_entry->storage_format,
value,
error);
if (serialize_stream == NULL)
{
g_return_val_if_fail (error == NULL || *error, NULL);
return NULL;
}
write_stream = gsk_stream_map_set (stream_map, key, error);
if (write_stream == NULL)
{
g_object_unref (serialize_stream);
g_return_val_if_fail (error == NULL || *error, NULL);
return NULL;
}
xfer_request =
gsk_stream_transfer_request_new (serialize_stream, write_stream);
g_return_val_if_fail (xfer_request, NULL);
g_object_unref (serialize_stream);
g_object_unref (write_stream);
/* HACK: maybe GskStreamTransferRequest should support this. */
{
guint32 format_id_out = format_entry->format_id;
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
format_id_out = GUINT32_TO_LE (format_id_out);
#endif
gsk_buffer_append (&xfer_request->buffer,
&format_id_out,
sizeof (format_id_out));
}
save_info = g_new0 (SaveInfo, 1);
save_info->xfer_request = xfer_request;
store_request = g_object_new (GSK_TYPE_STORE_REQUEST, NULL);
store_request->request_type = GSK_STORE_REQUEST_SAVE;
store_request->key = g_strdup (key);
store_request->private = save_info;
return store_request;
}
/*
*
* Load
*
*/
typedef struct _LoadInfo LoadInfo;
struct _LoadInfo
{
GType value_type;
GskStream *read_stream;
GskStore *store;
};
static void
load_handle_deserialize_request_done (GskRequest *request, gpointer user_data)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (user_data);
GskValueRequest *deserialize_request = GSK_VALUE_REQUEST (request);
GError *error = NULL;
const GValue *value;
if (gsk_request_had_error (deserialize_request))
{
error = g_error_copy (gsk_request_get_error (deserialize_request));
gsk_request_set_error (store_request, error);
gsk_request_done (store_request);
g_object_unref (store_request);
return;
}
value = gsk_value_request_get_value (deserialize_request);
if (value == NULL)
{
error = g_error_new (GSK_G_ERROR_DOMAIN,
GSK_ERROR_UNKNOWN, /* TODO: code */
"couldn't get value from a %s",
g_type_name (G_OBJECT_TYPE (deserialize_request)));
gsk_request_set_error (store_request, error);
gsk_request_done (store_request);
g_object_unref (store_request);
return;
}
g_value_init (&store_request->value_request.value, G_VALUE_TYPE (value));
g_value_copy (value, &store_request->value_request.value);
gsk_request_done (store_request);
g_object_unref (store_request);
}
static gboolean
load_handle_input_is_readable (GskIO *io, gpointer user_data)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (user_data);
LoadInfo *load_info = (LoadInfo *) store_request->private;
GskStream *read_stream;
guint32 format_id;
GskStoreFormatEntry *format_entry;
GskValueRequest *deserialize_request;
GError *error = NULL;
guint num_read;
g_return_val_if_fail (store_request->request_type == GSK_STORE_REQUEST_LOAD,
FALSE);
g_return_val_if_fail (load_info, FALSE);
read_stream = load_info->read_stream;
g_return_val_if_fail (read_stream == GSK_STREAM (io), FALSE);
/* XXX: We assume we can read 4 bytes in one try. Probably safe for
* any reasonable stream, but...
*/
num_read = gsk_stream_read (read_stream,
&format_id,
sizeof (format_id),
&error);
if (error)
{
gsk_request_set_error (store_request, error);
gsk_request_done (store_request);
return FALSE;
}
g_return_val_if_fail (num_read == sizeof (format_id), FALSE);
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
format_id = GUINT32_FROM_LE (format_id);
#endif
gsk_io_untrap_readable (read_stream);
g_return_val_if_fail (load_info->store, FALSE);
format_entry = get_format_entry_for_id (load_info->store, format_id, &error);
if (format_entry == NULL)
{
gsk_request_set_error (store_request, error);
gsk_request_done (store_request);
return FALSE;
}
deserialize_request =
gsk_storage_format_deserialize (format_entry->storage_format,
read_stream,
load_info->value_type,
&error);
if (deserialize_request == NULL)
{
gsk_request_set_error (store_request, error);
gsk_request_done (store_request);
g_return_val_if_fail (error, FALSE);
return FALSE;
}
g_object_ref (store_request);
g_signal_connect (deserialize_request,
"done",
G_CALLBACK (load_handle_deserialize_request_done),
store_request);
gsk_request_start (deserialize_request);
/* Note: we've already untrapped the hook above, so the return value
* is meaningless.
*/
return FALSE;
}
static gboolean
load_handle_input_shutdown_read (GskIO *io, gpointer user_data)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (user_data);
GError *error;
(void) io;
g_return_val_if_fail (store_request->request_type == GSK_STORE_REQUEST_LOAD,
FALSE);
error = g_error_new (GSK_G_ERROR_DOMAIN,
GSK_ERROR_UNKNOWN, /* TODO: code */
"premature end of stream (%s)",
g_type_name (G_OBJECT_TYPE (io)));
gsk_request_set_error (store_request, error);
gsk_request_done (store_request);
return FALSE;
}
static void
load_handle_input_is_readable_destroy (gpointer user_data)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (user_data);
LoadInfo *load_info = (LoadInfo *) store_request->private;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_LOAD);
g_return_if_fail (load_info);
g_object_unref (load_info->read_stream);
load_info->read_stream = NULL;
g_object_unref (store_request);
}
static void
load_start (GskStoreRequest *store_request)
{
LoadInfo *load_info = (LoadInfo *) store_request->private;
GskStream *read_stream;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_LOAD);
g_return_if_fail (load_info);
read_stream = load_info->read_stream;
g_return_if_fail (read_stream);
g_return_if_fail (gsk_stream_get_is_readable (read_stream));
g_return_if_fail (!gsk_io_has_read_hook (read_stream));
g_object_ref (store_request);
gsk_io_trap_readable (GSK_IO (read_stream),
load_handle_input_is_readable,
load_handle_input_shutdown_read,
store_request,
load_handle_input_is_readable_destroy);
}
GskStoreRequest *
gsk_store_load (GskStore *store,
const char *key,
GType value_type,
GError **error)
{
GskStreamMap *stream_map = store->stream_map;
GskStream *read_stream;
GskStoreRequest *store_request;
LoadInfo *load_info;
read_stream = gsk_stream_map_get (stream_map, key, error);
if (read_stream == NULL)
{
g_return_val_if_fail (error == NULL || *error, NULL);
return NULL;
}
load_info = g_new0 (LoadInfo, 1);
load_info->store = store;
g_object_ref (store);
load_info->value_type = value_type;
load_info->read_stream = read_stream;
store_request = g_object_new (GSK_TYPE_STORE_REQUEST, NULL);
store_request->request_type = GSK_STORE_REQUEST_LOAD;
store_request->key = g_strdup (key);
store_request->private = load_info;
return store_request;
}
/*
*
* Delete
*
*/
typedef struct _DeleteInfo DeleteInfo;
struct _DeleteInfo
{
GskStreamMapRequest *delete_request;
};
/* Signal handler invoked when the GskStreamMapRequest is done. */
static void
delete_handle_request_done (GskRequest *delete_request, gpointer user_data)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (user_data);
DeleteInfo *delete_info = (DeleteInfo *) store_request->private;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_DELETE);
g_return_if_fail (delete_info);
g_return_if_fail (delete_info->delete_request ==
GSK_STREAM_MAP_REQUEST (delete_request));
g_object_unref (store_request);
if (gsk_request_had_error (delete_request))
{
GError *error;
error = g_error_copy (gsk_request_get_error (delete_request));
gsk_request_set_error (store_request, error);
}
g_object_unref (delete_request);
delete_info->delete_request = NULL;
gsk_request_done (store_request);
}
static void
delete_start (GskStoreRequest *store_request)
{
DeleteInfo *delete_info = (DeleteInfo *) store_request->private;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_DELETE);
g_return_if_fail (delete_info);
g_object_ref (store_request);
g_signal_connect (delete_info->delete_request,
"done",
G_CALLBACK (delete_handle_request_done),
store_request);
gsk_request_start (delete_info->delete_request);
}
GskStoreRequest *
gsk_store_delete (GskStore *store,
const char *key,
GError **error)
{
GskStreamMap *stream_map = store->stream_map;
GskStreamMapRequest *delete_request;
DeleteInfo *delete_info;
GskStoreRequest *store_request;
delete_request = gsk_stream_map_delete (stream_map, key, error);
if (delete_request == NULL)
{
g_return_val_if_fail (error == NULL || *error, NULL);
return NULL;
}
delete_info = g_new0 (DeleteInfo, 1);
delete_info->delete_request = delete_request;
store_request = g_object_new (GSK_TYPE_STORE_REQUEST, NULL);
store_request->request_type = GSK_STORE_REQUEST_DELETE;
store_request->key = g_strdup (key);
store_request->private = delete_info;
return store_request;
}
/*
*
* Exists
*
*/
typedef struct _ExistsInfo ExistsInfo;
struct _ExistsInfo
{
GskStreamMapRequest *exists_request;
};
/* Signal handler invoked when the GskStreamMapRequest is done. */
static void
exists_handle_request_done (GskRequest *exists_request, gpointer user_data)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (user_data);
ExistsInfo *exists_info = (ExistsInfo *) store_request->private;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_EXISTS);
g_return_if_fail (exists_info);
g_return_if_fail (exists_info->exists_request ==
GSK_STREAM_MAP_REQUEST (exists_request));
g_object_unref (store_request);
if (gsk_request_had_error (exists_request))
{
GError *error;
error = g_error_copy (gsk_request_get_error (exists_request));
gsk_request_set_error (store_request, error);
}
g_value_init (&store_request->value_request.value, G_TYPE_BOOLEAN);
g_value_set_boolean (&store_request->value_request.value,
gsk_stream_map_request_get_exists (exists_request));
g_object_unref (exists_request);
exists_info->exists_request = NULL;
gsk_request_done (store_request);
}
static void
exists_start (GskStoreRequest *store_request)
{
ExistsInfo *exists_info = (ExistsInfo *) store_request->private;
g_return_if_fail (store_request->request_type == GSK_STORE_REQUEST_EXISTS);
g_return_if_fail (exists_info);
g_object_ref (store_request);
g_signal_connect (exists_info->exists_request,
"done",
G_CALLBACK (exists_handle_request_done),
store_request);
gsk_request_start (exists_info->exists_request);
}
GskStoreRequest *
gsk_store_exists (GskStore *store,
const char *key,
GError **error)
{
GskStreamMap *stream_map = store->stream_map;
GskStreamMapRequest *exists_request;
ExistsInfo *exists_info;
GskStoreRequest *store_request;
exists_request = gsk_stream_map_exists (stream_map, key, error);
if (exists_request == NULL)
{
g_return_val_if_fail (error == NULL || *error, NULL);
return NULL;
}
exists_info = g_new0 (ExistsInfo, 1);
exists_info->exists_request = exists_request;
store_request = g_object_new (GSK_TYPE_STORE_REQUEST, NULL);
store_request->request_type = GSK_STORE_REQUEST_EXISTS;
store_request->key = g_strdup (key);
store_request->private = exists_info;
return store_request;
}
GType
gsk_store_get_type (void)
{
static GType type = 0;
if (type == 0)
{
static const GTypeInfo info =
{
sizeof (GskStoreClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) NULL,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GskStore),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
NULL /* value_table */
};
type = g_type_register_static (G_TYPE_OBJECT,
"GskStore",
&info,
0);
}
return type;
}
/*
*
* GskStoreRequest
*
*/
static GObjectClass *gsk_store_request_parent_class = NULL;
/* GskRequest methods. */
/* TODO: cancelled methods */
static void
gsk_store_request_cancelled (GskRequest *request)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (request);
switch (store_request->request_type)
{
case GSK_STORE_REQUEST_LOAD:
// load_cancel (store_request);
break;
case GSK_STORE_REQUEST_SAVE:
// save_cancel (store_request);
break;
case GSK_STORE_REQUEST_DELETE:
// delete_cancel (store_request);
break;
case GSK_STORE_REQUEST_EXISTS:
// exists_cancel (store_request);
break;
default:
g_return_if_reached ();
break;
}
}
static void
gsk_store_request_start (GskRequest *request)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (request);
switch (store_request->request_type)
{
case GSK_STORE_REQUEST_LOAD:
load_start (store_request);
break;
case GSK_STORE_REQUEST_SAVE:
save_start (store_request);
break;
case GSK_STORE_REQUEST_DELETE:
delete_start (store_request);
break;
case GSK_STORE_REQUEST_EXISTS:
exists_start (store_request);
break;
default:
g_return_if_reached ();
break;
}
}
/* GObject methods. */
static void
gsk_store_request_finalize (GObject *object)
{
GskStoreRequest *store_request = GSK_STORE_REQUEST (object);
if (store_request->key)
g_free (store_request->key);
switch (store_request->request_type)
{
case GSK_STORE_REQUEST_LOAD:
/* TODO */
break;
case GSK_STORE_REQUEST_SAVE:
/* TODO */
break;
case GSK_STORE_REQUEST_DELETE:
/* TODO */
break;
case GSK_STORE_REQUEST_EXISTS:
/* TODO */
break;
default:
g_return_if_reached ();
break;
}
(*gsk_store_request_parent_class->finalize) (object);
}
static void
gsk_store_request_class_init (GskRequestClass *request_class)
{
gsk_store_request_parent_class = g_type_class_peek_parent (request_class);
G_OBJECT_CLASS (request_class)->finalize = gsk_store_request_finalize;
request_class->start = gsk_store_request_start;
request_class->cancelled = gsk_store_request_cancelled;
}
GType
gsk_store_request_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0))
{
static const GTypeInfo type_info =
{
sizeof (GskStoreRequestClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gsk_store_request_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GskStoreRequest),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
NULL /* value_table */
};
type = g_type_register_static (GSK_TYPE_VALUE_REQUEST,
"GskStoreRequest",
&type_info,
0);
}
return type;
}
/*
*
* GskStoreFormatEntry
*
*/
static GObjectClass *gsk_store_format_entry_parent_class = NULL;
/* GObject methods. */
static void
gsk_store_format_entry_finalize (GObject *object)
{
GskStoreFormatEntry *store_format_entry = GSK_STORE_FORMAT_ENTRY (object);
if (store_format_entry->storage_format)
g_object_unref (store_format_entry->storage_format);
(*gsk_store_format_entry_parent_class->finalize) (object);
}
static void
gsk_store_format_entry_class_init (GObjectClass *object_class)
{
gsk_store_format_entry_parent_class = g_type_class_peek_parent (object_class);
object_class->finalize = gsk_store_format_entry_finalize;
}
GType
gsk_store_format_entry_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0))
{
static const GTypeInfo type_info =
{
sizeof (GskStoreFormatEntryClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gsk_store_format_entry_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GskStoreFormatEntry),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
NULL /* value_table */
};
type = g_type_register_static (G_TYPE_OBJECT,
"GskStoreFormatEntry",
&type_info,
0);
}
return type;
}
syntax highlighted by Code2HTML, v. 0.9.1