aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--serd/serd.h88
-rw-r--r--src/inserter.c40
-rw-r--r--src/sink.c55
-rw-r--r--src/sink.h9
-rw-r--r--src/writer.c28
-rw-r--r--tests/env_test.c10
-rw-r--r--tests/read_chunk_test.c25
-rw-r--r--tests/serd_test.c16
-rw-r--r--tests/sink_test.c27
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;
}
diff --git a/src/sink.c b/src/sink.c
index 498935a0..039246b3 100644
--- a/src/sink.c
+++ b/src/sink.c
@@ -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;
}
diff --git a/src/sink.h b/src/sink.h
index d9b5c59c..c1d6a432 100644
--- a/src/sink.h
+++ b/src/sink.h
@@ -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));