void bb_adjust_value (GValue *out, const GValue *in, BbAdjustmentMode adjust_mode) { GType type = G_VALUE_TYPE (out); switch (G_TYPE_FUNDAMENTAL (type)) { case G_TYPE_DOUBLE: if (G_VALUE_TYPE (in) != G_TYPE_DOUBLE) g_error ("cannot adjust a double with a %s", G_VALUE_TYPE_NAME (in)); g_value_set_double (out, bb_adjust_double (g_value_get_double (out), g_value_get_double (in), adjust_mode)); break; default: if (type == BB_TYPE_DURATION) { BbDuration dur; switch (adjust_mode) { case BB_ADJUSTMENT_REPLACE: { if (G_VALUE_TYPE (in) != type) g_error ("cannot replace a %s with a %s", g_type_name (type), G_VALUE_TYPE_NAME (in)); g_value_copy (in, out); break; } case BB_ADJUSTMENT_MULTIPLY: { if (G_VALUE_TYPE (in) != G_TYPE_DOUBLE) g_error ("cannot multiply a duration by a %s", G_VALUE_TYPE_NAME (in)); bb_value_get_duration (out, &dur); dur.value *= g_value_get_double (in); bb_value_set_duration (out, dur.units, dur.value); break; } case BB_ADJUSTMENT_ADD: { BbDuration indur; if (G_VALUE_TYPE (in) != BB_TYPE_DURATION) g_error ("cannot add a %s to a duration", G_VALUE_TYPE_NAME (in)); bb_value_get_duration (out, &dur); bb_value_get_duration (in, &indur); if (dur.units != indur.units) g_error ("cannot add durations of differing units"); dur.value += indur.value; bb_value_set_duration (out, dur.units, dur.value); break; } case BB_ADJUSTMENT_DIVIDE: { if (G_VALUE_TYPE (in) != G_TYPE_DOUBLE) g_error ("cannot divide a duration by a %s", G_VALUE_TYPE_NAME (in)); bb_value_get_duration (out, &dur); dur.value *= g_value_get_double (in); bb_value_set_duration (out, dur.units, dur.value); break; } case BB_ADJUSTMENT_SUBTRACT: { BbDuration indur; if (G_VALUE_TYPE (in) != BB_TYPE_DURATION) g_error ("cannot subtract a %s to a duration", G_VALUE_TYPE_NAME (in)); bb_value_get_duration (out, &dur); bb_value_get_duration (in, &indur); if (dur.units != indur.units) g_error ("cannot subtract durations of differing units"); dur.value -= indur.value; bb_value_set_duration (out, dur.units, dur.value); break; } default: g_return_if_reached (); } } else g_error ("cannot interpolate value of type %s", g_type_name (type)); } }
static GObject * json_gobject_new (GType gtype, JsonObject *object) { JsonSerializableIface *iface = NULL; JsonSerializable *serializable = NULL; gboolean find_property; gboolean deserialize_property; gboolean set_property; GQueue *members; GList *l; GQueue members_left = G_QUEUE_INIT; guint n_members; GObjectClass *klass; GObject *retval; GArray *construct_params; gint i; klass = g_type_class_ref (gtype); n_members = json_object_get_size (object); members = json_object_get_members_internal (object); /* first pass: construct-only properties; here we cannot use Serializable * because we don't have an instance yet; we use the default implementation * of json_deserialize_pspec() to deserialize known types * * FIXME - find a way to allow deserialization for these properties */ construct_params = g_array_sized_new (FALSE, FALSE, sizeof (GParameter), n_members); for (l = members->head; l != NULL; l = l->next) { const gchar *member_name = l->data; GParamSpec *pspec; GParameter param = { NULL, }; JsonNode *val; gboolean res = FALSE; pspec = g_object_class_find_property (klass, member_name); if (!pspec) goto next_member; /* we only apply construct-only properties here */ if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0) goto next_member; if (!(pspec->flags & G_PARAM_WRITABLE)) goto next_member; g_value_init (¶m.value, G_PARAM_SPEC_VALUE_TYPE (pspec)); val = json_object_get_member (object, member_name); res = json_deserialize_pspec (¶m.value, pspec, val); if (!res) { g_warning ("Failed to deserialize \"%s\" property of type \"%s\" for an object of type \"%s\"", pspec->name, G_VALUE_TYPE_NAME (¶m.value), g_type_name (gtype)); g_value_unset (¶m.value); } else { param.name = g_strdup (pspec->name); g_array_append_val (construct_params, param); continue; } next_member: g_queue_push_tail (&members_left, l->data); } G_GNUC_BEGIN_IGNORE_DEPRECATIONS retval = g_object_newv (gtype, construct_params->len, (GParameter *) construct_params->data); G_GNUC_END_IGNORE_DEPRECATIONS /* free the contents of the GArray */ for (i = 0; i < construct_params->len; i++) { GParameter *param = &g_array_index (construct_params, GParameter, i); g_free ((gchar *) param->name); g_value_unset (¶m->value); } g_array_free (construct_params, TRUE); /* do the Serializable type check once */ if (g_type_is_a (gtype, JSON_TYPE_SERIALIZABLE)) { serializable = JSON_SERIALIZABLE (retval); iface = JSON_SERIALIZABLE_GET_IFACE (serializable); find_property = (iface->find_property != NULL); deserialize_property = (iface->deserialize_property != NULL); set_property = (iface->set_property != NULL); } else { find_property = FALSE; deserialize_property = FALSE; set_property = FALSE; } g_object_freeze_notify (retval); for (l = members_left.head; l != NULL; l = l->next) { const gchar *member_name = l->data; GParamSpec *pspec; JsonNode *val; GValue value = { 0, }; gboolean res = FALSE; if (find_property) pspec = json_serializable_find_property (serializable, member_name); else pspec = g_object_class_find_property (klass, member_name); if (pspec == NULL) continue; /* we should have dealt with these above */ if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) continue; if (!(pspec->flags & G_PARAM_WRITABLE)) continue; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); val = json_object_get_member (object, member_name); if (deserialize_property) { JSON_NOTE (GOBJECT, "Using JsonSerializable for property '%s'", pspec->name); res = json_serializable_deserialize_property (serializable, pspec->name, &value, pspec, val); } if (!res) { JSON_NOTE (GOBJECT, "Using json_deserialize_pspec for property '%s'", pspec->name); res = json_deserialize_pspec (&value, pspec, val); } if (res) { JSON_NOTE (GOBJECT, "Calling set_property('%s', '%s')", pspec->name, g_type_name (G_VALUE_TYPE (&value))); if (set_property) json_serializable_set_property (serializable, pspec, &value); else g_object_set_property (retval, pspec->name, &value); } else g_warning ("Failed to deserialize \"%s\" property of type \"%s\" for an object of type \"%s\"", pspec->name, g_type_name (G_VALUE_TYPE (&value)), g_type_name (gtype)); g_value_unset (&value); } g_queue_clear (&members_left); g_object_thaw_notify (retval); g_type_class_unref (klass); return retval; }