1
0
mirror of https://github.com/haiwen/libsearpc.git synced 2025-05-10 08:04:21 +00:00
libsearpc/json-glib/json-glib/json-gboxed.c
2012-05-09 13:33:59 +08:00

355 lines
9.9 KiB
C

/* json-gboxed.c - JSON GBoxed integration
*
* This file is part of JSON-GLib
*
* Copyright (C) 2007 OpenedHand Ltd.
* Copyright (C) 2009 Intel Corp.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
/**
* SECTION:json-gboxed
* @short_description: Serialize and deserialize GBoxed types
*
* GLib's #GBoxed type is a generic wrapper for arbitrary C structures.
*
* JSON-GLib allows serialization and deserialization of a #GBoxed type
* by registering functions mapping a #JsonNodeType to a specific
* #GType.
*
* When registering a #GBoxed type you should also register the
* corresponding transformation functions, e.g.:
*
* |[
* GType
* my_struct_get_type (void)
* {
* static GType boxed_type = 0;
*
* if (boxed_type == 0)
* {
* boxed_type =
* g_boxed_type_register_static (g_intern_static_string ("MyStruct"),
* (GBoxedCopyFunc) my_struct_copy,
* (GBoxedFreeFunc) my_struct_free);
*
* json_boxed_register_serialize_func (boxed_type, JSON_NODE_OBJECT,
* my_struct_serialize);
* json_boxed_register_deserialize_func (boxed_type, JSON_NODE_OBJECT,
* my_struct_deserialize);
* }
*
* return boxed_type;
* }
* ]|
*
* The serialization function will be invoked by json_boxed_serialize():
* it will be passed a pointer to the C structure and it must return a
* #JsonNode. The deserialization function will be invoked by
* json_boxed_deserialize(): it will be passed a #JsonNode for the
* declared type and it must return a newly allocated C structure.
*
* It is possible to check whether a #GBoxed type can be deserialized
* from a specific #JsonNodeType, and whether a #GBoxed can be serialized
* and to which specific #JsonNodeType.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include "json-types-private.h"
#include "json-gobject.h"
typedef struct _BoxedTransform BoxedTransform;
struct _BoxedTransform
{
GType boxed_type;
gint node_type;
JsonBoxedSerializeFunc serialize;
JsonBoxedDeserializeFunc deserialize;
};
G_LOCK_DEFINE_STATIC (boxed_serialize);
static GSList *boxed_serialize = NULL;
G_LOCK_DEFINE_STATIC (boxed_deserialize);
static GSList *boxed_deserialize = NULL;
static gint
boxed_transforms_cmp (gconstpointer a,
gconstpointer b)
{
const BoxedTransform *ta = a;
const BoxedTransform *tb = b;
return tb->boxed_type - ta->boxed_type;
}
static gint
boxed_transforms_find (gconstpointer a,
gconstpointer b)
{
const BoxedTransform *haystack = a;
const BoxedTransform *needle = b;
if (needle->node_type != -1)
return (haystack->boxed_type == needle->boxed_type &&
haystack->node_type == needle->node_type) ? 0 : 1;
else
return (haystack->boxed_type == needle->boxed_type) ? 0 : 1;
}
static BoxedTransform *
lookup_boxed_transform (GSList *transforms,
GType gboxed_type,
JsonNodeType node_type)
{
BoxedTransform lookup;
GSList *t;
lookup.boxed_type = gboxed_type;
lookup.node_type = node_type;
t = g_slist_find_custom (transforms, &lookup, boxed_transforms_find);
if (t == NULL)
return NULL;
return t->data;
}
/**
* json_boxed_register_serialize_func: (skip)
* @gboxed_type: a boxed type
* @node_type: a node type
* @serialize_func: serialization function for @boxed_type into
* a #JsonNode of type @node_type
*
* Registers a serialization function for a #GBoxed of type @gboxed_type
* to a #JsonNode of type @node_type
*
* Since: 0.10
*/
void
json_boxed_register_serialize_func (GType gboxed_type,
JsonNodeType node_type,
JsonBoxedSerializeFunc serialize_func)
{
BoxedTransform *t;
g_return_if_fail (G_TYPE_IS_BOXED (gboxed_type));
g_return_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE);
G_LOCK (boxed_serialize);
t = lookup_boxed_transform (boxed_serialize, gboxed_type, node_type);
if (t == NULL)
{
t = g_slice_new (BoxedTransform);
t->boxed_type = gboxed_type;
t->node_type = node_type;
t->serialize = serialize_func;
boxed_serialize = g_slist_insert_sorted (boxed_serialize, t,
boxed_transforms_cmp);
}
else
g_warning ("A serialization function for the boxed type %s into "
"JSON nodes of type %s already exists",
g_type_name (gboxed_type),
json_node_type_get_name (node_type));
G_UNLOCK (boxed_serialize);
}
/**
* json_boxed_register_deserialize_func: (skip)
* @gboxed_type: a boxed type
* @node_type: a node type
* @deserialize_func: deserialization function for @boxed_type from
* a #JsonNode of type @node_type
*
* Registers a deserialization function for a #GBoxed of type @gboxed_type
* from a #JsonNode of type @node_type
*
* Since: 0.10
*/
void
json_boxed_register_deserialize_func (GType gboxed_type,
JsonNodeType node_type,
JsonBoxedDeserializeFunc deserialize_func)
{
BoxedTransform *t;
g_return_if_fail (G_TYPE_IS_BOXED (gboxed_type));
g_return_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE);
G_LOCK (boxed_deserialize);
t = lookup_boxed_transform (boxed_deserialize, gboxed_type, node_type);
if (t == NULL)
{
t = g_slice_new (BoxedTransform);
t->boxed_type = gboxed_type;
t->node_type = node_type;
t->deserialize = deserialize_func;
boxed_deserialize = g_slist_insert_sorted (boxed_deserialize, t,
boxed_transforms_cmp);
}
else
g_warning ("A deserialization function for the boxed type %s from "
"JSON nodes of type %s already exists",
g_type_name (gboxed_type),
json_node_type_get_name (node_type));
G_UNLOCK (boxed_deserialize);
}
/**
* json_boxed_can_serialize:
* @gboxed_type: a boxed type
* @node_type: (out): the #JsonNode type to which the boxed type can be
* serialized into
*
* Checks whether it is possible to serialize a #GBoxed of
* type @gboxed_type into a #JsonNode. The type of the
* #JsonNode is placed inside @node_type if the function
* returns %TRUE and it's undefined otherwise.
*
* Return value: %TRUE if the type can be serialized,
* and %FALSE otherwise.
*
* Since: 0.10
*/
gboolean
json_boxed_can_serialize (GType gboxed_type,
JsonNodeType *node_type)
{
BoxedTransform *t;
g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), FALSE);
g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, FALSE);
t = lookup_boxed_transform (boxed_serialize, gboxed_type, -1);
if (t != NULL)
{
if (node_type)
*node_type = t->node_type;
return TRUE;
}
return FALSE;
}
/**
* json_boxed_can_deserialize:
* @gboxed_type: a boxed type
* @node_type: a #JsonNode type
*
* Checks whether it is possible to deserialize a #GBoxed of
* type @gboxed_type from a #JsonNode of type @node_type
*
* Return value: %TRUE if the type can be deserialized, %FALSE otherwise
*
* Since: 0.10
*/
gboolean
json_boxed_can_deserialize (GType gboxed_type,
JsonNodeType node_type)
{
BoxedTransform *t;
g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), FALSE);
g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, FALSE);
t = lookup_boxed_transform (boxed_deserialize, gboxed_type, node_type);
if (t != NULL)
return TRUE;
return FALSE;
}
/**
* json_boxed_serialize:
* @gboxed_type: a boxed type
* @boxed: a pointer to a #GBoxed of type @gboxed_type
*
* Serializes @boxed, a pointer to a #GBoxed of type @gboxed_type,
* into a #JsonNode
*
* Return value: (transfer full): a #JsonNode with the serialization of the
* boxed type, or %NULL if serialization either failed or was not possible
*
* Since: 0.10
*/
JsonNode *
json_boxed_serialize (GType gboxed_type,
gconstpointer boxed)
{
BoxedTransform *t;
g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), NULL);
g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, NULL);
g_return_val_if_fail (boxed != NULL, NULL);
t = lookup_boxed_transform (boxed_serialize, gboxed_type, -1);
if (t != NULL && t->serialize != NULL)
return t->serialize (boxed);
return NULL;
}
/**
* json_boxed_deserialize:
* @gboxed_type: a boxed type
* @node: a #JsonNode
*
* Deserializes @node into a #GBoxed of @gboxed_type
*
* Return value: (transfer full): the newly allocated #GBoxed. Use
* g_boxed_free() to release the resources allocated by this
* function
*
* Since: 0.10
*/
gpointer
json_boxed_deserialize (GType gboxed_type,
JsonNode *node)
{
JsonNodeType node_type;
BoxedTransform *t;
g_return_val_if_fail (G_TYPE_IS_BOXED (gboxed_type), NULL);
g_return_val_if_fail (G_TYPE_IS_ABSTRACT (gboxed_type) == FALSE, NULL);
g_return_val_if_fail (node != NULL, NULL);
node_type = json_node_get_node_type (node);
t = lookup_boxed_transform (boxed_deserialize, gboxed_type, node_type);
if (t != NULL && t->deserialize != NULL)
return t->deserialize (node);
return NULL;
}