diff options
-rw-r--r-- | serd/serd.h | 88 | ||||
-rw-r--r-- | src/inserter.c | 40 | ||||
-rw-r--r-- | src/sink.c | 55 | ||||
-rw-r--r-- | src/sink.h | 9 | ||||
-rw-r--r-- | src/writer.c | 28 | ||||
-rw-r--r-- | tests/env_test.c | 10 | ||||
-rw-r--r-- | tests/read_chunk_test.c | 25 | ||||
-rw-r--r-- | tests/serd_test.c | 16 | ||||
-rw-r--r-- | tests/sink_test.c | 27 |
9 files changed, 194 insertions, 104 deletions
diff --git a/serd/serd.h b/serd/serd.h index 5a6815f8..4dd7e7bd 100644 --- a/serd/serd.h +++ b/serd/serd.h @@ -849,39 +849,77 @@ serd_node_compare(const SerdNode* a, const SerdNode* b); @{ */ +/// Type of a SerdEvent +typedef enum { + SERD_BASE = 1, ///< Base URI changed + SERD_PREFIX = 2, ///< New URI prefix + SERD_STATEMENT = 3, ///< Statement + SERD_END = 4 ///< End of anonymous node +} SerdEventType; + /** - Sink (callback) for base URI changes + Event for base URI changes - Called whenever the base URI of the serialisation changes. + Emitted whenever the base URI of the serialisation changes. */ -typedef SerdStatus (*SerdBaseFunc)(void* handle, const SerdNode* uri); +typedef struct { + SerdEventType type; ///< #SERD_BASE + const SerdNode* uri; ///< Base URI +} SerdBaseEvent; /** - Sink function for namespace definitions + Event for namespace definitions - Called whenever a prefix is defined in the serialisation. + Emitted whenever a prefix is defined in the serialisation. */ -typedef SerdStatus (*SerdPrefixFunc)(void* handle, - const SerdNode* name, - const SerdNode* uri); +typedef struct { + SerdEventType type; ///< #SERD_PREFIX + const SerdNode* name; ///< Prefix name + const SerdNode* uri; ///< Namespace URI +} SerdPrefixEvent; /** - Sink function for statements + Event for statements - Called for every RDF statement in the serialisation. + Emitted for every RDF statement in the serialisation. */ -typedef SerdStatus (*SerdStatementFunc)(void* handle, - SerdStatementFlags flags, - const SerdStatement* statement); +typedef struct { + SerdEventType type; ///< #SERD_STATEMENT + SerdStatementFlags flags; ///< Flags for streaming pretty-printing + const SerdStatement* statement; ///< Statement +} SerdStatementEvent; /** - Sink function for anonymous node end markers + Event for the end of anonymous node descriptions - This is called to indicate that the anonymous node with the given + This is emitted to indicate that the anonymous node with the given `value` will no longer be referred to by any future statements (i.e. the anonymous serialisation of the node is finished). */ -typedef SerdStatus (*SerdEndFunc)(void* handle, const SerdNode* node); +typedef struct { + SerdEventType type; ///< #SERD_END + const SerdNode* node; ///< Anonymous blank node that is finished +} SerdEndEvent; + +/** + An event in a data stream + + Streams of data are represented as an ordered series of events. Events + represent everything that can occur in an RDF document, and are used to plumb + together different components. For example, when parsing a document, a + reader emits a stream of events which can be sent to a writer to serialise a + document, or to an inserter to build a model in memory. +*/ +typedef union { + SerdEventType type; ///< Event type (always set) + SerdBaseEvent base; ///< Base URI changed + SerdPrefixEvent prefix; ///< New namespace prefix + SerdStatementEvent statement; ///< Statement + SerdEndEvent end; ///< End of anonymous node +} SerdEvent; + +/// Function for handling events +typedef SerdStatus (*SerdEventFunc)(void* handle, const SerdEvent* event); /** @} @@ -1127,25 +1165,15 @@ SERD_API void serd_sink_free(SerdSink* sink); -/// Set a function to be called when the base URI changes -SERD_API -SerdStatus -serd_sink_set_base_func(SerdSink* sink, SerdBaseFunc base_func); - -/// Set a function to be called when a namespace prefix is defined -SERD_API -SerdStatus -serd_sink_set_prefix_func(SerdSink* sink, SerdPrefixFunc prefix_func); - -/// Set a function to be called when a statement is emitted +/// Set a function to be called for every event SERD_API SerdStatus -serd_sink_set_statement_func(SerdSink* sink, SerdStatementFunc statement_func); +serd_sink_set_event_func(SerdSink* sink, SerdEventFunc event_func); -/// Set a function to be called when an anonymous node ends +/// Send an event to the sink SERD_API SerdStatus -serd_sink_set_end_func(SerdSink* sink, SerdEndFunc end_func); +serd_sink_write_event(const SerdSink* sink, const SerdEvent* event); /// Set the base URI SERD_API diff --git a/src/inserter.c b/src/inserter.c index e2f95896..5ee5d2c2 100644 --- a/src/inserter.c +++ b/src/inserter.c @@ -36,20 +36,6 @@ manage_or_intern(SerdNodes* nodes, SerdNode* manage, const SerdNode* intern) } static SerdStatus -serd_inserter_on_base(SerdInserterData* data, const SerdNode* uri) -{ - return serd_env_set_base_uri(data->env, uri); -} - -static SerdStatus -serd_inserter_on_prefix(SerdInserterData* data, - const SerdNode* name, - const SerdNode* uri) -{ - return serd_env_set_prefix(data->env, name, uri); -} - -static SerdStatus serd_inserter_on_statement(SerdInserterData* data, const SerdStatementFlags flags, const SerdStatement* statement) @@ -85,6 +71,27 @@ serd_inserter_on_statement(SerdInserterData* data, return st > SERD_FAILURE ? st : SERD_SUCCESS; } +static SerdStatus +serd_inserter_on_event(SerdInserterData* data, const SerdEvent* event) +{ + switch (event->type) { + case SERD_BASE: + return serd_env_set_base_uri(data->env, event->base.uri); + case SERD_PREFIX: + return serd_env_set_prefix(data->env, + event->prefix.name, + event->prefix.uri); + case SERD_STATEMENT: + return serd_inserter_on_statement(data, + event->statement.flags, + event->statement.statement); + case SERD_END: + break; + } + + return SERD_SUCCESS; +} + static void free_data(void* handle) { @@ -108,10 +115,7 @@ serd_inserter_new(SerdModel* model, SerdEnv* env, const SerdNode* default_graph) SerdSink* const sink = serd_sink_new(data, free_data); - serd_sink_set_base_func(sink, (SerdBaseFunc)serd_inserter_on_base); - serd_sink_set_prefix_func(sink, (SerdPrefixFunc)serd_inserter_on_prefix); - serd_sink_set_statement_func(sink, - (SerdStatementFunc)serd_inserter_on_statement); + serd_sink_set_event_func(sink, (SerdEventFunc)serd_inserter_on_event); return sink; } @@ -46,37 +46,40 @@ serd_sink_free(SerdSink* sink) } SerdStatus -serd_sink_set_base_func(SerdSink* sink, SerdBaseFunc base_func) +serd_sink_set_event_func(SerdSink* sink, SerdEventFunc event_func) { - sink->base = base_func; + sink->on_event = event_func; return SERD_SUCCESS; } SerdStatus -serd_sink_set_prefix_func(SerdSink* sink, SerdPrefixFunc prefix_func) +serd_sink_write_event(const SerdSink* sink, const SerdEvent* event) { - sink->prefix = prefix_func; - return SERD_SUCCESS; -} - -SerdStatus -serd_sink_set_statement_func(SerdSink* sink, SerdStatementFunc statement_func) -{ - sink->statement = statement_func; - return SERD_SUCCESS; -} + switch (event->type) { + case SERD_BASE: + return serd_sink_write_base(sink, event->base.uri); + case SERD_PREFIX: + return serd_sink_write_prefix(sink, + event->prefix.name, + event->prefix.uri); + case SERD_STATEMENT: + return serd_sink_write_statement(sink, + event->statement.flags, + event->statement.statement); + case SERD_END: + return serd_sink_write_end(sink, event->end.node); + } -SerdStatus -serd_sink_set_end_func(SerdSink* sink, SerdEndFunc end_func) -{ - sink->end = end_func; return SERD_SUCCESS; } SerdStatus serd_sink_write_base(const SerdSink* sink, const SerdNode* uri) { - return sink->base ? sink->base(sink->handle, uri) : SERD_SUCCESS; + const SerdBaseEvent ev = { SERD_BASE, uri }; + + return sink->on_event ? sink->on_event(sink->handle, (const SerdEvent*)&ev) + : SERD_SUCCESS; } SerdStatus @@ -84,7 +87,10 @@ serd_sink_write_prefix(const SerdSink* sink, const SerdNode* name, const SerdNode* uri) { - return sink->prefix ? sink->prefix(sink->handle, name, uri) : SERD_SUCCESS; + const SerdPrefixEvent ev = { SERD_PREFIX, name, uri }; + + return sink->on_event ? sink->on_event(sink->handle, (const SerdEvent*)&ev) + : SERD_SUCCESS; } SerdStatus @@ -92,8 +98,10 @@ serd_sink_write_statement(const SerdSink* sink, const SerdStatementFlags flags, const SerdStatement* statement) { - return sink->statement ? sink->statement(sink->handle, flags, statement) - : SERD_SUCCESS; + const SerdStatementEvent ev = { SERD_STATEMENT, flags, statement }; + + return sink->on_event ? sink->on_event(sink->handle, (const SerdEvent*)&ev) + : SERD_SUCCESS; } SerdStatus @@ -112,5 +120,8 @@ serd_sink_write(const SerdSink* sink, SerdStatus serd_sink_write_end(const SerdSink* sink, const SerdNode* node) { - return sink->end ? sink->end(sink->handle, node) : SERD_SUCCESS; + const SerdEndEvent ev = {SERD_END, node}; + + return sink->on_event ? sink->on_event(sink->handle, (const SerdEvent*)&ev) + : SERD_SUCCESS; } @@ -23,12 +23,9 @@ An interface that receives a stream of RDF data. */ struct SerdSinkImpl { - void* handle; - SerdFreeFunc free_handle; - SerdBaseFunc base; - SerdPrefixFunc prefix; - SerdStatementFunc statement; - SerdEndFunc end; + void* handle; + SerdFreeFunc free_handle; + SerdEventFunc on_event; }; #endif // SERD_SINK_H diff --git a/src/writer.c b/src/writer.c index 2686cc8a..29d9e902 100644 --- a/src/writer.c +++ b/src/writer.c @@ -996,6 +996,27 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) return st; } +static SerdStatus +serd_writer_on_event(SerdWriter* writer, const SerdEvent* event) +{ + switch (event->type) { + case SERD_BASE: + return serd_writer_set_base_uri(writer, event->base.uri); + case SERD_PREFIX: + return serd_writer_set_prefix(writer, + event->prefix.name, + event->prefix.uri); + case SERD_STATEMENT: + return serd_writer_write_statement(writer, + event->statement.flags, + event->statement.statement); + case SERD_END: + return serd_writer_end_anon(writer, event->end.node); + } + + return SERD_SUCCESS; +} + SerdStatus serd_writer_finish(SerdWriter* writer) { @@ -1037,11 +1058,8 @@ serd_writer_new(SerdWorld* world, writer->context = context; writer->empty = true; - writer->iface.handle = writer; - writer->iface.base = (SerdBaseFunc)serd_writer_set_base_uri; - writer->iface.prefix = (SerdPrefixFunc)serd_writer_set_prefix; - writer->iface.statement = (SerdStatementFunc)serd_writer_write_statement; - writer->iface.end = (SerdEndFunc)serd_writer_end_anon; + writer->iface.handle = writer; + writer->iface.on_event = (SerdEventFunc)serd_writer_on_event; return writer; } diff --git a/tests/env_test.c b/tests/env_test.c index ee172fff..cc04366d 100644 --- a/tests/env_test.c +++ b/tests/env_test.c @@ -22,12 +22,12 @@ #include <string.h> static SerdStatus -count_prefixes(void* handle, const SerdNode* name, const SerdNode* uri) +count_prefixes(void* handle, const SerdEvent* event) { - (void)name; - (void)uri; + if (event->type == SERD_PREFIX) { + ++*(int*)handle; + } - ++*(int*)handle; return SERD_SUCCESS; } @@ -87,7 +87,7 @@ test_env(void) size_t n_prefixes = 0; SerdSink* count_prefixes_sink = serd_sink_new(&n_prefixes, NULL); - serd_sink_set_prefix_func(count_prefixes_sink, count_prefixes); + serd_sink_set_event_func(count_prefixes_sink, count_prefixes); serd_env_set_prefix(env, pre, eg); serd_env_write_prefixes(env, count_prefixes_sink); serd_sink_free(count_prefixes_sink); diff --git a/tests/read_chunk_test.c b/tests/read_chunk_test.c index 31b11603..dfa0c0ac 100644 --- a/tests/read_chunk_test.c +++ b/tests/read_chunk_test.c @@ -70,15 +70,31 @@ on_end(void* handle, const SerdNode* node) return SERD_SUCCESS; } +static SerdStatus +on_event(void* handle, const SerdEvent* event) +{ + switch (event->type) { + case SERD_BASE: + return on_base(handle, event->base.uri); + case SERD_PREFIX: + return on_prefix(handle, event->prefix.name, event->prefix.uri); + case SERD_STATEMENT: + return on_statement(handle, + event->statement.flags, + event->statement.statement); + case SERD_END: + return on_end(handle, event->end.node); + } + + return SERD_SUCCESS; +} + int main(void) { SerdWorld* world = serd_world_new(); SerdSink* sink = serd_sink_new(NULL, NULL); - serd_sink_set_base_func(sink, on_base); - serd_sink_set_prefix_func(sink, on_prefix); - serd_sink_set_statement_func(sink, on_statement); - serd_sink_set_end_func(sink, on_end); + serd_sink_set_event_func(sink, on_event); SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0, sink, 4096); assert(reader); @@ -108,5 +124,6 @@ main(void) serd_reader_free(reader); serd_sink_free(sink); serd_world_free(world); + return 0; } diff --git a/tests/serd_test.c b/tests/serd_test.c index f7931364..16209c27 100644 --- a/tests/serd_test.c +++ b/tests/serd_test.c @@ -28,14 +28,12 @@ #define NS_XSD "http://www.w3.org/2001/XMLSchema#" static SerdStatus -count_statements(void* handle, - SerdStatementFlags flags, - const SerdStatement* statement) +count_statements(void* handle, const SerdEvent* event) { - (void)flags; - (void)statement; + if (event->type == SERD_STATEMENT) { + ++*(size_t*)handle; + } - ++*(size_t*)handle; return SERD_SUCCESS; } @@ -99,7 +97,7 @@ test_read_chunks(void) SerdSink* sink = serd_sink_new(&n_statements, NULL); assert(sink); - serd_sink_set_statement_func(sink, count_statements); + serd_sink_set_event_func(sink, count_statements); SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0, sink, 4096); assert(reader); @@ -219,7 +217,7 @@ test_read_string(void) SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0, sink, 4096); assert(reader); - serd_sink_set_statement_func(sink, count_statements); + serd_sink_set_event_func(sink, count_statements); // Test reading a string that ends exactly at the end of input (no newline) assert(!serd_reader_start_string( @@ -676,7 +674,7 @@ test_reader(const char* path) size_t n_statements = 0; SerdSink* sink = serd_sink_new(&n_statements, NULL); - serd_sink_set_statement_func(sink, count_statements); + serd_sink_set_event_func(sink, count_statements); SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0, sink, 4096); assert(reader); diff --git a/tests/sink_test.c b/tests/sink_test.c index 71981cdb..cde0050e 100644 --- a/tests/sink_test.c +++ b/tests/sink_test.c @@ -74,6 +74,25 @@ on_end(void* handle, const SerdNode* node) return state->return_status; } +static SerdStatus +on_event(void* handle, const SerdEvent* event) +{ + switch (event->type) { + case SERD_BASE: + return on_base(handle, event->base.uri); + case SERD_PREFIX: + return on_prefix(handle, event->prefix.name, event->prefix.uri); + case SERD_STATEMENT: + return on_statement(handle, + event->statement.flags, + event->statement.statement); + case SERD_END: + return on_end(handle, event->end.node); + } + + return SERD_SUCCESS; +} + int main(void) { @@ -99,22 +118,20 @@ main(void) assert(!serd_sink_write(sink, 0, base, uri, blank, NULL)); assert(!serd_sink_write_end(sink, blank)); - // Set functions and try again + // Set event handler and try again + + serd_sink_set_event_func(sink, on_event); - serd_sink_set_base_func(sink, on_base); assert(!serd_sink_write_base(sink, base)); assert(serd_node_equals(state.last_base, base)); - serd_sink_set_prefix_func(sink, on_prefix); assert(!serd_sink_write_prefix(sink, name, uri)); assert(serd_node_equals(state.last_name, name)); assert(serd_node_equals(state.last_namespace, uri)); - serd_sink_set_statement_func(sink, on_statement); assert(!serd_sink_write_statement(sink, 0, statement)); assert(serd_statement_equals(state.last_statement, statement)); - serd_sink_set_end_func(sink, on_end); assert(!serd_sink_write_end(sink, blank)); assert(serd_node_equals(state.last_end, blank)); |