From b085fe7aa38e5e2caf82b1fec6b7e6094779dd5a Mon Sep 17 00:00:00 2001
From: David Robillard <d@drobilla.net>
Date: Mon, 1 Mar 2021 19:38:01 -0500
Subject: Add SerdSink interface and hide implementations

---
 include/serd/serd.h | 139 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 91 insertions(+), 48 deletions(-)

(limited to 'include')

diff --git a/include/serd/serd.h b/include/serd/serd.h
index 08b81269..9c205d26 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -77,12 +77,15 @@ extern "C" {
 /// Lexical environment for relative URIs or CURIEs (base URI and namespaces)
 typedef struct SerdEnvImpl SerdEnv;
 
-/// Streaming parser that reads a text stream and writes to a statement sink
+/// Streaming parser that reads a text stream and writes to a sink
 typedef struct SerdReaderImpl SerdReader;
 
 /// Streaming serialiser that writes a text stream as statements are pushed
 typedef struct SerdWriterImpl SerdWriter;
 
+/// An interface that receives a stream of RDF data
+typedef struct SerdSinkImpl SerdSink;
+
 /// Return status code
 typedef enum {
   SERD_SUCCESS,        ///< No error
@@ -810,6 +813,87 @@ serd_env_foreach(const SerdEnv* SERD_NONNULL env,
                  SerdPrefixFunc SERD_NONNULL func,
                  void* SERD_NULLABLE         handle);
 
+/**
+   @}
+   @defgroup serd_sink Sink
+   @{
+*/
+
+/// Function to free an opaque handle
+typedef void (*SerdFreeFunc)(void* SERD_NULLABLE ptr);
+
+/**
+   Create a new sink.
+
+   Initially, the sink has no set functions and will do nothing.  Use the
+   serd_sink_set_*_func functions to set handlers for various events.
+
+   @param handle Opaque handle that will be passed to sink functions.
+   @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);
+
+/// 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
+SERD_API
+SerdStatus
+serd_sink_set_end_func(SerdSink* SERD_NONNULL    sink,
+                       SerdEndFunc SERD_NULLABLE end_func);
+
+/// Set the base URI
+SERD_API
+SerdStatus
+serd_sink_write_base(const SerdSink* SERD_NONNULL sink,
+                     const SerdNode* SERD_NONNULL uri);
+
+/// Set a namespace prefix
+SERD_API
+SerdStatus
+serd_sink_write_prefix(const SerdSink* SERD_NONNULL sink,
+                       const SerdNode* SERD_NONNULL name,
+                       const SerdNode* SERD_NONNULL uri);
+
+/// Write a statement from individual nodes
+SERD_API
+SerdStatus
+serd_sink_write(const SerdSink* SERD_NONNULL  sink,
+                SerdStatementFlags            flags,
+                const SerdNode* SERD_NONNULL  subject,
+                const SerdNode* SERD_NONNULL  predicate,
+                const SerdNode* SERD_NONNULL  object,
+                const SerdNode* SERD_NULLABLE graph);
+
+/// Mark the end of an anonymous node
+SERD_API
+SerdStatus
+serd_sink_write_end(const SerdSink* SERD_NONNULL sink,
+                    const SerdNode* SERD_NONNULL node);
+
 /**
    @}
    @defgroup serd_reader Reader
@@ -819,13 +903,7 @@ serd_env_foreach(const SerdEnv* SERD_NONNULL env,
 /// Create a new RDF reader
 SERD_API
 SerdReader* SERD_ALLOCATED
-serd_reader_new(SerdSyntax          syntax,
-                void* SERD_NULLABLE handle,
-                void (*SERD_NULLABLE free_handle)(void* SERD_NULLABLE),
-                SerdBaseFunc SERD_NULLABLE      base_func,
-                SerdPrefixFunc SERD_NULLABLE    prefix_func,
-                SerdStatementFunc SERD_NULLABLE statement_func,
-                SerdEndFunc SERD_NULLABLE       end_func);
+serd_reader_new(SerdSyntax syntax, const SerdSink* SERD_NONNULL sink);
 
 /**
    Enable or disable strict parsing
@@ -850,11 +928,6 @@ serd_reader_set_error_sink(SerdReader* SERD_NONNULL    reader,
                            SerdErrorFunc SERD_NULLABLE error_func,
                            void* SERD_NULLABLE         error_handle);
 
-/// Return the `handle` passed to serd_reader_new()
-SERD_PURE_API
-void* SERD_NULLABLE
-serd_reader_handle(const SerdReader* SERD_NONNULL reader);
-
 /**
    Set a prefix to be added to all blank node identifiers.
 
@@ -967,6 +1040,11 @@ SERD_API
 void
 serd_writer_free(SerdWriter* SERD_NULLABLE writer);
 
+/// Return a sink interface that emits statements via `writer`
+SERD_CONST_API
+const SerdSink* SERD_NONNULL
+serd_writer_sink(SerdWriter* SERD_NONNULL writer);
+
 /// Return the env used by `writer`
 SERD_PURE_API
 SerdEnv* SERD_NONNULL
@@ -1045,41 +1123,6 @@ SerdStatus
 serd_writer_set_root_uri(SerdWriter* SERD_NONNULL      writer,
                          const SerdNode* SERD_NULLABLE uri);
 
-/**
-   Set a namespace prefix (and emit directive if applicable).
-
-   Note this function can be safely casted to SerdPrefixSink.
-*/
-SERD_API
-SerdStatus
-serd_writer_set_prefix(SerdWriter* SERD_NONNULL     writer,
-                       const SerdNode* SERD_NONNULL name,
-                       const SerdNode* SERD_NONNULL uri);
-
-/**
-   Write a statement.
-
-   Note this function can be safely casted to SerdStatementSink.
-*/
-SERD_API
-SerdStatus
-serd_writer_write_statement(SerdWriter* SERD_NONNULL      writer,
-                            SerdStatementFlags            flags,
-                            const SerdNode* SERD_NULLABLE graph,
-                            const SerdNode* SERD_NONNULL  subject,
-                            const SerdNode* SERD_NONNULL  predicate,
-                            const SerdNode* SERD_NONNULL  object);
-
-/**
-   Mark the end of an anonymous node's description.
-
-   Note this function can be safely casted to SerdEndSink.
-*/
-SERD_API
-SerdStatus
-serd_writer_end_anon(SerdWriter* SERD_NONNULL      writer,
-                     const SerdNode* SERD_NULLABLE node);
-
 /**
    Finish a write
 
-- 
cgit v1.2.1