diff options
author | David Robillard <d@drobilla.net> | 2020-05-30 21:32:37 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2020-10-27 13:13:59 +0100 |
commit | 7026fb72f85e349eea64a62bd924358c608520cc (patch) | |
tree | 857cef38b39ceb3687216e91904b5edc7bf48a0c | |
parent | 797eb91498ea83003922b70aa943925b4fb81bb5 (diff) | |
download | serd-7026fb72f85e349eea64a62bd924358c608520cc.tar.gz serd-7026fb72f85e349eea64a62bd924358c608520cc.tar.bz2 serd-7026fb72f85e349eea64a62bd924358c608520cc.zip |
Replace multiple stream callbacks with SerdEvent
This makes plumbing easier since everything goes through the same "stream" and
only one callback is required to handling everything. It's also more easily
extensible in case more event types need to be added in the future.
-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)); |