diff options
author | David Robillard <d@drobilla.net> | 2023-03-31 17:17:41 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2023-12-02 18:49:08 -0500 |
commit | b5956c4dc6b065d664908104d5fc6752a87e3364 (patch) | |
tree | 6be1fa515891e759092bb9bea082e27c78bfb6de /src/inserter.c | |
parent | 439d6ec3d6dfbea74334beace790f500e61c9b7d (diff) | |
download | serd-b5956c4dc6b065d664908104d5fc6752a87e3364.tar.gz serd-b5956c4dc6b065d664908104d5fc6752a87e3364.tar.bz2 serd-b5956c4dc6b065d664908104d5fc6752a87e3364.zip |
Add model and serd-sort utility
With all the new functionality, the complexity of the serd-pipe command-line
interface is starting to push the limits of available flags. So, instead of
grafting on further options to control a model, this commit adds a new tool,
serd-sort, which acts somewhat like a stripped-down serd-pipe that stores
statements in a model in memory.
This keeps the complexity (including the user-facing complexity) of any one
tool down, since other more focused tools can be used for streaming tasks in a
pipeline.
In other words, abandon Swissarmyknifeism, take a page from the Unix
philosophy, and try to expose the model functionality to the command-line in a
dedicated focused tool. The model implementation is tested by using this tool
to run a subset of the usual test suites, and a special suite to test statement
sorting.
Diffstat (limited to 'src/inserter.c')
-rw-r--r-- | src/inserter.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/inserter.c b/src/inserter.c new file mode 100644 index 00000000..f3b8631b --- /dev/null +++ b/src/inserter.c @@ -0,0 +1,146 @@ +// Copyright 2011-2020 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#include "memory.h" +#include "model.h" +#include "statement.h" + +#include "serd/caret.h" +#include "serd/event.h" +#include "serd/inserter.h" +#include "serd/log.h" +#include "serd/model.h" +#include "serd/node.h" +#include "serd/nodes.h" +#include "serd/sink.h" +#include "serd/statement.h" +#include "serd/status.h" +#include "serd/uri.h" +#include "serd/world.h" + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> + +typedef struct { + SerdModel* model; + SerdNode* default_graph; +} SerdInserterData; + +static bool +can_insert(SerdWorld* const world, const SerdNode* const node) +{ + if (node) { + switch (serd_node_type(node)) { + case SERD_LITERAL: + return can_insert(world, serd_node_datatype(node)); + + case SERD_URI: + if (!serd_uri_string_has_scheme(serd_node_string(node))) { + serd_logf(world, + SERD_LOG_LEVEL_ERROR, + "attempt to insert relative URI <%s> into model", + serd_node_string(node)); + return false; + } + break; + + case SERD_BLANK: + case SERD_VARIABLE: + break; + } + } + + return true; +} + +static SerdStatus +serd_inserter_on_statement(SerdInserterData* const data, + const SerdStatementFlags flags, + const SerdStatement* const statement) +{ + (void)flags; + + SerdModel* const model = data->model; + SerdWorld* const world = model->world; + + // Check that every node is expanded so it is context-free + for (unsigned i = 0; i < 4; ++i) { + if (!can_insert(world, serd_statement_node(statement, (SerdField)i))) { + return SERD_BAD_DATA; + } + } + + const SerdNode* const s = + serd_nodes_intern(model->nodes, serd_statement_subject(statement)); + + const SerdNode* const p = + serd_nodes_intern(model->nodes, serd_statement_predicate(statement)); + + const SerdNode* const o = + serd_nodes_intern(model->nodes, serd_statement_object(statement)); + + const SerdNode* const g = serd_nodes_intern( + model->nodes, + serd_statement_graph(statement) ? serd_statement_graph(statement) + : data->default_graph); + + const SerdCaret* const caret = + (data->model->flags & SERD_STORE_CARETS) ? statement->caret : NULL; + + const SerdStatus st = + serd_model_add_with_caret(data->model, s, p, o, g, caret); + + return st > SERD_FAILURE ? st : SERD_SUCCESS; +} + +static SerdStatus +serd_inserter_on_event(void* const handle, const SerdEvent* const event) +{ + SerdInserterData* const data = (SerdInserterData*)handle; + + if (event->type == SERD_STATEMENT) { + return serd_inserter_on_statement( + data, event->statement.flags, event->statement.statement); + } + + return SERD_SUCCESS; +} + +static SerdInserterData* +serd_inserter_data_new(SerdModel* const model, + const SerdNode* const default_graph) +{ + SerdInserterData* const data = + (SerdInserterData*)serd_wcalloc(model->world, 1, sizeof(SerdInserterData)); + + if (data) { + data->model = model; + data->default_graph = serd_node_copy(model->allocator, default_graph); + } + + return data; +} + +static void +serd_inserter_data_free(void* const ptr) +{ + SerdInserterData* const data = (SerdInserterData*)ptr; + serd_node_free(data->model->allocator, data->default_graph); + serd_wfree(data->model->world, data); +} + +SerdSink* +serd_inserter_new(SerdModel* const model, const SerdNode* const default_graph) +{ + assert(model); + + SerdEventFunc func = serd_inserter_on_event; + SerdInserterData* const data = serd_inserter_data_new(model, default_graph); + + return data ? serd_sink_new(serd_world_allocator(model->world), + data, + func, + (SerdFreeFunc)serd_inserter_data_free) + : NULL; +} |