Implement config_item_set_from()

This commit is contained in:
Přemysl Eric Janouch 2015-05-01 21:48:43 +02:00
parent d4deb31a17
commit b4dab3489d
1 changed files with 97 additions and 13 deletions

110
common.c
View File

@ -534,7 +534,7 @@ struct config_schema
bool (*validate) (struct config_item_ *, const struct config_item_ *);
/// The value has changed. Only appliable to objects.
bool (*on_changed) (struct config_item_ *);
void (*on_changed) (struct config_item_ *);
/// Free any resources located in "item->user_data"
void (*on_destroy) (struct config_item_ *item);
@ -542,12 +542,33 @@ struct config_schema
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
config_item_destroy (struct config_item_ *self)
static const char *
config_item_type_name (enum config_item_type type)
{
if (self->schema && self->schema->on_destroy)
self->schema->on_destroy (self);
switch (type)
{
case CONFIG_ITEM_NULL: return "null";
case CONFIG_ITEM_BOOLEAN: return "boolean";
case CONFIG_ITEM_INTEGER: return "integer";
case CONFIG_ITEM_STRING: return "string";
case CONFIG_ITEM_STRING_ARRAY: return "string array";
default:
hard_assert (!"invalid config item type value");
return NULL;
}
}
static bool
config_item_type_is_string (enum config_item_type type)
{
return type == CONFIG_ITEM_STRING
|| type == CONFIG_ITEM_STRING_ARRAY;
}
static void
config_item_free (struct config_item_ *self)
{
switch (self->type)
{
case CONFIG_ITEM_STRING:
@ -559,9 +580,32 @@ config_item_destroy (struct config_item_ *self)
default:
break;
}
}
static void
config_item_destroy (struct config_item_ *self)
{
if (self->schema && self->schema->on_destroy)
self->schema->on_destroy (self);
config_item_free (self);
free (self);
}
/// Doesn't do any validations or handle schemas, just moves source data
/// to the target item and destroys the source item
static void
config_item_move (struct config_item_ *self, struct config_item_ *source)
{
// Not quite sure how to handle that
hard_assert (!source->schema);
config_item_free (self);
self->type = source->type;
memcpy (&self->value, &source->value, sizeof source->value);
free (source);
}
static struct config_item_ *
config_item_new (enum config_item_type type)
{
@ -618,19 +662,59 @@ config_item_object (void)
return self;
}
/// Doesn't do any validations or such, only moves source data to the item
static void
config_item_move (struct config_item_ *self, struct config_item_ *source)
static bool
config_schema_accepts_type
(struct config_schema *self, enum config_item_type type)
{
// TODO
if (self->type == type)
return true;
// This is a bit messy but it has its purpose
if (config_item_type_is_string (self->type)
&& config_item_type_is_string (type))
return true;
return self->is_nullable && type == CONFIG_ITEM_NULL;
}
static bool
config_item_set_from (struct config_item_ *self,
struct config_item_ *source, struct error **e)
config_item_set_from (struct config_item_ *self, struct config_item_ *source,
struct error **e)
{
hard_assert (self->type == CONFIG_ITEM_OBJECT);
// TODO
struct config_schema *schema = self->schema;
if (!schema)
{
// Easy, we don't know what this item is
config_item_move (self, source);
return true;
}
// Otherwise we check the type and validate the item
if (!config_schema_accepts_type (schema, source->type))
{
error_set (e, "invalid type of value, expected: %s%s",
config_item_type_name (schema->type),
schema->is_nullable ? " (or null)" : "");
return false;
}
if (schema->validate && !schema->validate (self, source))
{
// XXX: perhaps "schema->validate" could provide a message for us?
error_set (e, "invalid value");
return false;
}
// Make sure the string subtype fits the schema
if (config_item_type_is_string (self->type)
&& config_item_type_is_string (source->type))
source->type = self->type;
config_item_move (self, source);
// Notify owner about the change so that they can apply it
if (schema->on_changed)
schema->on_changed (self);
return true;
}
static struct config_item_ *