/* json-value.c - JSON value container
*
* This file is part of JSON-GLib
* Copyright (C) 2012 Emmanuele Bassi <ebassi@gnome.org>
* Copyright (C) 2015 Collabora Ltd.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
* Philip Withnall <philip.withnall@collabora.co.uk>
*/
#include "config.h"
#include <glib.h>
#include "json-types-private.h"
const gchar *
json_value_type_get_name (JsonValueType value_type)
{
switch (value_type)
{
case JSON_VALUE_INVALID:
return "Unset";
case JSON_VALUE_INT:
return "Integer";
case JSON_VALUE_DOUBLE:
return "Floating Point";
case JSON_VALUE_BOOLEAN:
return "Boolean";
case JSON_VALUE_STRING:
return "String";
case JSON_VALUE_NULL:
return "Null";
}
return "Undefined";
}
GType
json_value_type (const JsonValue *value)
{
switch (value->type)
{
case JSON_VALUE_INVALID:
return G_TYPE_INVALID;
case JSON_VALUE_INT:
return G_TYPE_INT64;
case JSON_VALUE_DOUBLE:
return G_TYPE_DOUBLE;
case JSON_VALUE_BOOLEAN:
return G_TYPE_BOOLEAN;
case JSON_VALUE_STRING:
return G_TYPE_STRING;
case JSON_VALUE_NULL:
return G_TYPE_INVALID;
}
return G_TYPE_INVALID;
}
JsonValue *
json_value_alloc (void)
{
JsonValue *res = g_slice_new0 (JsonValue);
res->ref_count = 1;
return res;
}
JsonValue *
json_value_init (JsonValue *value,
JsonValueType value_type)
{
g_return_val_if_fail (value != NULL, NULL);
if (value->type != JSON_VALUE_INVALID)
json_value_unset (value);
value->type = value_type;
return value;
}
JsonValue *
json_value_ref (JsonValue *value)
{
g_return_val_if_fail (value != NULL, NULL);
value->ref_count++;
return value;
}
void
json_value_unref (JsonValue *value)
{
g_return_if_fail (value != NULL);
if (--value->ref_count == 0)
json_value_free (value);
}
void
json_value_unset (JsonValue *value)
{
g_return_if_fail (value != NULL);
switch (value->type)
{
case JSON_VALUE_INVALID:
break;
case JSON_VALUE_INT:
value->data.v_int = 0;
break;
case JSON_VALUE_DOUBLE:
value->data.v_double = 0.0;
break;
case JSON_VALUE_BOOLEAN:
value->data.v_bool = FALSE;
break;
case JSON_VALUE_STRING:
g_free (value->data.v_str);
value->data.v_str = NULL;
break;
case JSON_VALUE_NULL:
break;
}
}
void
json_value_free (JsonValue *value)
{
if (G_LIKELY (value != NULL))
{
json_value_unset (value);
g_slice_free (JsonValue, value);
}
}
/**
* json_value_seal:
* @value: a #JsonValue
*
* Seals the #JsonValue, making it immutable to further changes.
*
* If the @value is already immutable, this is a no-op.
*
* Since: 1.2
*/
void
json_value_seal (JsonValue *value)
{
g_return_if_fail (JSON_VALUE_IS_VALID (value));
g_return_if_fail (value->ref_count > 0);
value->immutable = TRUE;
}
guint
json_value_hash (gconstpointer key)
{
JsonValue *value;
guint value_hash;
guint type_hash;
value = (JsonValue *) key;
/* Hash the type and value separately.
* Use the top 3 bits to store the type. */
type_hash = value->type << (sizeof (guint) * 8 - 3);
switch (value->type)
{
case JSON_VALUE_NULL:
value_hash = 0;
break;
case JSON_VALUE_BOOLEAN:
value_hash = json_value_get_boolean (value) ? 1 : 0;
break;
case JSON_VALUE_STRING:
value_hash = json_string_hash (json_value_get_string (value));
break;
case JSON_VALUE_INT: {
gint64 v = json_value_get_int (value);
value_hash = g_int64_hash (&v);
break;
}
case JSON_VALUE_DOUBLE: {
gdouble v = json_value_get_double (value);
value_hash = g_double_hash (&v);
break;
}
case JSON_VALUE_INVALID:
default:
g_assert_not_reached ();
}
/* Mask out the top 3 bits of the @value_hash. */
value_hash &= ~(7 << (sizeof (guint) * 8 - 3));
return (type_hash | value_hash);
}
#define _JSON_VALUE_DEFINE_SET(Type,EType,CType,VField) \
void \
json_value_set_##Type (JsonValue *value, CType VField) \
{ \
g_return_if_fail (JSON_VALUE_IS_VALID (value)); \
g_return_if_fail (JSON_VALUE_HOLDS (value, JSON_VALUE_##EType)); \
g_return_if_fail (!value->immutable); \
\
value->data.VField = VField; \
\
}
#define _JSON_VALUE_DEFINE_GET(Type,EType,CType,VField) \
CType \
json_value_get_##Type (const JsonValue *value) \
{ \
g_return_val_if_fail (JSON_VALUE_IS_VALID (value), 0); \
g_return_val_if_fail (JSON_VALUE_HOLDS (value, JSON_VALUE_##EType), 0); \
\
return value->data.VField; \
}
#define _JSON_VALUE_DEFINE_SET_GET(Type,EType,CType,VField) \
_JSON_VALUE_DEFINE_SET(Type,EType,CType,VField) \
_JSON_VALUE_DEFINE_GET(Type,EType,CType,VField)
_JSON_VALUE_DEFINE_SET_GET(int, INT, gint64, v_int)
_JSON_VALUE_DEFINE_SET_GET(double, DOUBLE, gdouble, v_double)
_JSON_VALUE_DEFINE_SET_GET(boolean, BOOLEAN, gboolean, v_bool)
void
json_value_set_string (JsonValue *value,
const gchar *v_str)
{
g_return_if_fail (JSON_VALUE_IS_VALID (value));
g_return_if_fail (JSON_VALUE_HOLDS_STRING (value));
g_return_if_fail (!value->immutable);
g_free (value->data.v_str);
value->data.v_str = g_strdup (v_str);
}
_JSON_VALUE_DEFINE_GET(string, STRING, const gchar *, v_str)
#undef _JSON_VALUE_DEFINE_SET_GET
#undef _JSON_VALUE_DEFINE_GET
#undef _JSON_VALUE_DEFINE_SET