aboutsummaryrefslogtreecommitdiffstats
path: root/serd/serd.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'serd/serd.hpp')
-rw-r--r--serd/serd.hpp1111
1 files changed, 1111 insertions, 0 deletions
diff --git a/serd/serd.hpp b/serd/serd.hpp
new file mode 100644
index 00000000..e7632212
--- /dev/null
+++ b/serd/serd.hpp
@@ -0,0 +1,1111 @@
+/*
+ Copyright 2018 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/// @file serd.hpp C++ API for Serd, a lightweight RDF syntax library
+
+#ifndef SERD_SERD_HPP
+#define SERD_SERD_HPP
+
+#include <serd/serd.h>
+
+#include <cassert>
+#include <memory>
+#include <ostream>
+#include <type_traits>
+#include <utility>
+
+/**
+ @defgroup serdxx Serdxx
+ C++ bindings for Serd, a lightweight RDF syntax library.
+ @{
+*/
+
+namespace serd {
+namespace detail {
+
+template <typename T>
+using FreeFunc = void (*)(T*);
+
+template <typename T>
+using CopyFunc = T* (*)(const T*);
+
+template <typename T>
+void
+no_free(T*)
+{
+}
+
+template <typename T>
+struct Deleter
+{
+ Deleter(FreeFunc<T> free_func) : _free_func(free_func) {}
+
+ void operator()(T* ptr)
+ {
+ if (_free_func) {
+ _free_func(ptr);
+ }
+ }
+
+ FreeFunc<T> _free_func;
+};
+
+/// C++ wrapper for a C object
+template <typename T, void FreeFunc(T*)>
+class Wrapper
+{
+public:
+ using CType = T;
+
+ Wrapper(T* ptr) : _ptr(ptr, Deleter<T>(FreeFunc)) {}
+
+ Wrapper(const T* ptr) : _ptr(const_cast<T*>(ptr), nullptr) {}
+
+ Wrapper(Wrapper&& wrapper) = default;
+ Wrapper& operator=(Wrapper&& wrapper) = default;
+
+ Wrapper(const Wrapper&) = delete;
+ Wrapper& operator=(const Wrapper&) = delete;
+
+ bool operator==(const Wrapper&) = delete;
+ bool operator!=(const Wrapper&) = delete;
+
+ operator const T*() const { return _ptr.get(); }
+
+ inline T* c_obj() { return _ptr.get(); }
+ inline const T* c_obj() const { return _ptr.get(); }
+
+protected:
+ Wrapper(std::nullptr_t) : _ptr(nullptr, nullptr) {}
+
+ std::unique_ptr<T, Deleter<T>> _ptr;
+};
+
+template <typename T, T* CopyFunc(const T*), void FreeFunc(T*)>
+class Copyable : public Wrapper<T, FreeFunc>
+{
+public:
+ Copyable(T* ptr) : Wrapper<T, FreeFunc>(ptr) {}
+
+ Copyable(const T* ptr) : Wrapper<T, FreeFunc>(ptr) {}
+
+ Copyable(const Copyable& wrapper)
+ : Wrapper<T, FreeFunc>(CopyFunc(wrapper.c_obj()))
+ {
+ }
+
+ Copyable(Copyable&&) = default;
+ Copyable& operator=(Copyable&&) = default;
+
+ Copyable& operator=(const Copyable& wrapper)
+ {
+ this->_ptr = std::unique_ptr<T, Deleter<T>>(CopyFunc(wrapper.c_obj()),
+ FreeFunc);
+ return *this;
+ }
+
+protected:
+ Copyable(std::nullptr_t) : Wrapper<T, FreeFunc>(nullptr) {}
+};
+
+static inline size_t
+stream_sink(const void* buf, size_t size, size_t nmemb, void* stream)
+{
+ try {
+ std::ostream* const s = static_cast<std::ostream*>(stream);
+ s->write(static_cast<const char*>(buf), std::streamsize(size * nmemb));
+ if (s->good()) {
+ return nmemb;
+ }
+ } catch (...) {
+ }
+ return 0;
+}
+
+/// Type-safe bit flags
+template <typename Flag>
+class Flags
+{
+public:
+ static_assert(std::is_enum<Flag>::value, "");
+
+ using FlagUnderlyingType = typename std::underlying_type<Flag>::type;
+ using Value = typename std::make_unsigned<FlagUnderlyingType>::type;
+
+ Flags() : _value(0) {}
+ Flags(const Flag f) : _value(static_cast<Value>(f)) {}
+ explicit Flags(const Value value) : _value{value} {}
+
+ Flags operator|(const Flag rhs) const
+ {
+ return Flags{_value | static_cast<Value>(rhs)};
+ }
+
+ Flags operator|(const Flags rhs) const
+ {
+ return Flags{_value | rhs._value};
+ }
+
+ operator Value() const { return _value; }
+
+private:
+ Value _value{};
+};
+
+} // namespace detail
+
+template <typename Flag>
+inline typename std::enable_if<std::is_enum<Flag>::value,
+ detail::Flags<Flag>>::type
+operator|(const Flag lhs, const Flag rhs)
+{
+ return detail::Flags<Flag>{lhs} | rhs;
+}
+
+/// Return status code
+enum class Status {
+ success = SERD_SUCCESS, ///< No error
+ failure = SERD_FAILURE, ///< Non-fatal failure
+ err_unknown = SERD_ERR_UNKNOWN, ///< Unknown error
+ err_bad_syntax = SERD_ERR_BAD_SYNTAX, ///< Invalid syntax
+ err_bad_arg = SERD_ERR_BAD_ARG, ///< Invalid argument
+ err_bad_iter = SERD_ERR_BAD_ITER, ///< Use of invalidated iterator
+ err_not_found = SERD_ERR_NOT_FOUND, ///< Not found
+ err_id_clash = SERD_ERR_ID_CLASH, ///< Clashing blank node IDs
+ err_bad_curie = SERD_ERR_BAD_CURIE, ///< Invalid CURIE
+ err_internal = SERD_ERR_INTERNAL, ///< Unexpected internal error
+ err_overflow = SERD_ERR_OVERFLOW, ///< Stack overflow
+ err_invalid = SERD_ERR_INVALID ///< Invalid data
+};
+
+/// RDF syntax type
+enum class Syntax {
+ Turtle = SERD_TURTLE, ///< Terse RDF Triple Language
+ NTriples = SERD_NTRIPLES, ///< Line-based RDF triples
+ NQuads = SERD_NQUADS, ///< Line-based RDF quads (NTriples with graphs)
+ TriG = SERD_TRIG ///< Terse RDF quads (Turtle with graphs)
+};
+
+/// Flags indicating inline abbreviation information for a statement
+enum class StatementFlag {
+ empty_S = SERD_EMPTY_S, ///< Empty blank node subject
+ anon_S = SERD_ANON_S, ///< Start of anonymous subject
+ anon_O = SERD_ANON_O, ///< Start of anonymous object
+ list_S = SERD_LIST_S, ///< Start of list subject
+ list_O = SERD_LIST_O ///< Start of list object
+};
+
+using StatementFlags = detail::Flags<StatementFlag>;
+
+/// Flags that control style for a model serialisation
+enum class SerialisationFlag {
+ no_inline_objects =
+ SERD_NO_INLINE_OBJECTS, ///< Do not inline objects where possible
+};
+
+using SerialisationFlags = detail::Flags<SerialisationFlag>;
+
+/**
+ Type of a syntactic RDF node
+
+ This is more precise than the type of an abstract RDF node. An abstract
+ node is either a resource, literal, or blank. In syntax there are two ways
+ to refer to a resource (by URI or CURIE) and two ways to refer to a blank
+ (by ID or anonymously). Anonymous (inline) blank nodes are expressed using
+ SerdStatementFlags rather than this type.
+*/
+enum class NodeType {
+ /**
+ The type of a nonexistent node
+
+ This type is useful as a sentinel, but is never emitted by the reader.
+ */
+ nothing = SERD_NOTHING,
+
+ /**
+ Literal value
+
+ A literal optionally has either a language, or a datatype (not both).
+ */
+ literal = SERD_LITERAL,
+
+ /**
+ URI (absolute or relative)
+
+ Value is an unquoted URI string, which is either a relative reference
+ with respect to the current base URI (e.g. "foo/bar"), or an absolute
+ URI (e.g. "http://example.org/foo").
+ @see <a href="http://tools.ietf.org/html/rfc3986">RFC3986</a>.
+ */
+ URI = SERD_URI,
+
+ /**
+ CURIE, a shortened URI
+
+ Value is an unquoted CURIE string relative to the current environment,
+ e.g. "rdf:type".
+ @see <a href="http://www.w3.org/TR/curie">CURIE Syntax 1.0</a>
+ */
+ CURIE = SERD_CURIE,
+
+ /**
+ A blank node
+
+ Value is a blank node ID, e.g. "id3", which is meaningful only within
+ this serialisation.
+ @see <a href="http://www.w3.org/TeamSubmission/turtle#nodeID">Turtle
+ <tt>nodeID</tt></a>
+ */
+ blank = SERD_BLANK
+};
+
+/// Flags indicating certain string properties relevant to serialisation
+enum class NodeFlag {
+ has_newline = SERD_HAS_NEWLINE, ///< Contains line breaks
+ has_quote = SERD_HAS_QUOTE, ///< Contains quotes
+ has_datatype = SERD_HAS_DATATYPE, ///< Literal node has datatype
+ has_language = SERD_HAS_LANGUAGE ///< Literal node has language
+};
+
+using NodeFlags = detail::Flags<NodeFlag>;
+
+/// Field in a statement
+enum class Field {
+ subject = SERD_SUBJECT, ///< Subject
+ predicate = SERD_PREDICATE, ///< Predicate ("key")
+ object = SERD_OBJECT, ///< Object ("value")
+ graph = SERD_GRAPH ///< Graph ("context")
+};
+
+/**
+ Syntax style options
+
+ The style of the writer output can be controlled by ORing together
+ values from this enumeration. Note that some options are only supported
+ for some syntaxes (e.g. NTriples does not support abbreviation and is
+ always ASCII).
+*/
+enum class WriterFlag {
+ ascii = SERD_STYLE_ASCII, ///< Escape all non-ASCII characters
+};
+
+using WriterFlags = detail::Flags<WriterFlag>;
+
+/// Indexing option
+enum class ModelFlag {
+ index_SPO = SERD_INDEX_SPO, ///< Subject, Predicate, Object
+ index_SOP = SERD_INDEX_SOP, ///< Subject, Object, Predicate
+ index_OPS = SERD_INDEX_OPS, ///< Object, Predicate, Subject
+ index_OSP = SERD_INDEX_OSP, ///< Object, Subject, Predicate
+ index_PSO = SERD_INDEX_PSO, ///< Predicate, Subject, Object
+ index_POS = SERD_INDEX_POS, ///< Predicate, Object, Subject
+ index_graphs = SERD_INDEX_GRAPHS ///< Support multiple graphs in model
+};
+
+using ModelFlags = detail::Flags<ModelFlag>;
+
+/**
+ A simple optional wrapper around a wrapped type with a pointer-like API
+
+ This works like a typical optional type, but only works with Wrapper types,
+ and exploits the fact that these are interally just pointers to avoid adding
+ space overhead for an "is_set" flag, like a generic optional class would.
+*/
+template <typename T>
+class Optional
+{
+public:
+ using CType = typename T::CType;
+
+ Optional() : _value() {}
+ Optional(std::nullptr_t) : _value() {}
+ Optional(const T& value) : _value(value) {}
+ Optional(T&& value) : _value(std::move(value)) {}
+
+ Optional(const Optional&) = default;
+ Optional(Optional&&) = default;
+ Optional& operator=(const Optional&) = default;
+ Optional& operator=(Optional&&) = default;
+
+ void reset() { *this = nullptr; }
+
+ const T& operator*() const
+ {
+ assert(_value.c_obj());
+ return _value;
+ }
+
+ T& operator*()
+ {
+ assert(_value.c_obj());
+ return _value;
+ }
+
+ const T* operator->() const
+ {
+ assert(_value.c_obj());
+ return &_value;
+ }
+
+ T* operator->()
+ {
+ assert(_value.c_obj());
+ return &_value;
+ }
+
+ bool operator==(const Optional& optional)
+ {
+ return (!*this && !optional) ||
+ (*this && optional && _value == optional._value);
+ }
+
+ bool operator!=(const Optional& optional) { return !operator==(optional); }
+
+ explicit operator bool() const { return _value.c_obj(); }
+
+ bool operator!() const { return !_value.c_obj(); }
+
+ inline CType* ptr() { return _value.c_obj(); }
+ inline const CType* ptr() const { return _value.c_obj(); }
+
+private:
+ T _value;
+};
+
+/**
+ A temporary reference to a string
+
+ This is used as a function parameter type to allow passing either
+ `std::string` or `const char*` without requiring multiple wrapper
+ definitions or the copying overhead of `std::string`.
+*/
+struct StringRef
+{
+ StringRef(const char* str) : _ptr(str) {}
+ StringRef(const std::string& str) : _ptr(str.c_str()) {}
+
+ StringRef(const StringRef&) = delete;
+ StringRef& operator=(const StringRef&) = delete;
+
+ operator const char*() const { return _ptr; }
+
+private:
+ const char* const _ptr;
+};
+
+/**
+ @name String Utilities
+ @{
+*/
+
+inline const char*
+strerror(const Status status)
+{
+ return serd_strerror(static_cast<SerdStatus>(status));
+}
+
+/**
+ @}
+ @name URI
+ @{
+*/
+
+inline std::string
+file_uri_parse(const StringRef& uri, std::string* hostname = nullptr)
+{
+ char* c_hostname = nullptr;
+ char* c_path = serd_file_uri_parse(uri, &c_hostname);
+ if (hostname && c_hostname) {
+ *hostname = c_hostname;
+ }
+ const std::string path(c_path);
+ free(c_hostname);
+ free(c_path);
+ return path;
+}
+
+/**
+ @}
+ @name Node
+ @{
+*/
+
+class Node : public detail::Copyable<SerdNode, serd_node_copy, serd_node_free>
+{
+public:
+ explicit Node(SerdNode* ptr) : Copyable(ptr) {}
+ explicit Node(const SerdNode* ptr) : Copyable(ptr) {}
+
+ NodeType type() const { return NodeType(serd_node_get_type(c_obj())); }
+ const char* c_str() const { return serd_node_get_string(c_obj()); }
+ std::string str() const { return c_str(); }
+ size_t size() const { return serd_node_get_length(c_obj()); }
+ size_t length() const { return serd_node_get_length(c_obj()); }
+ NodeFlags flags() const { return NodeFlags(serd_node_get_flags(c_obj())); }
+
+ Optional<Node> datatype() const
+ {
+ return Node(serd_node_get_datatype(c_obj()));
+ }
+
+ Optional<Node> language() const
+ {
+ return Node(serd_node_get_language(c_obj()));
+ }
+
+ Node resolve(const Node& base) const
+ {
+ return Node(serd_node_resolve(c_obj(), base.c_obj()));
+ }
+
+ bool operator==(const Node& node) const
+ {
+ return serd_node_equals(c_obj(), node.c_obj());
+ }
+
+ bool operator!=(const Node& node) const
+ {
+ return !serd_node_equals(c_obj(), node.c_obj());
+ }
+
+ bool operator<(const Node& node) const
+ {
+ return serd_node_compare(c_obj(), node.c_obj()) < 0;
+ }
+
+ operator std::string() const
+ {
+ return std::string(serd_node_get_string(c_obj()),
+ serd_node_get_length(c_obj()));
+ }
+
+private:
+ friend class Optional<Node>;
+ Node() : Copyable(nullptr) {}
+};
+
+inline std::ostream&
+operator<<(std::ostream& os, const Node& node)
+{
+ return os << node.c_str();
+}
+
+inline Node
+make_string(const StringRef& str)
+{
+ return Node(serd_new_string(str));
+}
+
+inline Node
+make_plain_literal(const StringRef& str, const StringRef& lang)
+{
+ return Node(serd_new_plain_literal(str, lang));
+}
+
+inline Node
+make_typed_literal(const StringRef& str, const Node& datatype)
+{
+ return Node(serd_new_typed_literal(str, datatype.c_obj()));
+}
+
+inline Node
+make_blank(const StringRef& str)
+{
+ return Node(serd_new_blank(str));
+}
+
+inline Node
+make_curie(const StringRef& str)
+{
+ return Node(serd_new_curie(str));
+}
+
+inline Node
+make_uri(const StringRef& str)
+{
+ return Node(serd_new_uri(str));
+}
+
+inline Node
+make_resolved_uri(const StringRef& str, const Node& base)
+{
+ return Node(serd_new_resolved_uri(str, base.c_obj()));
+}
+
+inline Node
+make_file_uri(const StringRef& path)
+{
+ return Node(serd_new_file_uri(path, nullptr));
+}
+
+inline Node
+make_file_uri(const StringRef& path, const StringRef& hostname)
+{
+ return Node(serd_new_file_uri(path, hostname));
+}
+
+inline Node
+make_relative_uri(const StringRef& str,
+ const Node& base,
+ const Optional<Node>& root = {})
+{
+ return Node(serd_new_relative_uri(str, base.c_obj(), root.ptr()));
+}
+
+inline Node
+make_decimal(double d,
+ unsigned frac_digits,
+ const Optional<Node>& datatype = {})
+{
+ return Node(serd_new_decimal(d, frac_digits, datatype.ptr()));
+}
+
+inline Node
+make_integer(int64_t i, const Optional<Node>& datatype = {})
+{
+ return Node(serd_new_integer(i, datatype.ptr()));
+}
+
+inline Node
+make_blob(const void* buf,
+ size_t size,
+ bool wrap_lines,
+ const Optional<Node>& datatype = {})
+{
+ return Node(serd_new_blob(buf, size, wrap_lines, datatype.ptr()));
+}
+
+/**
+ @}
+ @name World
+ @{
+*/
+
+class World : public detail::Wrapper<SerdWorld, serd_world_free>
+{
+public:
+ World() : Wrapper(serd_world_new()) {}
+
+ explicit World(SerdWorld* ptr) : Wrapper(ptr) {}
+
+ Node get_blank() { return Node(serd_world_get_blank(c_obj())); }
+
+ void set_message_sink(SerdMessageSink msg_sink, void* handle)
+ {
+ serd_world_set_message_sink(c_obj(), msg_sink, handle);
+ }
+};
+
+/**
+ @}
+ @name Statement
+ @{
+*/
+
+class Statement : public detail::Wrapper<SerdStatement, detail::no_free>
+{
+public:
+ Statement(const SerdStatement* statement) : Wrapper(statement) {}
+
+ Node node(Field field)
+ {
+ return Node(serd_statement_get_node(c_obj(),
+ static_cast<SerdField>(field)));
+ }
+
+ Node subject() const { return Node(serd_statement_get_subject(c_obj())); }
+
+ Node predicate() const
+ {
+ return Node(serd_statement_get_predicate(c_obj()));
+ }
+
+ Node object() const { return Node(serd_statement_get_object(c_obj())); }
+
+ Node graph() const { return Node(serd_statement_get_graph(c_obj())); }
+};
+
+/**
+ @}
+ @name Sink
+ @{
+*/
+
+class Sink
+{
+public:
+ Sink()
+ : _sink(serd_sink_new(this, NULL),
+ detail::Deleter<SerdSink>(serd_sink_free))
+ , _is_user(true)
+ {
+ serd_sink_set_base_func(_sink.get(), s_base);
+ serd_sink_set_prefix_func(_sink.get(), s_prefix);
+ serd_sink_set_statement_func(_sink.get(), s_statement);
+ serd_sink_set_end_func(_sink.get(), s_end);
+ }
+
+ explicit Sink(const SerdSink* ptr)
+ : _sink(const_cast<SerdSink*>(ptr), detail::Deleter<SerdSink>(nullptr))
+ , _is_user(false)
+ {
+ }
+
+ virtual ~Sink() = default;
+
+ virtual Status base(const Node& uri)
+ {
+ return _is_user ? Status::success
+ : Status(serd_sink_set_base(_sink.get(), uri.c_obj()));
+ }
+
+ virtual Status prefix(const Node& name, const Node& uri)
+ {
+ return _is_user ? Status::success
+ : Status(serd_sink_set_prefix(
+ _sink.get(), name.c_obj(), uri.c_obj()));
+ }
+
+ virtual Status statement(StatementFlags flags, const Statement& statement)
+ {
+ return _is_user ? Status::success
+ : Status(serd_sink_write_statement(
+ _sink.get(), flags, statement.c_obj()));
+ }
+
+ virtual Status write(StatementFlags flags,
+ const Node& subject,
+ const Node& predicate,
+ const Node& object,
+ const Optional<Node>& graph = {})
+ {
+ return _is_user ? Status::success
+ : Status(serd_sink_write(_sink.get(),
+ flags,
+ subject.c_obj(),
+ predicate.c_obj(),
+ object.c_obj(),
+ graph.ptr()));
+ }
+
+ virtual Status end(const Node& node)
+ {
+ return _is_user ? Status::success
+ : Status(serd_sink_end(_sink.get(), node.c_obj()));
+ }
+
+ const SerdSink* c_sink() const { return _sink.get(); }
+ SerdSink* c_sink() { return _sink.get(); }
+
+private:
+ static SerdStatus s_base(void* handle, const SerdNode* uri)
+ {
+ Sink* const sink = static_cast<Sink*>(handle);
+ return static_cast<SerdStatus>(sink->base(Node(uri)));
+ }
+
+ static SerdStatus
+ s_prefix(void* handle, const SerdNode* name, const SerdNode* uri)
+ {
+ Sink* const sink = static_cast<Sink*>(handle);
+ return static_cast<SerdStatus>(sink->prefix(Node(name), Node(uri)));
+ }
+
+ static SerdStatus s_statement(void* handle,
+ SerdStatementFlags flags,
+ const SerdStatement* statement)
+ {
+ Sink* const sink = static_cast<Sink*>(handle);
+ return static_cast<SerdStatus>(
+ sink->statement(StatementFlags(flags), statement));
+ }
+
+ static SerdStatus s_end(void* handle, const SerdNode* node)
+ {
+ Sink* const sink = static_cast<Sink*>(handle);
+ return static_cast<SerdStatus>(sink->end(Node(node)));
+ }
+
+ std::unique_ptr<SerdSink, detail::Deleter<SerdSink>> _sink;
+ bool _is_user;
+};
+
+/**
+ @}
+ @name Environment
+ @{
+*/
+
+class Env : public detail::Copyable<SerdEnv, serd_env_copy, serd_env_free>
+{
+public:
+ explicit Env(const Optional<Node>& base = {})
+ : Copyable(serd_env_new(base.ptr()))
+ {
+ }
+
+ /// Return the base URI
+ Node base_uri() const { return Node(serd_env_get_base_uri(c_obj())); }
+
+ /// Set the base URI
+ Status set_base_uri(const Node& uri)
+ {
+ return Status(serd_env_set_base_uri(c_obj(), uri.c_obj()));
+ }
+
+ /// Set a namespace prefix
+ Status set_prefix(const Node& name, const Node& uri)
+ {
+ return Status(serd_env_set_prefix(c_obj(), name.c_obj(), uri.c_obj()));
+ }
+
+ /// Set a namespace prefix
+ Status set_prefix(const StringRef& name, const StringRef& uri)
+ {
+ return Status(serd_env_set_prefix_from_strings(c_obj(), name, uri));
+ }
+
+ /// Qualify `uri` into a CURIE if possible
+ Optional<Node> qualify(const Node& uri) const
+ {
+ return Node(serd_env_qualify(c_obj(), uri.c_obj()));
+ }
+
+ /// Expand `node` into an absolute URI if possible
+ Optional<Node> expand(const Node& node) const
+ {
+ return Node(serd_env_expand(c_obj(), node.c_obj()));
+ }
+
+ /// Send all prefixes to `sink`
+ void send_prefixes(Sink& sink) const
+ {
+ serd_env_send_prefixes(c_obj(), sink.c_sink());
+ }
+
+ bool operator==(const Env& env)
+ {
+ return serd_env_equals(c_obj(), env.c_obj());
+ }
+
+ bool operator!=(const Env& env) { return !operator==(env); }
+};
+
+/**
+ @}
+ @name Reader
+ @{
+*/
+
+class Reader : public detail::Wrapper<SerdReader, serd_reader_free>
+{
+public:
+ Reader(World& world, Syntax syntax, const Sink& sink, size_t stack_size)
+ : Wrapper(serd_reader_new(world.c_obj(),
+ SerdSyntax(syntax),
+ sink.c_sink(),
+ stack_size))
+ {
+ }
+
+ void set_strict(bool strict) { serd_reader_set_strict(c_obj(), strict); }
+
+ void add_blank_prefix(const StringRef& prefix)
+ {
+ serd_reader_add_blank_prefix(c_obj(), prefix);
+ }
+
+ SerdStatus start_file(const StringRef& uri, bool bulk = true)
+ {
+ return serd_reader_start_file(c_obj(), uri, bulk);
+ }
+
+ SerdStatus start_stream(SerdReadFunc read_func,
+ SerdStreamErrorFunc error_func,
+ void* stream,
+ const Node& name,
+ size_t page_size)
+ {
+ return serd_reader_start_stream(c_obj(),
+ read_func,
+ error_func,
+ stream,
+ name.c_obj(),
+ page_size);
+ }
+
+ SerdStatus
+ start_string(const StringRef& utf8, const Optional<Node>& name = {})
+ {
+ return serd_reader_start_string(c_obj(), utf8, name.ptr());
+ }
+
+ SerdStatus read_chunk() { return serd_reader_read_chunk(c_obj()); }
+
+ SerdStatus read_document() { return serd_reader_read_document(c_obj()); }
+
+ SerdStatus finish() { return serd_reader_finish(c_obj()); }
+};
+
+/**
+ @}
+ @name Writer
+ @{
+*/
+
+class ByteSink : public detail::Wrapper<SerdByteSink, serd_byte_sink_free>
+{
+public:
+ ByteSink(SerdWriteFunc sink, void* stream, size_t block_size)
+ : Wrapper(serd_byte_sink_new(sink, stream, block_size))
+ {
+ }
+
+ ByteSink(std::ostream& stream)
+ : Wrapper(serd_byte_sink_new(detail::stream_sink, &stream, 1))
+ {
+ }
+};
+
+class Writer : public detail::Wrapper<SerdWriter, serd_writer_free>, public Sink
+{
+public:
+ Writer(World& world,
+ const Syntax syntax,
+ const WriterFlags writer_flags,
+ Env& env,
+ ByteSink& sink)
+ : Wrapper(serd_writer_new(
+ world.c_obj(),
+ SerdSyntax(syntax),
+ writer_flags,
+ env.c_obj(),
+ reinterpret_cast<SerdWriteFunc>(serd_byte_sink_write),
+ sink.c_obj()))
+ , Sink(serd_writer_get_sink(c_obj()))
+ {
+ }
+
+ Writer(World& world,
+ const Syntax syntax,
+ const WriterFlags writer_flags,
+ Env& env,
+ SerdWriteFunc write_func,
+ void* stream)
+ : Wrapper(serd_writer_new(world.c_obj(),
+ SerdSyntax(syntax),
+ writer_flags,
+ env.c_obj(),
+ write_func,
+ stream))
+ , Sink(serd_writer_get_sink(c_obj()))
+ {
+ }
+
+ Writer(World& world,
+ const Syntax syntax,
+ const WriterFlags writer_flags,
+ Env& env,
+ std::ostream& stream)
+ : Wrapper(serd_writer_new(world.c_obj(),
+ SerdSyntax(syntax),
+ writer_flags,
+ env.c_obj(),
+ detail::stream_sink,
+ &stream))
+ , Sink(serd_writer_get_sink(c_obj()))
+ {
+ }
+
+ Status set_root_uri(const Node& uri)
+ {
+ return Status(serd_writer_set_root_uri(c_obj(), uri.c_obj()));
+ }
+
+ SerdStatus finish() { return serd_writer_finish(c_obj()); }
+};
+
+/**
+ @}
+*/
+
+class Iter : public detail::Copyable<SerdIter, serd_iter_copy, serd_iter_free>
+{
+public:
+ Iter(SerdIter* i) : Copyable(i) {}
+ Iter(const SerdIter* i) : Copyable(i) {}
+
+ Iter& operator++()
+ {
+ serd_iter_next(c_obj());
+ return *this;
+ }
+
+ Statement operator*() const { return Statement(serd_iter_get(c_obj())); }
+
+ bool operator==(const Iter& i) const
+ {
+ return serd_iter_equals(c_obj(), i.c_obj());
+ }
+
+ bool operator!=(const Iter& i) const
+ {
+ return !serd_iter_equals(c_obj(), i.c_obj());
+ }
+};
+
+class Range
+ : public detail::Copyable<SerdRange, serd_range_copy, serd_range_free>
+{
+public:
+ Range(SerdRange* r) : Copyable(r) {}
+ Range(const SerdRange* r) : Copyable(r) {}
+
+ Iter begin() const { return Iter(serd_range_begin(c_obj())); }
+ Iter end() const { return Iter(serd_range_end(c_obj())); }
+
+ bool operator==(const Range& i) const
+ {
+ return serd_range_equals(c_obj(), i.c_obj());
+ }
+
+ bool operator!=(const Range& i) const
+ {
+ return !serd_range_equals(c_obj(), i.c_obj());
+ }
+};
+
+class Model
+ : public detail::Copyable<SerdModel, serd_model_copy, serd_model_free>
+{
+public:
+ using value_type = Statement;
+ using iterator = Iter;
+ using const_iterator = Iter;
+
+ Model(World& world, ModelFlags flags)
+ : Copyable(serd_model_new(world.c_obj(), flags))
+ {
+ }
+
+ Model(World& world, ModelFlag flag)
+ : Copyable(serd_model_new(world.c_obj(), ModelFlags(flag)))
+ {
+ }
+
+ size_t size() const { return serd_model_size(c_obj()); }
+
+ bool empty() const { return serd_model_empty(c_obj()); }
+
+ void insert(const Statement& s) { serd_model_insert(c_obj(), s.c_obj()); }
+
+ void insert(const Node& s,
+ const Node& p,
+ const Node& o,
+ const Optional<Node>& g = {})
+ {
+ serd_model_add(c_obj(), s.c_obj(), p.c_obj(), o.c_obj(), g.ptr());
+ }
+
+ Iter find(const Optional<Node>& s,
+ const Optional<Node>& p,
+ const Optional<Node>& o,
+ const Optional<Node>& g = {}) const
+ {
+ return Iter(
+ serd_model_find(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr()));
+ }
+
+ Range range(const Optional<Node>& s,
+ const Optional<Node>& p,
+ const Optional<Node>& o,
+ const Optional<Node>& g = {}) const
+ {
+ return Range(
+ serd_model_range(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr()));
+ }
+
+ Optional<Node> get(const Optional<Node>& s,
+ const Optional<Node>& p,
+ const Optional<Node>& o,
+ const Optional<Node>& g = {}) const
+ {
+ return Node(
+ serd_model_get(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr()));
+ }
+
+ Optional<Statement> get_statement(const Optional<Node>& s,
+ const Optional<Node>& p,
+ const Optional<Node>& o,
+ const Optional<Node>& g = {}) const
+ {
+ return Statement(serd_model_get_statement(
+ c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr()));
+ }
+
+ bool ask(const Optional<Node>& s,
+ const Optional<Node>& p,
+ const Optional<Node>& o,
+ const Optional<Node>& g = {}) const
+ {
+ return serd_model_ask(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr());
+ }
+
+ size_t count(const Optional<Node>& s,
+ const Optional<Node>& p,
+ const Optional<Node>& o,
+ const Optional<Node>& g = {}) const
+ {
+ return serd_model_count(c_obj(), s.ptr(), p.ptr(), o.ptr(), g.ptr());
+ }
+
+ bool operator==(const Model& model) const
+ {
+ return serd_model_equals(c_obj(), model.c_obj());
+ }
+
+ bool operator!=(const Model& model) const
+ {
+ return !serd_model_equals(c_obj(), model.c_obj());
+ }
+
+ Range all() const { return Range(serd_model_all(c_obj())); }
+
+ iterator begin() const { return iterator(serd_model_begin(c_obj())); }
+
+ iterator end() const { return iterator(serd_model_end(c_obj())); }
+};
+
+class Inserter : public detail::Wrapper<SerdInserter, serd_inserter_free>,
+ public Sink
+{
+public:
+ Inserter(Model& model, Env& env, const Optional<Node>& default_graph = {})
+ : Wrapper(serd_inserter_new(model.c_obj(),
+ env.c_obj(),
+ default_graph.ptr()))
+ , Sink(serd_inserter_get_sink(c_obj()))
+ {
+ }
+};
+
+} // namespace serd
+
+/**
+ @}
+*/
+
+#endif /* SERD_SERD_HPP */