aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-05-05 09:43:57 -0400
committerDavid Robillard <d@drobilla.net>2023-12-02 18:49:08 -0500
commit4711fdf527f416faee8ff19e15f050d4b48dcfb2 (patch)
tree6b18712ec44cce5713ddef1a21aec5f12651d901 /src
parent248a874d7425749d29cf900a1c3783c624ea8d8c (diff)
downloadserd-4711fdf527f416faee8ff19e15f050d4b48dcfb2.tar.gz
serd-4711fdf527f416faee8ff19e15f050d4b48dcfb2.tar.bz2
serd-4711fdf527f416faee8ff19e15f050d4b48dcfb2.zip
[WIP] Generalize node construction API
Diffstat (limited to 'src')
-rw-r--r--src/base64.c27
-rw-r--r--src/base64.h35
-rw-r--r--src/byte_source.c3
-rw-r--r--src/env.c37
-rw-r--r--src/node.c967
-rw-r--r--src/node.h66
-rw-r--r--src/read_turtle.c2
-rw-r--r--src/value.c101
-rw-r--r--src/world.c4
-rw-r--r--src/writer.c7
10 files changed, 788 insertions, 461 deletions
diff --git a/src/base64.c b/src/base64.c
deleted file mode 100644
index 50ec3981..00000000
--- a/src/base64.c
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2011-2020 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#include "base64.h"
-
-#include "exess/exess.h"
-#include "serd/string.h"
-
-#include <stdlib.h>
-
-void*
-serd_base64_decode(const char* const str, const size_t len, size_t* const size)
-{
- const size_t max_size = exess_base64_decoded_size(len);
-
- void* const buf = malloc(max_size);
- const ExessVariableResult r = exess_read_base64(max_size, buf, str);
- if (r.status) {
- *size = 0;
- free(buf);
- return NULL;
- }
-
- *size = r.write_count;
-
- return buf;
-}
diff --git a/src/base64.h b/src/base64.h
deleted file mode 100644
index d3e2b6e1..00000000
--- a/src/base64.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2011-2023 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#ifndef SERD_SRC_BASE64_H
-#define SERD_SRC_BASE64_H
-
-#include "serd/attributes.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- Return the number of bytes required to encode `size` bytes in base64.
-
- @param size The number of input (binary) bytes to encode.
- @param wrap_lines Wrap lines at 76 characters to conform to RFC 2045.
- @return The length of the base64 encoding, excluding null terminator.
-*/
-SERD_CONST_FUNC size_t
-serd_base64_get_length(size_t size, bool wrap_lines);
-
-/**
- Encode `size` bytes of `buf` into `str`, which must be large enough.
-
- @param str Output string buffer.
- @param buf Input binary data.
- @param size Number of bytes to encode from `buf`.
- @param wrap_lines Wrap lines at 76 characters to conform to RFC 2045.
- @return True iff `str` contains newlines.
-*/
-bool
-serd_base64_encode(uint8_t* str, const void* buf, size_t size, bool wrap_lines);
-
-#endif // SERD_SRC_BASE64_H
diff --git a/src/byte_source.c b/src/byte_source.c
index cf9a2466..249c0dde 100644
--- a/src/byte_source.c
+++ b/src/byte_source.c
@@ -7,7 +7,6 @@
#include "system.h"
#include "serd/node.h"
-#include "serd/string_view.h"
#include <assert.h>
#include <stdbool.h>
@@ -67,7 +66,7 @@ serd_byte_source_new_input(SerdAllocator* const allocator,
SerdNode* const source_name =
name ? serd_node_copy(allocator, name)
- : serd_new_string(allocator, serd_string("input"));
+ : serd_node_new(allocator, serd_a_string("input"));
if (!source_name) {
return NULL;
diff --git a/src/env.c b/src/env.c
index 90924cd2..dcffb98e 100644
--- a/src/env.c
+++ b/src/env.c
@@ -159,7 +159,7 @@ serd_env_set_base_uri(SerdEnv* const env, const SerdStringView uri)
// Replace the current base URI
if ((env->base_uri_node =
- serd_new_parsed_uri(env->allocator, new_base_uri))) {
+ serd_node_new(env->allocator, serd_a_parsed_uri(new_base_uri)))) {
env->base_uri = serd_node_uri_view(env->base_uri_node);
} else {
return SERD_BAD_ALLOC;
@@ -209,7 +209,7 @@ serd_env_add(SerdEnv* const env,
if (prefix) {
if (!!strcmp(serd_node_string(prefix->uri), uri.data)) {
serd_node_free(env->allocator, prefix->uri);
- prefix->uri = serd_new_uri(env->allocator, uri);
+ prefix->uri = serd_node_new(env->allocator, serd_a_uri(uri));
}
} else {
SerdPrefix* const new_prefixes =
@@ -222,8 +222,9 @@ serd_env_add(SerdEnv* const env,
env->prefixes = new_prefixes;
- SerdNode* const name_node = serd_new_string(env->allocator, name);
- SerdNode* const uri_node = serd_new_uri(env->allocator, uri);
+ SerdNode* const name_node =
+ serd_node_new(env->allocator, serd_a_string_view(name));
+ SerdNode* const uri_node = serd_node_new(env->allocator, serd_a_uri(uri));
if (!name_node || !uri_node) {
serd_node_free(env->allocator, uri_node);
serd_node_free(env->allocator, name_node);
@@ -260,7 +261,8 @@ serd_env_set_prefix(SerdEnv* const env,
assert(abs_uri_view.scheme.length);
// Create a new node for the absolute URI
- SerdNode* const abs_uri = serd_new_parsed_uri(env->allocator, abs_uri_view);
+ SerdNode* const abs_uri =
+ serd_node_new(env->allocator, serd_a_parsed_uri(abs_uri_view));
if (!abs_uri) {
return SERD_BAD_ALLOC;
}
@@ -317,7 +319,7 @@ serd_env_expand_in_place(const SerdEnv* const env,
return SERD_BAD_CURIE;
}
- uri_prefix->data = serd_node_string(prefix->uri);
+ uri_prefix->data = prefix->uri ? serd_node_string(prefix->uri) : "";
uri_prefix->length = prefix->uri ? prefix->uri->length : 0;
uri_suffix->data = colon + 1;
uri_suffix->length = curie.length - name_len - 1;
@@ -338,15 +340,23 @@ serd_env_expand_curie(const SerdEnv* const env, const SerdStringView curie)
return NULL;
}
- const size_t len = prefix.length + suffix.length;
- SerdNode* const ret = serd_node_malloc(env->allocator, len, 0U, SERD_URI);
- if (ret) {
- char* const string = serd_node_buffer(ret);
+ const size_t len = prefix.length + suffix.length;
+ const size_t real_length = serd_node_pad_length(len);
+ const size_t node_size = sizeof(SerdNode) + real_length;
+ SerdNode* node = serd_node_malloc(env->allocator, node_size);
+
+ if (node) {
+ node->length = len;
+ node->flags = 0U;
+ node->type = SERD_URI;
+
+ char* const string = (char*)(node + 1U);
+ assert(prefix.data);
memcpy(string, prefix.data, prefix.length);
memcpy(string + prefix.length, suffix.data, suffix.length);
}
- return ret;
+ return node;
}
SerdNode*
@@ -359,8 +369,9 @@ serd_env_expand_node(const SerdEnv* const env, const SerdNode* const node)
const SerdURIView uri = serd_node_uri_view(node);
const SerdURIView abs_uri = serd_resolve_uri(uri, env->base_uri);
- return abs_uri.scheme.length ? serd_new_parsed_uri(env->allocator, abs_uri)
- : NULL;
+ return abs_uri.scheme.length
+ ? serd_node_new(env->allocator, serd_a_parsed_uri(abs_uri))
+ : NULL;
}
SerdStatus
diff --git a/src/node.c b/src/node.c
index 135ccc22..b4cd14fa 100644
--- a/src/node.c
+++ b/src/node.c
@@ -8,81 +8,142 @@
#include "string_utils.h"
#include "exess/exess.h"
-#include "serd/buffer.h"
#include "serd/node.h"
#include "serd/status.h"
#include "serd/string_view.h"
#include "serd/uri.h"
+#include "serd/value.h"
#include "serd/write_result.h"
#include "zix/attributes.h"
#include <assert.h>
-#include <math.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdlib.h>
#include <string.h>
-typedef struct {
- const void* ZIX_NULLABLE buf;
- size_t len;
-} SerdConstBuffer;
+#ifndef NDEBUG
+# define MUST_SUCCEED(status) assert(!(status))
+#else
+# define MUST_SUCCEED(status) ((void)(status))
+#endif
#define NS_XSD "http://www.w3.org/2001/XMLSchema#"
-typedef struct StaticNode {
- SerdNode node;
- char buf[sizeof(NS_XSD "base64Binary")];
-} StaticNode;
+static const SerdNodeFlags meta_mask = (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE);
-#define DEFINE_XSD_NODE(name) \
- static const StaticNode serd_xsd_##name = { \
- {sizeof(NS_XSD #name) - 1, 0, SERD_URI}, NS_XSD #name};
+static const ExessDatatype value_type_datatypes[] = {
+ EXESS_NOTHING,
+ EXESS_BOOLEAN,
+ EXESS_DOUBLE,
+ EXESS_FLOAT,
+ EXESS_LONG,
+ EXESS_INT,
+ EXESS_SHORT,
+ EXESS_BYTE,
+ EXESS_ULONG,
+ EXESS_UINT,
+ EXESS_USHORT,
+ EXESS_UBYTE,
+};
-DEFINE_XSD_NODE(base64Binary)
-DEFINE_XSD_NODE(boolean)
-DEFINE_XSD_NODE(decimal)
-DEFINE_XSD_NODE(integer)
+// Argument constructors
-static const SerdNodeFlags meta_mask = (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE);
+SerdNodeArgs
+serd_a_token(const SerdNodeType type, const SerdStringView string)
+{
+ const SerdNodeArgs args = {SERD_NODE_ARGS_TOKEN, {{type, string}}};
+ return args;
+}
-static size_t
-string_sink(const void* const buf,
- const size_t size,
- const size_t nmemb,
- void* const stream)
+SerdNodeArgs
+serd_a_parsed_uri(const SerdURIView uri)
{
- char** ptr = (char**)stream;
- memcpy(*ptr, buf, size * nmemb);
- *ptr += size * nmemb;
- return nmemb;
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_PARSED_URI;
+ args.data.as_parsed_uri.uri = uri;
+ return args;
+}
+
+SerdNodeArgs
+serd_a_file_uri(const SerdStringView path, const SerdStringView hostname)
+{
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_FILE_URI;
+ args.data.as_file_uri.path = path;
+ args.data.as_file_uri.hostname = hostname;
+ return args;
}
-ZIX_PURE_FUNC static size_t
-serd_node_pad_length(const size_t n_bytes)
+SerdNodeArgs
+serd_a_literal(const SerdStringView string,
+ const SerdNodeFlags flags,
+ const SerdStringView meta)
{
- const size_t pad = sizeof(SerdNode) - (n_bytes + 2) % sizeof(SerdNode);
- const size_t size = n_bytes + 2 + pad;
- assert(size % sizeof(SerdNode) == 0);
- return size;
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_LITERAL;
+ args.data.as_literal.string = string;
+ args.data.as_literal.flags = flags;
+ args.data.as_literal.meta = meta;
+ return args;
}
-static const SerdNode*
-serd_node_meta_c(const SerdNode* const node)
+SerdNodeArgs
+serd_a_primitive(const SerdValue value)
{
- return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_PRIMITIVE;
+ args.data.as_primitive.value = value;
+ return args;
}
-static SerdNode*
-serd_node_meta(SerdNode* const node)
+SerdNodeArgs
+serd_a_decimal(const double value)
{
- return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_DECIMAL;
+ args.data.as_decimal.value = value;
+ return args;
}
-ZIX_PURE_FUNC static const SerdNode*
-serd_node_maybe_get_meta_c(const SerdNode* const node)
+SerdNodeArgs
+serd_a_integer(const int64_t value)
+{
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_INTEGER;
+ args.data.as_integer.value = value;
+ return args;
+}
+
+SerdNodeArgs
+serd_a_hex(const size_t size, const void* const data)
+{
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_HEX;
+ args.data.as_blob.size = size;
+ args.data.as_blob.data = data;
+ return args;
+}
+
+SerdNodeArgs
+serd_a_base64(size_t size, const void* const data)
+{
+ SerdNodeArgs args;
+ args.type = SERD_NODE_ARGS_BASE64;
+ args.data.as_blob.size = size;
+ args.data.as_blob.data = data;
+ return args;
+}
+
+// Node functions
+
+// Round size up to an even multiple of the node alignment
+static size_t
+serd_node_pad_size(const size_t size)
{
- return (node->flags & meta_mask) ? serd_node_meta_c(node) : NULL;
+ const size_t n_trailing = size % serd_node_align;
+ const size_t n_pad = n_trailing ? (serd_node_align - n_trailing) : 0U;
+
+ return size + n_pad;
}
static void
@@ -96,7 +157,8 @@ serd_node_check_padding(const SerdNode* node)
assert(serd_node_buffer_c(node)[node->length + i] == '\0');
}
- serd_node_check_padding(serd_node_maybe_get_meta_c(node));
+ serd_node_check_padding(serd_node_datatype(node));
+ serd_node_check_padding(serd_node_language(node));
}
#endif
}
@@ -104,32 +166,37 @@ serd_node_check_padding(const SerdNode* node)
size_t
serd_node_total_size(const SerdNode* const node)
{
- return node ? (sizeof(SerdNode) + serd_node_pad_length(node->length) +
- serd_node_total_size(serd_node_maybe_get_meta_c(node)))
- : 0;
+ const size_t real_length = serd_node_pad_length(node->length);
+ const size_t base_size = sizeof(SerdNode) + real_length;
+
+ if (!(node->flags & meta_mask)) {
+ return base_size;
+ }
+
+ const SerdNode* const meta = serd_node_meta_c(node);
+ const size_t meta_real_length = serd_node_pad_length(meta->length);
+
+ return base_size + sizeof(SerdNode) + meta_real_length;
}
SerdNode*
-serd_node_malloc(SerdAllocator* const allocator,
- const size_t length,
- const SerdNodeFlags flags,
- const SerdNodeType type)
+serd_node_malloc(SerdAllocator* const allocator, const size_t size)
{
- const size_t size = sizeof(SerdNode) + serd_node_pad_length(length);
-
- SerdNode* const node =
- (SerdNode*)serd_aaligned_calloc(allocator, serd_node_align, size);
-
- if (node) {
- node->length = 0;
- node->flags = flags;
- node->type = type;
- }
+ SerdNode* const node = (SerdNode*)serd_aaligned_calloc(
+ allocator, serd_node_align, serd_node_pad_size(size));
assert((uintptr_t)node % serd_node_align == 0U);
return node;
}
+SerdNode*
+serd_node_try_malloc(SerdAllocator* const allocator, const SerdWriteResult r)
+{
+ return (r.status && r.status != SERD_OVERFLOW)
+ ? NULL
+ : serd_node_malloc(allocator, r.count);
+}
+
SerdStatus
serd_node_set(SerdAllocator* const allocator,
SerdNode** const dst,
@@ -179,44 +246,31 @@ result(const SerdStatus status, const size_t count)
return result;
}
-SerdNode*
-serd_new_token(SerdAllocator* const allocator,
- const SerdNodeType type,
- const SerdStringView str)
-{
- SerdNodeFlags flags = 0U;
- const size_t length = str.data ? str.length : 0U;
- SerdNode* node = serd_node_malloc(allocator, length, flags, type);
-
- if (node) {
- if (str.data) {
- memcpy(serd_node_buffer(node), str.data, length);
- }
-
- node->length = length;
+static SerdWriteResult
+serd_node_construct_simple(const size_t buf_size,
+ void* const buf,
+ const SerdNodeType type,
+ const SerdNodeFlags flags,
+ const SerdStringView string)
+{
+ const size_t total_size =
+ sizeof(SerdNode) + serd_node_pad_length(string.length);
+ if (!buf || total_size > buf_size) {
+ return result(SERD_OVERFLOW, total_size);
}
- serd_node_check_padding(node);
+ SerdNode* const node = (SerdNode*)buf;
- return node;
-}
-
-SerdNode*
-serd_new_string(SerdAllocator* const allocator, const SerdStringView str)
-{
- SerdNodeFlags flags = 0U;
- SerdNode* node = serd_node_malloc(allocator, str.length, flags, SERD_LITERAL);
-
- if (node) {
- if (str.data && str.length) {
- memcpy(serd_node_buffer(node), str.data, str.length);
- }
+ node->length = string.length;
+ node->flags = flags;
+ node->type = type;
- node->length = str.length;
- serd_node_check_padding(node);
+ if (string.data) {
+ memcpy(serd_node_buffer(node), string.data, string.length);
}
- return node;
+ serd_node_zero_pad(node);
+ return result(SERD_SUCCESS, total_size);
}
ZIX_PURE_FUNC static bool
@@ -248,165 +302,427 @@ is_langtag(const SerdStringView string)
return true;
}
-SerdNode*
-serd_new_literal(SerdAllocator* const allocator,
- const SerdStringView string,
- const SerdNodeFlags flags,
- const SerdStringView meta)
+static SerdWriteResult
+serd_node_construct_literal(const size_t buf_size,
+ void* const buf,
+ const SerdStringView string,
+ const SerdNodeFlags flags,
+ const SerdStringView meta)
{
if (!(flags & (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE))) {
- SerdNode* node =
- serd_node_malloc(allocator, string.length, flags, SERD_LITERAL);
-
- memcpy(serd_node_buffer(node), string.data, string.length);
- node->length = string.length;
- serd_node_check_padding(node);
- return node;
+ return serd_node_construct_simple(
+ buf_size, buf, SERD_LITERAL, flags, string);
}
if ((flags & SERD_HAS_DATATYPE) && (flags & SERD_HAS_LANGUAGE)) {
- return NULL;
+ return result(SERD_BAD_ARG, 0);
}
if (!meta.length) {
- return NULL;
+ return result(SERD_BAD_ARG, 0);
}
if (((flags & SERD_HAS_DATATYPE) &&
(!serd_uri_string_has_scheme(meta.data) ||
!strcmp(meta.data, NS_RDF "langString"))) ||
((flags & SERD_HAS_LANGUAGE) && !is_langtag(meta))) {
- return NULL;
+ return result(SERD_BAD_ARG, 0);
+ }
+
+ // Calculate total node size
+ const size_t padded_len = serd_node_pad_length(string.length);
+ const size_t meta_size = sizeof(SerdNode) + serd_node_pad_length(meta.length);
+ const size_t total_size = sizeof(SerdNode) + padded_len + meta_size;
+ if (!buf || total_size > buf_size) {
+ return result(SERD_OVERFLOW, total_size);
}
- const size_t len = serd_node_pad_length(string.length);
- const size_t meta_len = serd_node_pad_length(meta.length);
- const size_t meta_size = sizeof(SerdNode) + meta_len;
+ // Write node header
+ SerdNode* const node = (SerdNode*)buf;
+ node->length = string.length;
+ node->flags = flags;
+ node->type = SERD_LITERAL;
- SerdNode* node =
- serd_node_malloc(allocator, len + meta_size, flags, SERD_LITERAL);
+ // Copy string to node body
memcpy(serd_node_buffer(node), string.data, string.length);
- node->length = string.length;
- SerdNode* meta_node = node + 1U + (len / sizeof(SerdNode));
- meta_node->length = meta.length;
+ // Append datatype or language
+ SerdNode* meta_node = node + 1 + (padded_len / sizeof(SerdNode));
meta_node->type = (flags & SERD_HAS_DATATYPE) ? SERD_URI : SERD_LITERAL;
+ meta_node->length = meta.length;
memcpy(serd_node_buffer(meta_node), meta.data, meta.length);
- serd_node_check_padding(meta_node);
- serd_node_check_padding(node);
- return node;
+ serd_node_zero_pad(node);
+ return result(SERD_SUCCESS, total_size);
+}
+
+static ExessDatatype
+value_type_datatype(const SerdValueType value_type)
+{
+ return (value_type > SERD_UBYTE) ? EXESS_NOTHING
+ : value_type_datatypes[value_type];
+}
+
+static const char*
+value_type_uri(const SerdValueType value_type)
+{
+ return exess_datatype_uri(value_type_datatype(value_type));
+}
+
+static inline SerdValueType
+datatype_value_type(const ExessDatatype datatype)
+{
+ switch (datatype) {
+ case EXESS_NOTHING:
+ return SERD_NOTHING;
+ case EXESS_BOOLEAN:
+ return SERD_BOOL;
+ case EXESS_DECIMAL:
+ case EXESS_DOUBLE:
+ return SERD_DOUBLE;
+ case EXESS_FLOAT:
+ return SERD_FLOAT;
+ case EXESS_INTEGER:
+ case EXESS_NON_POSITIVE_INTEGER:
+ case EXESS_NEGATIVE_INTEGER:
+ case EXESS_LONG:
+ return SERD_LONG;
+ case EXESS_INT:
+ return SERD_INT;
+ case EXESS_SHORT:
+ return SERD_SHORT;
+ case EXESS_BYTE:
+ return SERD_BYTE;
+ case EXESS_NON_NEGATIVE_INTEGER:
+ case EXESS_ULONG:
+ return SERD_ULONG;
+ case EXESS_UINT:
+ return SERD_UINT;
+ case EXESS_USHORT:
+ return SERD_USHORT;
+ case EXESS_UBYTE:
+ return SERD_UBYTE;
+ case EXESS_POSITIVE_INTEGER:
+ return SERD_ULONG;
+
+ case EXESS_DURATION:
+ case EXESS_DATETIME:
+ case EXESS_TIME:
+ case EXESS_DATE:
+ case EXESS_HEX:
+ case EXESS_BASE64:
+ break;
+ }
+
+ return SERD_NOTHING;
}
-SerdNode*
-serd_new_blank(SerdAllocator* const allocator, const SerdStringView str)
-{
- return serd_new_token(allocator, SERD_BLANK, str);
+static SerdWriteResult
+serd_node_construct_value(const size_t buf_size,
+ void* const buf,
+ const SerdValue value)
+{
+ char temp[EXESS_MAX_DOUBLE_LENGTH + 1] = {0};
+ ExessResult r = {EXESS_UNSUPPORTED, 0U};
+ switch (value.type) {
+ case SERD_NOTHING:
+ return result(SERD_BAD_ARG, 0U);
+ case SERD_BOOL:
+ r = exess_write_boolean(value.data.as_bool, sizeof(temp), temp);
+ break;
+ case SERD_DOUBLE:
+ r = exess_write_double(value.data.as_double, sizeof(temp), temp);
+ break;
+ case SERD_FLOAT:
+ r = exess_write_float(value.data.as_float, sizeof(temp), temp);
+ break;
+ case SERD_LONG:
+ r = exess_write_long(value.data.as_long, sizeof(temp), temp);
+ break;
+ case SERD_INT:
+ r = exess_write_int(value.data.as_int, sizeof(temp), temp);
+ break;
+ case SERD_SHORT:
+ r = exess_write_short(value.data.as_short, sizeof(temp), temp);
+ break;
+ case SERD_BYTE:
+ r = exess_write_byte(value.data.as_byte, sizeof(temp), temp);
+ break;
+ case SERD_ULONG:
+ r = exess_write_ulong(value.data.as_ulong, sizeof(temp), temp);
+ break;
+ case SERD_UINT:
+ r = exess_write_uint(value.data.as_uint, sizeof(temp), temp);
+ break;
+ case SERD_USHORT:
+ r = exess_write_ushort(value.data.as_ushort, sizeof(temp), temp);
+ break;
+ case SERD_UBYTE:
+ r = exess_write_ubyte(value.data.as_ubyte, sizeof(temp), temp);
+ break;
+ }
+
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
+
+ const char* const datatype_uri = value_type_uri(value.type);
+ assert(datatype_uri);
+
+ return serd_node_construct_literal(buf_size,
+ buf,
+ serd_substring(temp, r.count),
+ SERD_HAS_DATATYPE,
+ serd_string(datatype_uri));
}
-ExessResult
-serd_node_get_value_as(const SerdNode* const node,
- const ExessDatatype value_type,
- const size_t value_size,
- void* const value)
+static SerdWriteResult
+serd_node_construct_decimal(const size_t buf_size,
+ void* const buf,
+ const double value)
{
- const SerdNode* const datatype_node = serd_node_datatype(node);
+ char temp[EXESS_MAX_DECIMAL_LENGTH + 1] = {0};
- const ExessDatatype node_type =
- datatype_node ? exess_datatype_from_uri(serd_node_string(datatype_node))
- : EXESS_NOTHING;
+ const ExessResult r = exess_write_decimal(value, sizeof(temp), temp);
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
+
+ return serd_node_construct_literal(buf_size,
+ buf,
+ serd_substring(temp, r.count),
+ SERD_HAS_DATATYPE,
+ serd_string(EXESS_XSD_URI "decimal"));
+}
- if (node_type == EXESS_NOTHING ||
- (node_type == EXESS_HEX && value_type == EXESS_BASE64) ||
- (node_type == EXESS_BASE64 && value_type == EXESS_HEX)) {
- // Try to read the large or untyped node string directly into the result
- const ExessVariableResult vr =
- exess_read_value(value_type, value_size, value, serd_node_string(node));
+static SerdWriteResult
+serd_node_construct_integer(const size_t buf_size,
+ void* const buf,
+ const int64_t value)
+{
+ char temp[24] = {0};
+ const ExessResult r = exess_write_long(value, sizeof(temp), temp);
+ MUST_SUCCEED(r.status); // The only error is buffer overrun
- const ExessResult r = {vr.status, vr.write_count};
- return r;
+ return serd_node_construct_literal(buf_size,
+ buf,
+ serd_substring(temp, r.count),
+ SERD_HAS_DATATYPE,
+ serd_string(NS_XSD "integer"));
+}
+
+static SerdWriteResult
+serd_node_construct_binary(
+ const size_t buf_size,
+ void* const buf,
+ const size_t value_size,
+ const void* const value,
+ const SerdStringView datatype_uri,
+ ExessResult (*write_func)(size_t, const void*, size_t, char*))
+{
+ // Verify argument sanity
+ if (!value || !value_size) {
+ return result(SERD_BAD_ARG, 0);
}
- // Read the (smallish) value from the node
- ExessValue node_value = {false};
- const ExessVariableResult vr = exess_read_value(
- node_type, sizeof(node_value), &node_value, serd_node_string(node));
+ // Find the size required for the datatype
+ const size_t type_length = serd_node_pad_length(datatype_uri.length);
+ const size_t type_size = sizeof(SerdNode) + type_length;
- if (vr.status) {
- const ExessResult r = {vr.status, 0U};
- return r;
+ // Find the length of the encoded string (just an O(1) arithmetic expression)
+ ExessResult r = write_func(value_size, value, 0, NULL);
+
+ // Check that the provided buffer is large enough
+ const size_t padded_length = serd_node_pad_length(r.count);
+ const size_t total_size = sizeof(SerdNode) + padded_length + type_size;
+ if (!buf || total_size > buf_size) {
+ return result(SERD_OVERFLOW, total_size);
}
- // Coerce value to the desired type if possible
- return exess_value_coerce(EXESS_REDUCE_PRECISION,
- node_type,
- vr.write_count,
- &node_value,
- value_type,
- value_size,
- value);
+ // Write node header
+ SerdNode* const node = (SerdNode*)buf;
+ node->length = r.count;
+ node->flags = SERD_HAS_DATATYPE;
+ node->type = SERD_LITERAL;
+
+ // Write the encoded string into the node body
+ r = write_func(
+ value_size, value, total_size - sizeof(SerdNode), serd_node_buffer(node));
+
+ MUST_SUCCEED(r.status);
+ (void)r;
+
+ // Append datatype
+ SerdNode* meta_node = node + 1 + (padded_length / sizeof(SerdNode));
+ meta_node->length = datatype_uri.length;
+ meta_node->flags = 0U;
+ meta_node->type = SERD_URI;
+ memcpy(serd_node_buffer(meta_node), datatype_uri.data, datatype_uri.length);
+
+ return result(SERD_SUCCESS, total_size);
}
-bool
-serd_get_boolean(const SerdNode* const node)
+static size_t
+string_sink(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
- assert(node);
+ char** ptr = (char**)stream;
+ memcpy(*ptr, buf, size * nmemb);
+ *ptr += size * nmemb;
+ return nmemb;
+}
- bool value = false;
- serd_node_get_value_as(node, EXESS_BOOLEAN, sizeof(value), &value);
+static SerdWriteResult
+serd_node_construct_uri(const size_t buf_size,
+ void* const buf,
+ const SerdURIView uri)
+{
+ const size_t length = serd_uri_string_length(uri);
+ const size_t required_size = sizeof(SerdNode) + serd_node_pad_length(length);
+ if (!buf || buf_size < required_size) {
+ return result(SERD_OVERFLOW, required_size);
+ }
+
+ // Write node header
+ SerdNode* const node = (SerdNode*)buf;
+ node->length = length;
+ node->flags = 0U;
+ node->type = SERD_URI;
- return value;
+ // Serialise URI to node body
+ char* ptr = serd_node_buffer(node);
+ const size_t actual_length = serd_write_uri(uri, string_sink, &ptr);
+ assert(actual_length == length);
+
+ serd_node_buffer(node)[actual_length] = '\0';
+ serd_node_check_padding(node);
+ return result(SERD_SUCCESS, required_size);
}
-double
-serd_get_double(const SerdNode* const node)
+SerdNode*
+serd_node_new(SerdAllocator* const allocator, const SerdNodeArgs args)
{
- assert(node);
+ SerdWriteResult r = serd_node_construct(0, NULL, args);
+ if (r.status != SERD_OVERFLOW) {
+ return NULL;
+ }
- double value = (double)NAN; // NOLINT(google-readability-casting)
- serd_node_get_value_as(node, EXESS_DOUBLE, sizeof(value), &value);
+ assert(r.count % sizeof(SerdNode) == 0);
- return value;
+ SerdNode* const node =
+ serd_node_malloc(allocator, sizeof(SerdNode) + r.count + 1);
+
+ if (node) {
+ r = serd_node_construct(r.count, node, args);
+ MUST_SUCCEED(r.status); // Any error should have been reported above
+ }
+
+ return node;
}
-float
-serd_get_float(const SerdNode* const node)
+SerdValue
+serd_node_value(const SerdNode* const node)
{
assert(node);
- float value = (float)NAN; // NOLINT(google-readability-casting)
- serd_node_get_value_as(node, EXESS_FLOAT, sizeof(value), &value);
+ const SerdNode* const datatype_node = serd_node_datatype(node);
+
+ const ExessDatatype datatype =
+ datatype_node ? exess_datatype_from_uri(serd_node_string(datatype_node))
+ : EXESS_NOTHING;
+
+ const SerdValueType value_type = datatype_value_type(datatype);
+ if (value_type == SERD_NOTHING) {
+ return serd_nothing();
+ }
+
+ ExessValue value = {false};
+ const ExessVariableResult vr =
+ exess_read_value(datatype, sizeof(value), &value, serd_node_string(node));
- return value;
+ if (vr.status) {
+ return serd_nothing();
+ }
+
+ SerdValue result = {value_type, {false}};
+ memcpy(&result.data, &value, vr.write_count);
+
+ return result;
}
-int64_t
-serd_get_integer(const SerdNode* const node)
+SerdValue
+serd_node_value_as(const SerdNode* const node,
+ const SerdValueType type,
+ const bool lossy)
{
- assert(node);
+ // Get the value as it is
+ const SerdValue value = serd_node_value(node);
+ if (!value.type || value.type == type) {
+ return value;
+ }
- int64_t value = 0;
- serd_node_get_value_as(node, EXESS_LONG, sizeof(value), &value);
+ const ExessCoercions coercions =
+ lossy ? (EXESS_REDUCE_PRECISION | EXESS_ROUND | EXESS_TRUNCATE)
+ : EXESS_LOSSLESS;
+
+ const ExessDatatype node_datatype = value_type_datatype(value.type);
+ const ExessDatatype datatype = value_type_datatype(type);
+ SerdValue result = {type, {false}};
+
+ // Coerce to the desired type
+ const ExessResult r = exess_value_coerce(coercions,
+ node_datatype,
+ exess_value_size(node_datatype),
+ &value.data,
+ datatype,
+ exess_value_size(datatype),
+ &result.data);
+
+ if (r.status) {
+ result.type = SERD_NOTHING;
+ }
- return value;
+ return result;
}
size_t
-serd_get_base64_size(const SerdNode* const node)
+serd_node_decoded_size(const SerdNode* const node)
{
- return exess_base64_decoded_size(serd_node_length(node));
+ const SerdNode* const datatype = serd_node_datatype(node);
+ if (!datatype) {
+ return 0U;
+ }
+
+ if (!strcmp(serd_node_string(datatype), NS_XSD "hexBinary")) {
+ return exess_hex_decoded_size(serd_node_length(node));
+ }
+
+ if (!strcmp(serd_node_string(datatype), NS_XSD "base64Binary")) {
+ return exess_base64_decoded_size(serd_node_length(node));
+ }
+
+ return 0U;
}
SerdWriteResult
-serd_get_base64(const SerdNode* const node,
- const size_t buf_size,
- void* const buf)
+serd_node_decode(const SerdNode* const node,
+ const size_t buf_size,
+ void* const buf)
{
- const size_t max_size = serd_get_base64_size(node);
- const ExessVariableResult r =
- exess_read_base64(buf_size, buf, serd_node_string(node));
+ const SerdNode* const datatype = serd_node_datatype(node);
+ if (!datatype) {
+ return result(SERD_BAD_ARG, 0U);
+ }
+
+ ExessVariableResult r = {EXESS_UNSUPPORTED, 0U, 0U};
- return r.status == EXESS_NO_SPACE ? result(SERD_OVERFLOW, max_size)
+ if (!strcmp(serd_node_string(datatype), NS_XSD "hexBinary")) {
+ r = exess_read_hex(buf_size, buf, serd_node_string(node));
+ } else if (!strcmp(serd_node_string(datatype), NS_XSD "base64Binary")) {
+ r = exess_read_base64(buf_size, buf, serd_node_string(node));
+ } else {
+ return result(SERD_BAD_ARG, 0U);
+ }
+
+ return r.status == EXESS_NO_SPACE ? result(SERD_OVERFLOW, r.write_count)
: r.status ? result(SERD_BAD_SYNTAX, 0U)
: result(SERD_SUCCESS, r.write_count);
}
@@ -485,197 +801,120 @@ serd_node_compare(const SerdNode* const a, const SerdNode* const b)
return strcmp(serd_node_string_i(ma), serd_node_string_i(mb));
}
-SerdNode*
-serd_new_uri(SerdAllocator* const allocator, const SerdStringView string)
-{
- return serd_new_token(allocator, SERD_URI, string);
-}
+typedef struct {
+ char* buf;
+ size_t len;
+ size_t offset;
+} ConstructWriteHead;
-SerdNode*
-serd_new_parsed_uri(SerdAllocator* const allocator, const SerdURIView uri)
+static size_t
+construct_write(const void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
{
- const size_t len = serd_uri_string_length(uri);
- SerdNode* const node = serd_node_malloc(allocator, len, 0, SERD_URI);
-
- if (node) {
- char* ptr = serd_node_buffer(node);
- const size_t actual_len = serd_write_uri(uri, string_sink, &ptr);
-
- assert(actual_len == len);
+ const size_t n_bytes = size * nmemb;
+ ConstructWriteHead* const head = (ConstructWriteHead*)stream;
- serd_node_buffer(node)[actual_len] = '\0';
- node->length = actual_len;
+ if (head->buf && head->offset + n_bytes <= head->len) {
+ memcpy(head->buf + head->offset, buf, n_bytes);
}
- serd_node_check_padding(node);
- return node;
-}
-
-SerdNode*
-serd_new_file_uri(SerdAllocator* const allocator,
- const SerdStringView path,
- const SerdStringView hostname)
-{
- SerdBuffer buffer = {NULL, NULL, 0U};
-
- serd_write_file_uri(path, hostname, serd_buffer_write, &buffer);
- serd_buffer_close(&buffer);
-
- const size_t length = buffer.len;
- const char* const string = (char*)buffer.buf;
- SerdNode* const node =
- serd_new_string(allocator, serd_substring(string, length));
-
- free(buffer.buf);
- serd_node_check_padding(node);
- return node;
+ head->offset += n_bytes;
+ return n_bytes;
}
-typedef size_t (*SerdWriteLiteralFunc)(const void* user_data,
- size_t buf_size,
- char* buf);
-
-static SerdNode*
-serd_new_custom_literal(SerdAllocator* const allocator,
- const void* const user_data,
- const size_t len,
- const SerdWriteLiteralFunc write,
- const SerdNode* const datatype)
-{
- if (len == 0 || !write) {
- return NULL;
+static SerdWriteResult
+serd_node_construct_file_uri(const size_t buf_size,
+ void* const buf,
+ const SerdStringView path,
+ const SerdStringView hostname)
+{
+ SerdNode* const node = (SerdNode*)buf;
+ ConstructWriteHead head = {(char*)buf, buf_size, 0U};
+ size_t count = 0U;
+
+ // Write node header
+ SerdNode header = {0U, 0U, SERD_URI};
+ count += construct_write(&header, sizeof(header), 1, &head);
+
+ // Write URI string node body
+ const size_t length =
+ serd_write_file_uri(path, hostname, construct_write, &head);
+
+ // Terminate string and pad with at least 1 additional null byte
+ const size_t padded_length = serd_node_pad_length(length);
+ count += length;
+ for (size_t p = 0U; p < padded_length - length; ++p) {
+ count += construct_write("", 1, 1, &head);
}
- const size_t datatype_size = serd_node_total_size(datatype);
- const size_t total_size = serd_node_pad_length(len) + datatype_size;
-
- SerdNode* const node = serd_node_malloc(
- allocator, total_size, datatype ? SERD_HAS_DATATYPE : 0U, SERD_LITERAL);
-
- node->length = write(user_data, len + 1, serd_node_buffer(node));
-
- if (datatype) {
- memcpy(serd_node_meta(node), datatype, datatype_size);
+ if (!buf || count > buf_size) {
+ return result(SERD_OVERFLOW, count);
}
- return node;
-}
-
-SerdNode*
-serd_new_double(SerdAllocator* const allocator, const double d)
-{
- char buf[EXESS_MAX_DOUBLE_LENGTH + 1] = {0};
-
- const ExessResult r = exess_write_double(d, sizeof(buf), buf);
-
- return r.status ? NULL
- : serd_new_literal(allocator,
- serd_substring(buf, r.count),
- SERD_HAS_DATATYPE,
- serd_string(EXESS_XSD_URI "double"));
-}
-
-SerdNode*
-serd_new_float(SerdAllocator* const allocator, const float f)
-{
- char buf[EXESS_MAX_FLOAT_LENGTH + 1] = {0};
-
- const ExessResult r = exess_write_float(f, sizeof(buf), buf);
+ node->length = length;
+ assert(node->length == strlen(serd_node_string(node)));
- return r.status ? NULL
- : serd_new_literal(allocator,
- serd_substring(buf, r.count),
- SERD_HAS_DATATYPE,
- serd_string(EXESS_XSD_URI "float"));
+ return result(SERD_SUCCESS, count);
}
-SerdNode*
-serd_new_boolean(SerdAllocator* const allocator, bool b)
-{
- return serd_new_literal(allocator,
- b ? serd_string("true") : serd_string("false"),
- SERD_HAS_DATATYPE,
- serd_node_string_view(&serd_xsd_boolean.node));
-}
-
-SerdNode*
-serd_new_decimal(SerdAllocator* const allocator,
- const double d,
- const SerdNode* const datatype)
-{
- // Use given datatype, or xsd:decimal as a default if it is null
- const SerdNode* type = datatype ? datatype : &serd_xsd_decimal.node;
- const size_t type_size = serd_node_total_size(type);
-
- // Measure integer string to know how much space the node will need
- ExessResult r = exess_write_decimal(d, 0, NULL);
- assert(!r.status);
-
- // Allocate node with enough space for value and datatype URI
- SerdNode* const node =
- serd_node_malloc(allocator,
- serd_node_pad_length(r.count) + type_size,
- SERD_HAS_DATATYPE,
- SERD_LITERAL);
-
- // Write string directly into node
- r = exess_write_decimal(d, r.count + 1, serd_node_buffer(node));
- assert(!r.status);
-
- node->length = r.count;
- memcpy(serd_node_meta(node), type, type_size);
- serd_node_check_padding(node);
- return node;
-}
-
-SerdNode*
-serd_new_integer(SerdAllocator* const allocator, const int64_t i)
-{
- // Use given datatype, or xsd:integer as a default if it is null
- const SerdNode* datatype = &serd_xsd_integer.node;
- const size_t datatype_size = serd_node_total_size(datatype);
-
- // Measure integer string to know how much space the node will need
- ExessResult r = exess_write_long(i, 0, NULL);
- assert(!r.status);
-
- // Allocate node with enough space for value and datatype URI
- SerdNode* const node =
- serd_node_malloc(allocator,
- serd_node_pad_length(r.count) + datatype_size,
- SERD_HAS_DATATYPE,
- SERD_LITERAL);
-
- // Write string directly into node
- r = exess_write_long(i, r.count + 1U, serd_node_buffer(node));
- assert(!r.status);
-
- node->length = r.count;
- memcpy(serd_node_meta(node), datatype, datatype_size);
- serd_node_check_padding(node);
- return node;
-}
-
-static size_t
-write_base64_literal(const void* const user_data,
- const size_t buf_size,
- char* const buf)
-{
- const SerdConstBuffer blob = *(const SerdConstBuffer*)user_data;
-
- const ExessResult r = exess_write_base64(blob.len, blob.buf, buf_size, buf);
-
- return r.status ? 0 : r.count;
-}
-
-SerdNode*
-serd_new_base64(SerdAllocator* const allocator, const void* buf, size_t size)
-{
- const size_t len = exess_write_base64(size, buf, 0, NULL).count;
- SerdConstBuffer blob = {buf, size};
+SerdWriteResult
+serd_node_construct(const size_t buf_size,
+ void* const buf,
+ const SerdNodeArgs args)
+{
+ switch (args.type) {
+ case SERD_NODE_ARGS_TOKEN:
+ return serd_node_construct_simple(
+ buf_size, buf, args.data.as_token.type, 0U, args.data.as_token.string);
+
+ case SERD_NODE_ARGS_PARSED_URI:
+ return serd_node_construct_uri(buf_size, buf, args.data.as_parsed_uri.uri);
+
+ case SERD_NODE_ARGS_FILE_URI:
+ return serd_node_construct_file_uri(buf_size,
+ buf,
+ args.data.as_file_uri.path,
+ args.data.as_file_uri.hostname);
+
+ case SERD_NODE_ARGS_LITERAL:
+ return serd_node_construct_literal(buf_size,
+ buf,
+ args.data.as_literal.string,
+ args.data.as_literal.flags,
+ args.data.as_literal.meta);
+
+ case SERD_NODE_ARGS_PRIMITIVE:
+ return serd_node_construct_value(
+ buf_size, buf, args.data.as_primitive.value);
+
+ case SERD_NODE_ARGS_DECIMAL:
+ return serd_node_construct_decimal(
+ buf_size, buf, args.data.as_decimal.value);
+
+ case SERD_NODE_ARGS_INTEGER:
+ return serd_node_construct_integer(
+ buf_size, buf, args.data.as_integer.value);
+
+ case SERD_NODE_ARGS_HEX:
+ return serd_node_construct_binary(buf_size,
+ buf,
+ args.data.as_blob.size,
+ args.data.as_blob.data,
+ serd_string(NS_XSD "hexBinary"),
+ exess_write_hex);
+
+ case SERD_NODE_ARGS_BASE64:
+ return serd_node_construct_binary(buf_size,
+ buf,
+ args.data.as_blob.size,
+ args.data.as_blob.data,
+ serd_string(NS_XSD "base64Binary"),
+ exess_write_base64);
+ }
- return serd_new_custom_literal(
- allocator, &blob, len, write_base64_literal, &serd_xsd_base64Binary.node);
+ return result(SERD_BAD_ARG, 0U);
}
SerdNodeType
@@ -760,3 +999,5 @@ serd_node_free(SerdAllocator* const allocator, SerdNode* const node)
{
serd_aaligned_free(allocator, node);
}
+
+#undef MUST_SUCCEED
diff --git a/src/node.h b/src/node.h
index 43368367..0dd15d0c 100644
--- a/src/node.h
+++ b/src/node.h
@@ -4,12 +4,13 @@
#ifndef SERD_SRC_NODE_H
#define SERD_SRC_NODE_H
-#include "exess/exess.h"
#include "serd/memory.h"
#include "serd/node.h"
#include "serd/status.h"
+#include "serd/write_result.h"
#include "zix/attributes.h"
+#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -22,19 +23,57 @@ struct SerdNodeImpl {
static const size_t serd_node_align = 2 * sizeof(uint64_t);
-static inline char* ZIX_NONNULL
+#if SIZE_MAX == UINT64_MAX
+
+static inline size_t
+serd_node_pad_length(const size_t n_bytes)
+{
+ const size_t align = sizeof(SerdNode);
+
+ assert((align & (align - 1U)) == 0U);
+
+ return (n_bytes + align + 2U) & ~(align - 1U);
+}
+
+#else
+
+static inline size_t
+serd_node_pad_length(const size_t n_bytes)
+{
+ const size_t pad = sizeof(SerdNode) - (n_bytes + 2) % sizeof(SerdNode);
+ const size_t size = n_bytes + 2 + pad;
+ assert(size % sizeof(SerdNode) == 0);
+ return size;
+}
+
+#endif
+
+ZIX_CONST_FUNC static inline char* ZIX_NONNULL
serd_node_buffer(SerdNode* ZIX_NONNULL node)
{
return (char*)(node + 1);
}
-static inline const char* ZIX_NONNULL
+ZIX_PURE_FUNC static inline const char* ZIX_NONNULL
serd_node_buffer_c(const SerdNode* ZIX_NONNULL node)
{
return (const char*)(node + 1);
}
-static inline const char* ZIX_NONNULL
+ZIX_PURE_FUNC static inline SerdNode* ZIX_NONNULL
+serd_node_meta(SerdNode* const ZIX_NONNULL node)
+{
+ return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
+}
+
+ZIX_PURE_FUNC static inline const SerdNode* ZIX_NONNULL
+serd_node_meta_c(const SerdNode* const ZIX_NONNULL node)
+{
+ assert(node->flags & (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE));
+ return node + 1 + (serd_node_pad_length(node->length) / sizeof(SerdNode));
+}
+
+ZIX_CONST_FUNC static inline const char* ZIX_NONNULL
serd_node_string_i(const SerdNode* const ZIX_NONNULL node)
{
return (const char*)(node + 1);
@@ -47,11 +86,12 @@ serd_node_pattern_match(const SerdNode* ZIX_NULLABLE a,
return !a || !b || serd_node_equals(a, b);
}
-SerdNode* ZIX_ALLOCATED
-serd_node_malloc(SerdAllocator* ZIX_NULLABLE allocator,
- size_t length,
- SerdNodeFlags flags,
- SerdNodeType type);
+ZIX_MALLOC_FUNC SerdNode* ZIX_ALLOCATED
+serd_node_malloc(SerdAllocator* ZIX_NULLABLE allocator, size_t size);
+
+ZIX_MALLOC_FUNC SerdNode* ZIX_ALLOCATED
+serd_node_try_malloc(SerdAllocator* ZIX_NULLABLE allocator,
+ SerdWriteResult result);
SerdStatus
serd_node_set(SerdAllocator* ZIX_NULLABLE allocator,
@@ -59,15 +99,9 @@ serd_node_set(SerdAllocator* ZIX_NULLABLE allocator,
const SerdNode* ZIX_NONNULL src);
ZIX_PURE_FUNC size_t
-serd_node_total_size(const SerdNode* ZIX_NULLABLE node);
+serd_node_total_size(const SerdNode* ZIX_NONNULL node);
void
serd_node_zero_pad(SerdNode* ZIX_NONNULL node);
-ExessResult
-serd_node_get_value_as(const SerdNode* ZIX_NONNULL node,
- ExessDatatype value_type,
- size_t value_size,
- void* ZIX_NONNULL value);
-
#endif // SERD_SRC_NODE_H
diff --git a/src/read_turtle.c b/src/read_turtle.c
index 613b33d2..f85c956a 100644
--- a/src/read_turtle.c
+++ b/src/read_turtle.c
@@ -348,7 +348,7 @@ resolve_IRIREF(SerdReader* const reader,
temp->length = serd_write_uri(uri, write_to_stack, &ctx);
if (!ctx.status) {
// Replace the destination with the new expanded node
- memmove(dest, temp, serd_node_total_size(temp));
+ memmove(dest, temp, sizeof(SerdNode) + serd_node_pad_length(temp->length));
serd_stack_pop_to(&reader->stack, string_start_offset + dest->length);
}
diff --git a/src/value.c b/src/value.c
new file mode 100644
index 00000000..ab6b1b43
--- /dev/null
+++ b/src/value.c
@@ -0,0 +1,101 @@
+// Copyright 2022 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "serd/value.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+SerdValue
+serd_nothing(void)
+{
+ static const SerdValue value = {SERD_NOTHING, {0}};
+ return value;
+}
+
+SerdValue
+serd_bool(const bool v)
+{
+ const SerdValue value = {SERD_BOOL, {v}};
+ return value;
+}
+
+SerdValue
+serd_double(const double v)
+{
+ SerdValue value = {SERD_DOUBLE, {0}};
+ value.data.as_double = v;
+ return value;
+}
+
+SerdValue
+serd_float(const float v)
+{
+ SerdValue value = {SERD_FLOAT, {0}};
+ value.data.as_float = v;
+ return value;
+}
+
+SerdValue
+serd_long(const int64_t v)
+{
+ SerdValue value = {SERD_LONG, {0}};
+ value.data.as_long = v;
+ return value;
+}
+
+SerdValue
+serd_int(const int32_t v)
+{
+ SerdValue value = {SERD_INT, {0}};
+ value.data.as_int = v;
+ return value;
+}
+
+SerdValue
+serd_short(const int16_t v)
+{
+ SerdValue value = {SERD_SHORT, {0}};
+ value.data.as_short = v;
+ return value;
+}
+
+SerdValue
+serd_byte(const int8_t v)
+{
+ SerdValue value = {SERD_BYTE, {0}};
+ value.data.as_byte = v;
+ return value;
+}
+
+SerdValue
+serd_ulong(const uint64_t v)
+{
+ SerdValue value = {SERD_ULONG, {0}};
+ value.data.as_ulong = v;
+ return value;
+}
+
+SerdValue
+serd_uint(const uint32_t v)
+{
+ SerdValue value = {SERD_UINT, {0}};
+ value.data.as_uint = v;
+ return value;
+}
+
+SerdValue
+serd_ushort(const uint16_t v)
+{
+ SerdValue value = {SERD_USHORT, {0}};
+ value.data.as_ushort = v;
+ return value;
+}
+
+SerdValue
+serd_ubyte(const uint8_t v)
+{
+ SerdValue value = {SERD_UBYTE, {0}};
+ value.data.as_ubyte = v;
+ return value;
+}
diff --git a/src/world.c b/src/world.c
index 2c563f15..406956b1 100644
--- a/src/world.c
+++ b/src/world.c
@@ -9,7 +9,6 @@
#include "serd/node.h"
#include "serd/status.h"
-#include "serd/string_view.h"
#include "serd/world.h"
#include <assert.h>
@@ -23,7 +22,8 @@ serd_world_new(SerdAllocator* const allocator)
allocator ? allocator : serd_default_allocator();
SerdWorld* world = (SerdWorld*)serd_acalloc(actual, 1, sizeof(SerdWorld));
- SerdNode* blank_node = serd_new_blank(actual, serd_string("b00000000000"));
+ SerdNode* blank_node =
+ serd_node_new(actual, serd_a_blank_string("b00000000000"));
if (!world || !blank_node) {
serd_node_free(actual, blank_node);
diff --git a/src/writer.c b/src/writer.c
index 6d52b4e6..1de5e055 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -18,6 +18,7 @@
#include "serd/env.h"
#include "serd/event.h"
#include "serd/log.h"
+#include "serd/memory.h"
#include "serd/node.h"
#include "serd/output_stream.h"
#include "serd/sink.h"
@@ -1430,12 +1431,14 @@ serd_writer_set_root_uri(SerdWriter* writer, const SerdStringView uri)
{
assert(writer);
- serd_node_free(writer->world->allocator, writer->root_node);
+ SerdAllocator* const allocator = writer->world->allocator;
+
+ serd_node_free(allocator, writer->root_node);
writer->root_node = NULL;
writer->root_uri = SERD_URI_NULL;
if (uri.length) {
- writer->root_node = serd_new_uri(writer->world->allocator, uri);
+ writer->root_node = serd_node_new(allocator, serd_a_uri(uri));
writer->root_uri = serd_node_uri_view(writer->root_node);
}