aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/serd/serd.h111
-rw-r--r--src/env.c4
-rw-r--r--src/sink.c60
-rw-r--r--src/sink.h9
-rw-r--r--src/writer.c26
-rw-r--r--test/test_env.c24
-rw-r--r--test/test_read_chunk.c25
-rw-r--r--test/test_reader_writer.c45
8 files changed, 176 insertions, 128 deletions
diff --git a/include/serd/serd.h b/include/serd/serd.h
index e32e66cc..d689cc62 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -822,42 +822,78 @@ serd_node_equals(const SerdNode* SERD_NULLABLE a,
typedef SerdStatus (*SerdErrorFunc)(void* SERD_NULLABLE handle,
const SerdError* SERD_NONNULL error);
+/// 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 function 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* SERD_NULLABLE handle,
- const SerdNode* SERD_NONNULL uri);
+typedef struct {
+ SerdEventType type; ///< #SERD_BASE
+ const SerdNode* SERD_NONNULL 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* SERD_NULLABLE handle,
- const SerdNode* SERD_NONNULL name,
- const SerdNode* SERD_NONNULL uri);
+typedef struct {
+ SerdEventType type; ///< #SERD_PREFIX
+ const SerdNode* SERD_NONNULL name; ///< Prefix name
+ const SerdNode* SERD_NONNULL 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* SERD_NULLABLE handle,
- SerdStatementFlags flags,
- const SerdStatement* SERD_NONNULL
- statement);
+typedef struct {
+ SerdEventType type; ///< #SERD_STATEMENT
+ SerdStatementFlags flags; ///< Flags for pretty-printing
+ const SerdStatement* SERD_NONNULL 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* SERD_NULLABLE handle,
- const SerdNode* SERD_NONNULL node);
+typedef struct {
+ SerdEventType type; ///< #SERD_END
+ const SerdNode* SERD_NONNULL node; ///< Anonymous node that is finished
+} SerdEndEvent;
+
+/**
+ An event in a data stream
+
+ Streams of data are represented as a 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* SERD_NULLABLE handle,
+ const SerdEvent* SERD_NONNULL event);
/**
@}
@@ -966,12 +1002,11 @@ SerdNode* SERD_ALLOCATED
serd_env_expand(const SerdEnv* SERD_NONNULL env,
const SerdNode* SERD_NONNULL node);
-/// Call `func` for each prefix defined in `env`
+/// Write all prefixes in `env` to `sink`
SERD_API
void
-serd_env_foreach(const SerdEnv* SERD_NONNULL env,
- SerdPrefixFunc SERD_NONNULL func,
- void* SERD_NULLABLE handle);
+serd_env_write_prefixes(const SerdEnv* SERD_NONNULL env,
+ const SerdSink* SERD_NONNULL sink);
/**
@}
@@ -989,41 +1024,25 @@ typedef void (*SerdFreeFunc)(void* SERD_NULLABLE ptr);
serd_sink_set_*_func functions to set handlers for various events.
@param handle Opaque handle that will be passed to sink functions.
+ @param event_func Function that will be called for every event
@param free_handle Free function to call on handle in serd_sink_free().
*/
SERD_API
SerdSink* SERD_ALLOCATED
-serd_sink_new(void* SERD_NULLABLE handle,
- SerdFreeFunc SERD_NULLABLE free_handle);
+serd_sink_new(void* SERD_NULLABLE handle,
+ SerdEventFunc SERD_NULLABLE event_func,
+ SerdFreeFunc SERD_NULLABLE free_handle);
/// Free `sink`
SERD_API
void
serd_sink_free(SerdSink* SERD_NULLABLE sink);
-/// Set a function to be called when the base URI changes
-SERD_API
-SerdStatus
-serd_sink_set_base_func(SerdSink* SERD_NONNULL sink,
- SerdBaseFunc SERD_NULLABLE base_func);
-
-/// Set a function to be called when a namespace prefix is defined
-SERD_API
-SerdStatus
-serd_sink_set_prefix_func(SerdSink* SERD_NONNULL sink,
- SerdPrefixFunc SERD_NULLABLE prefix_func);
-
-/// Set a function to be called when a statement is emitted
-SERD_API
-SerdStatus
-serd_sink_set_statement_func(SerdSink* SERD_NONNULL sink,
- SerdStatementFunc SERD_NULLABLE statement_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* SERD_NONNULL sink,
- SerdEndFunc SERD_NULLABLE end_func);
+serd_sink_write_event(const SerdSink* SERD_NONNULL sink,
+ const SerdEvent* SERD_NONNULL event);
/// Set the base URI
SERD_API
diff --git a/src/env.c b/src/env.c
index f7c8c6ba..6ff8e3f5 100644
--- a/src/env.c
+++ b/src/env.c
@@ -264,9 +264,9 @@ serd_env_expand(const SerdEnv* env, const SerdNode* node)
}
void
-serd_env_foreach(const SerdEnv* env, SerdPrefixFunc func, void* handle)
+serd_env_write_prefixes(const SerdEnv* env, const SerdSink* sink)
{
for (size_t i = 0; i < env->n_prefixes; ++i) {
- func(handle, env->prefixes[i].name, env->prefixes[i].uri);
+ serd_sink_write_prefix(sink, env->prefixes[i].name, env->prefixes[i].uri);
}
}
diff --git a/src/sink.c b/src/sink.c
index 6f8cc734..2cd601ad 100644
--- a/src/sink.c
+++ b/src/sink.c
@@ -23,11 +23,14 @@
#include <stdlib.h>
SerdSink*
-serd_sink_new(void* handle, SerdFreeFunc free_handle)
+serd_sink_new(void* const handle,
+ SerdEventFunc event_func,
+ SerdFreeFunc free_handle)
{
SerdSink* sink = (SerdSink*)calloc(1, sizeof(SerdSink));
sink->handle = handle;
+ sink->on_event = event_func;
sink->free_handle = free_handle;
return sink;
@@ -46,37 +49,30 @@ serd_sink_free(SerdSink* sink)
}
SerdStatus
-serd_sink_set_base_func(SerdSink* sink, SerdBaseFunc base_func)
+serd_sink_write_event(const SerdSink* sink, const SerdEvent* event)
{
- sink->base = base_func;
- return SERD_SUCCESS;
-}
-
-SerdStatus
-serd_sink_set_prefix_func(SerdSink* sink, SerdPrefixFunc prefix_func)
-{
- 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 +80,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 +91,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
@@ -111,5 +112,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 e0f99a53..6e8dffe3 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 4160c09d..9b10848f 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -935,6 +935,25 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node)
return SERD_SUCCESS;
}
+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)
{
@@ -975,11 +994,8 @@ serd_writer_new(SerdWorld* world,
writer->byte_sink = serd_byte_sink_new(
ssink, stream, (flags & SERD_WRITE_BULK) ? SERD_PAGE_SIZE : 1);
- 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/test/test_env.c b/test/test_env.c
index 3e38f71d..da53df45 100644
--- a/test/test_env.c
+++ b/test/test_env.c
@@ -22,20 +22,21 @@
#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;
}
static void
test_env(void)
{
+ static const SerdStringView eg = SERD_STATIC_STRING("http://example.org/");
+
SerdNode* hello = serd_new_string(SERD_STATIC_STRING("hello\""));
- SerdNode* eg = serd_new_uri(SERD_STATIC_STRING("http://example.org/"));
SerdNode* foo_u = serd_new_uri(SERD_STATIC_STRING("http://example.org/foo"));
SerdNode* foo_c = serd_new_curie(SERD_STATIC_STRING("eg.2:foo"));
SerdNode* b = serd_new_curie(SERD_STATIC_STRING("invalid"));
@@ -43,7 +44,7 @@ test_env(void)
const SerdStringView prefix = SERD_STATIC_STRING("eg.2");
SerdEnv* env = serd_env_new(SERD_EMPTY_STRING());
- serd_env_set_prefix(env, prefix, serd_node_string_view(eg));
+ serd_env_set_prefix(env, prefix, eg);
assert(!serd_env_base_uri(env));
assert(!serd_env_set_base_uri(env, SERD_EMPTY_STRING()));
@@ -81,19 +82,22 @@ test_env(void)
assert(!serd_env_expand(env, blank));
serd_node_free(blank);
- int n_prefixes = 0;
- serd_env_set_prefix(env, prefix, serd_node_string_view(eg));
- serd_env_foreach(env, count_prefixes, &n_prefixes);
+ size_t n_prefixes = 0;
+ SerdSink* const count_prefixes_sink =
+ serd_sink_new(&n_prefixes, count_prefixes, NULL);
+
+ serd_env_set_prefix(env, prefix, eg);
+ serd_env_write_prefixes(env, count_prefixes_sink);
assert(n_prefixes == 1);
SerdNode* qualified = serd_env_qualify(env, foo_u);
assert(serd_node_equals(qualified, foo_c));
serd_node_free(qualified);
+ serd_sink_free(count_prefixes_sink);
serd_node_free(foo_c);
serd_node_free(foo_u);
serd_node_free(b);
- serd_node_free(eg);
serd_env_free(env);
}
diff --git a/test/test_read_chunk.c b/test/test_read_chunk.c
index d77c3398..0f24089d 100644
--- a/test/test_read_chunk.c
+++ b/test/test_read_chunk.c
@@ -70,15 +70,29 @@ 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);
+ SerdSink* sink = serd_sink_new(NULL, on_event, NULL);
SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
assert(reader);
@@ -109,5 +123,6 @@ main(void)
serd_reader_free(reader);
serd_sink_free(sink);
serd_world_free(world);
+
return 0;
}
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index 9ccfa967..b43337f5 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -26,14 +26,11 @@
#include <string.h>
static SerdStatus
-test_sink(void* handle,
- SerdStatementFlags flags,
- const SerdStatement* statement)
+count_statements(void* handle, const SerdEvent* event)
{
- (void)flags;
- (void)statement;
-
- ++*(size_t*)handle;
+ if (event->type == SERD_STATEMENT) {
+ ++*(size_t*)handle;
+ }
return SERD_SUCCESS;
}
@@ -72,13 +69,12 @@ test_read_chunks(void)
size_t n_statements = 0;
FILE* const f = tmpfile();
static const char null = 0;
- SerdSink* sink = serd_sink_new(&n_statements, NULL);
- SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
- assert(reader);
+ SerdSink* const sink = serd_sink_new(&n_statements, count_statements, NULL);
assert(sink);
- assert(f);
- serd_sink_set_statement_func(sink, test_sink);
+
+ SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ assert(reader);
SerdStatus st = serd_reader_start_stream(
reader, (SerdReadFunc)fread, (SerdStreamErrorFunc)ferror, f, NULL, 1);
@@ -148,17 +144,14 @@ test_get_blank(void)
static void
test_read_string(void)
{
- SerdWorld* world = serd_world_new();
- size_t n_statements = 0;
- SerdSink* sink = serd_sink_new(&n_statements, NULL);
- SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ SerdWorld* world = serd_world_new();
+ size_t n_statements = 0;
- assert(reader);
+ SerdSink* sink = serd_sink_new(&n_statements, count_statements, NULL);
assert(sink);
- serd_sink_set_statement_func(sink, test_sink);
-
- serd_sink_set_statement_func(sink, test_sink);
+ SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ assert(reader);
// Test reading a string that ends exactly at the end of input (no newline)
assert(
@@ -281,14 +274,14 @@ test_writer(const char* const path)
static void
test_reader(const char* path)
{
- SerdWorld* world = serd_world_new();
- size_t n_statements = 0;
- SerdSink* const sink = serd_sink_new(&n_statements, NULL);
- SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ SerdWorld* world = serd_world_new();
+ size_t n_statements = 0;
- assert(reader);
+ SerdSink* const sink = serd_sink_new(&n_statements, count_statements, NULL);
assert(sink);
- serd_sink_set_statement_func(sink, test_sink);
+
+ SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096);
+ assert(reader);
serd_reader_add_blank_prefix(reader, "tmp");