aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2022-01-02 21:21:50 -0500
committerDavid Robillard <d@drobilla.net>2022-01-28 21:57:29 -0500
commit0b6260d46e57acfbe6f65301d9951836178bde6e (patch)
tree77d0ce977336ce03d0b98064335e22662652f45e
parent6e274953587941934e8f291d2dd99b843d5580ab (diff)
downloadserd-0b6260d46e57acfbe6f65301d9951836178bde6e.tar.gz
serd-0b6260d46e57acfbe6f65301d9951836178bde6e.tar.bz2
serd-0b6260d46e57acfbe6f65301d9951836178bde6e.zip
Consolidate number support into a single "value" API
-rw-r--r--doc/conf.py.in5
-rw-r--r--include/serd/serd.h267
-rw-r--r--meson.build1
-rw-r--r--src/node.c309
-rw-r--r--src/node.h7
-rw-r--r--src/nodes.c22
-rw-r--r--src/value.c114
-rw-r--r--test/test_node.c351
-rw-r--r--test/test_node_syntax.c15
-rw-r--r--test/test_nodes.c16
10 files changed, 685 insertions, 422 deletions
diff --git a/doc/conf.py.in b/doc/conf.py.in
index 39d9568f..8760bbd9 100644
--- a/doc/conf.py.in
+++ b/doc/conf.py.in
@@ -35,9 +35,14 @@ _opaque = [
"SerdStatementImpl",
"SerdWorldImpl",
"SerdWriterImpl",
+ "int16_t",
+ "int32_t",
"int64_t",
+ "int8_t",
"size_t",
+ "uint16_t",
"uint32_t",
+ "uint64_t",
"uint8_t",
"uintptr_t",
"va_list",
diff --git a/include/serd/serd.h b/include/serd/serd.h
index 49046054..c09494bc 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -741,6 +741,116 @@ typedef enum {
} SerdNodeType;
/**
+ @defgroup serd_node_value Values
+
+ Serd supports reading and writing machine-native numbers, called "values",
+ in a standards-conformant and portable way. The value structure is used in
+ the API to allow passing and returning a primitive value of any supported
+ type. Note that this is just an API convenience, literal nodes themselves
+ always store their values as strings.
+
+ @{
+*/
+
+/// The type of a #SerdValue
+typedef enum {
+ SERD_NOTHING, ///< Sentinel for unknown datatypes or errors
+ SERD_BOOL, ///< xsd:boolean (bool)
+ SERD_DOUBLE, ///< xsd:double (double)
+ SERD_FLOAT, ///< xsd:float (float)
+ SERD_LONG, ///< xsd:long (int64_t)
+ SERD_INT, ///< xsd:integer (int32_t)
+ SERD_SHORT, ///< xsd:short (int16_t)
+ SERD_BYTE, ///< xsd:byte (int8_t)
+ SERD_ULONG, ///< xsd:unsignedLong (uint64_t)
+ SERD_UINT, ///< xsd:unsignedInt (uint32_t)
+ SERD_USHORT, ///< xsd:unsignedShort (uint16_t)
+ SERD_UBYTE, ///< xsd:unsignedByte (uint8_t)
+} SerdValueType;
+
+/// The data of a #SerdValue (the actual machine-native primitive)
+typedef union {
+ bool as_bool;
+ double as_double;
+ float as_float;
+ int64_t as_long;
+ int32_t as_int;
+ int16_t as_short;
+ int8_t as_byte;
+ uint64_t as_ulong;
+ uint32_t as_uint;
+ uint16_t as_ushort;
+ uint8_t as_ubyte;
+} SerdValueData;
+
+/// A primitive value with a type tag
+typedef struct {
+ SerdValueType type;
+ SerdValueData data;
+} SerdValue;
+
+/// Convenience constructor to make a #SERD_NOTHING (non-)value
+SERD_CONST_API
+SerdValue
+serd_nothing(void);
+
+/// Convenience constructor to make a #SERD_BOOL value
+SERD_CONST_API
+SerdValue
+serd_bool(bool v);
+
+/// Convenience constructor to make a #SERD_DOUBLE value
+SERD_CONST_API
+SerdValue
+serd_double(double v);
+
+/// Convenience constructor to make a #SERD_FLOAT value
+SERD_CONST_API
+SerdValue
+serd_float(float v);
+
+/// Convenience constructor to make a #SERD_LONG value
+SERD_CONST_API
+SerdValue
+serd_long(int64_t v);
+
+/// Convenience constructor to make a #SERD_INT value
+SERD_CONST_API
+SerdValue
+serd_int(int32_t v);
+
+/// Convenience constructor to make a #SERD_SHORT value
+SERD_CONST_API
+SerdValue
+serd_short(int16_t v);
+
+/// Convenience constructor to make a #SERD_BYTE value
+SERD_CONST_API
+SerdValue
+serd_byte(int8_t v);
+
+/// Convenience constructor to make a #SERD_ULONG value
+SERD_CONST_API
+SerdValue
+serd_ulong(uint64_t v);
+
+/// Convenience constructor to make a #SERD_UINT value
+SERD_CONST_API
+SerdValue
+serd_uint(uint32_t v);
+
+/// Convenience constructor to make a #SERD_USHORT value
+SERD_CONST_API
+SerdValue
+serd_ushort(uint16_t v);
+
+/// Convenience constructor to make a #SERD_UBYTE value
+SERD_CONST_API
+SerdValue
+serd_ubyte(uint8_t v);
+
+/**
+ @}
@defgroup serd_node_construction Construction
This is the low-level node construction API, which can be used to construct
@@ -864,18 +974,15 @@ serd_node_construct_literal(size_t buf_size,
SerdStringView meta);
/**
- Construct a canonical xsd:boolean literal.
-
- The constructed node will be either "true" or "false", with datatype
- xsd:boolean.
+ Construct a canonical literal for a primitive value.
- This is a convenience wrapper for serd_node_construct_literal() that
- constructs a node directly from a `bool`.
+ The constructed node will be a typed literal in canonical form for the xsd
+ datatype corresponding to the value.
*/
SerdWriteResult
-serd_node_construct_boolean(size_t buf_size,
- void* SERD_NULLABLE buf,
- bool value);
+serd_node_construct_value(size_t buf_size,
+ void* SERD_NULLABLE buf,
+ SerdValue value);
/**
Construct a canonical xsd:decimal literal.
@@ -896,38 +1003,6 @@ serd_node_construct_decimal(size_t buf_size,
double value);
/**
- Construct a canonical xsd:double literal.
-
- The constructed node will be an xsd:double literal, like "1.23E45", with
- datatype xsd:double. A canonical xsd:double is always in scientific
- notation.
-
- This is a convenience wrapper for serd_node_construct_literal() that
- constructs a node directly from a `double`.
-*/
-SerdWriteResult
-serd_node_construct_double(size_t buf_size,
- void* SERD_NULLABLE buf,
- double value);
-
-/**
- Construct a canonical xsd:float literal.
-
- The constructed node will be an xsd:float literal, like "1.23E45", with
- datatype xsd:float. A canonical xsd:float is always in scientific notation.
-
- Uses identical formatting to serd_node_construct_double(), except with at
- most 9 significant digits (under 14 characters total).
-
- This is a convenience wrapper for serd_node_construct_literal() that
- constructs a node directly from a `float`.
-*/
-SerdWriteResult
-serd_node_construct_float(size_t buf_size,
- void* SERD_NULLABLE buf,
- float value);
-
-/**
Construct a canonical xsd:integer literal.
The constructed node will be an xsd:integer literal like "1234", with the
@@ -1069,17 +1144,17 @@ serd_new_literal(SerdAllocator* SERD_NULLABLE allocator,
SerdStringView meta);
/**
- Create a new canonical xsd:boolean node.
+ Create a new canonical value node.
- This is a wrapper for serd_node_construct_boolean() that allocates a new
- node on the heap.
+ This is a wrapper for serd_node_construct_value() that allocates a new node
+ on the heap.
@return A newly allocated node that must be freed with serd_node_free(), or
null.
*/
SERD_API
SerdNode* SERD_ALLOCATED
-serd_new_boolean(SerdAllocator* SERD_NULLABLE allocator, bool b);
+serd_new_value(SerdAllocator* SERD_NULLABLE allocator, SerdValue value);
/**
Create a new canonical xsd:decimal literal.
@@ -1095,32 +1170,6 @@ SerdNode* SERD_ALLOCATED
serd_new_decimal(SerdAllocator* SERD_NULLABLE allocator, double d);
/**
- Create a new canonical xsd:double literal.
-
- This is a wrapper for serd_node_construct_double() that allocates a new
- node on the heap.
-
- @return A newly allocated node that must be freed with serd_node_free(), or
- null.
-*/
-SERD_API
-SerdNode* SERD_ALLOCATED
-serd_new_double(SerdAllocator* SERD_NULLABLE allocator, double d);
-
-/**
- Create a new canonical xsd:float literal.
-
- This is a wrapper for serd_node_construct_float() that allocates a new
- node on the heap.
-
- @return A newly allocated node that must be freed with serd_node_free(), or
- null.
-*/
-SERD_API
-SerdNode* SERD_ALLOCATED
-serd_new_float(SerdAllocator* SERD_NULLABLE allocator, float f);
-
-/**
Create a new canonical xsd:integer literal.
This is a wrapper for serd_node_construct_integer() that allocates a new
@@ -1153,49 +1202,39 @@ serd_new_base64(SerdAllocator* SERD_NULLABLE allocator,
*/
/**
- Return the value of `node` as a boolean.
+ Return the primitive value of `node`.
- This will work for booleans, and numbers of any datatype if they are 0 or
- 1.
+ This will return a typed value if the node can be read as one, or a value
+ with type #SERD_NOTHING otherwise.
- @return The value of `node` as a `bool`, or `false` on error.
+ @return The value of `node` as a #SerdValue, if possible.
*/
SERD_API
-bool
-serd_get_boolean(const SerdNode* SERD_NONNULL node);
+SerdValue
+serd_get_value(const SerdNode* SERD_NONNULL node);
/**
- Return the value of `node` as a double.
+ Return the value of `node` as a specific type of number.
- This will coerce numbers of any datatype to double, if the value fits.
+ This is like serd_get_number(), but will coerce the value of the node to the
+ requrested type if possible.
- @return The value of `node` as a `double`, or NaN on error.
-*/
-SERD_API
-double
-serd_get_double(const SerdNode* SERD_NONNULL node);
+ @param node The node to interpret as a number.
-/**
- Return the value of `node` as a float.
+ @param type The desired numeric datatype of the result.
- This will coerce numbers of any datatype to float, if the value fits.
+ @param lossy Whether lossy conversions can be used. If this is false, then
+ this function only succeeds if the value could be converted back to the
+ original datatype of the node without loss. Otherwise, precision may be
+ reduced or values may be truncated to fit the result.
- @return The value of `node` as a `float`, or NaN on error.
+ @return The value of `node` as a #SerdValue, or nothing.
*/
SERD_API
-float
-serd_get_float(const SerdNode* SERD_NONNULL node);
-
-/**
- Return the value of `node` as a long (signed 64-bit integer).
-
- This will coerce numbers of any datatype to long, if the value fits.
-
- @return The value of `node` as a `int64_t`, or 0 on error.
-*/
-SERD_API
-int64_t
-serd_get_integer(const SerdNode* SERD_NONNULL node);
+SerdValue
+serd_get_value_as(const SerdNode* SERD_NONNULL node,
+ SerdValueType type,
+ bool lossy);
/**
Return the maximum size of a decoded base64 node in bytes.
@@ -1426,14 +1465,14 @@ serd_nodes_literal(SerdNodes* SERD_NONNULL nodes,
SerdStringView meta);
/**
- Make a canonical xsd:boolean node.
+ Make a canonical value node.
- A new node will be constructed with serd_node_construct_boolean() if an
+ A new node will be constructed with serd_node_construct_value() if an
equivalent one is not already in the set.
*/
SERD_API
const SerdNode* SERD_ALLOCATED
-serd_nodes_boolean(SerdNodes* SERD_NONNULL nodes, bool value);
+serd_nodes_value(SerdNodes* SERD_NONNULL nodes, SerdValue value);
/**
Make a canonical xsd:decimal node.
@@ -1446,26 +1485,6 @@ const SerdNode* SERD_ALLOCATED
serd_nodes_decimal(SerdNodes* SERD_NONNULL nodes, double value);
/**
- Make a canonical xsd:double node.
-
- A new node will be constructed with serd_node_construct_double() if an
- equivalent one is not already in the set.
-*/
-SERD_API
-const SerdNode* SERD_ALLOCATED
-serd_nodes_double(SerdNodes* SERD_NONNULL nodes, double value);
-
-/**
- Make a canonical xsd:float node.
-
- A new node will be constructed with serd_node_construct_float() if an
- equivalent one is not already in the set.
-*/
-SERD_API
-const SerdNode* SERD_ALLOCATED
-serd_nodes_float(SerdNodes* SERD_NONNULL nodes, float value);
-
-/**
Make a canonical xsd:integer node.
A new node will be constructed with serd_node_construct_integer() if an
diff --git a/meson.build b/meson.build
index 57547bfc..f94c9dd1 100644
--- a/meson.build
+++ b/meson.build
@@ -118,6 +118,7 @@ sources = [
'src/syntax.c',
'src/system.c',
'src/uri.c',
+ 'src/value.c',
'src/world.c',
'src/writer.c',
]
diff --git a/src/node.c b/src/node.c
index 2d92e07d..7ccc039f 100644
--- a/src/node.c
+++ b/src/node.c
@@ -24,7 +24,6 @@
#include "serd/serd.h"
#include <assert.h>
-#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
@@ -37,6 +36,21 @@
static const SerdNodeFlags meta_mask = (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE);
+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,
+};
+
// Round size up to an even multiple of the node alignment
static size_t
serd_node_pad_size(const size_t size)
@@ -281,21 +295,122 @@ serd_node_construct(const size_t buf_size,
: serd_node_construct_token(buf_size, buf, type, string));
}
+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;
+}
+
SerdWriteResult
-serd_node_construct_boolean(const size_t buf_size,
- void* const buf,
- const bool value)
-{
- char temp[EXESS_MAX_BOOLEAN_LENGTH + 1] = {0};
+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;
+ }
- const ExessResult r = exess_write_boolean(value, sizeof(temp), temp);
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(EXESS_XSD_URI "boolean"));
+ SERD_OPTIONAL_STRING(datatype_uri));
}
SerdWriteResult
@@ -316,40 +431,6 @@ serd_node_construct_decimal(const size_t buf_size,
}
SerdWriteResult
-serd_node_construct_double(const size_t buf_size,
- void* const buf,
- const double value)
-{
- char temp[EXESS_MAX_DOUBLE_LENGTH + 1] = {0};
-
- const ExessResult r = exess_write_double(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 "double"));
-}
-
-SerdWriteResult
-serd_node_construct_float(const size_t buf_size,
- void* const buf,
- const float value)
-{
- char temp[EXESS_MAX_FLOAT_LENGTH + 1] = {0};
-
- const ExessResult r = exess_write_float(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 "float"));
-}
-
-SerdWriteResult
serd_node_construct_integer(const size_t buf_size,
void* const buf,
const int64_t value)
@@ -503,91 +584,69 @@ serd_new_literal(SerdAllocator* const allocator,
return serd_node_new(allocator, SERD_LITERAL, str, flags, meta);
}
-ExessResult
-serd_node_get_value_as(const SerdNode* const node,
- const ExessDatatype value_type,
- const size_t value_size,
- void* const value)
+SerdValue
+serd_get_value(const SerdNode* const node)
{
+ assert(node);
+
const SerdNode* const datatype_node = serd_node_datatype(node);
- const ExessDatatype node_type =
+ const ExessDatatype datatype =
datatype_node ? exess_datatype_from_uri(serd_node_string(datatype_node))
: EXESS_NOTHING;
- 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));
-
- const ExessResult r = {vr.status, vr.write_count};
- return r;
+ const SerdValueType value_type = datatype_value_type(datatype);
+ if (value_type == SERD_NOTHING) {
+ return serd_nothing();
}
- // 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));
+ ExessValue value = {false};
+ const ExessVariableResult vr =
+ exess_read_value(datatype, sizeof(value), &value, serd_node_string(node));
if (vr.status) {
- const ExessResult r = {vr.status, 0u};
- return r;
+ return serd_nothing();
}
- // 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);
-}
-
-bool
-serd_get_boolean(const SerdNode* const node)
-{
- assert(node);
-
- bool value = false;
- serd_node_get_value_as(node, EXESS_BOOLEAN, sizeof(value), &value);
-
- return value;
-}
-
-double
-serd_get_double(const SerdNode* const node)
-{
- assert(node);
-
- double value = (double)NAN; // NOLINT(google-readability-casting)
- serd_node_get_value_as(node, EXESS_DOUBLE, sizeof(value), &value);
+ SerdValue result = {value_type, {false}};
+ memcpy(&result.data, &value, vr.write_count);
- return value;
+ return result;
}
-float
-serd_get_float(const SerdNode* const node)
+SerdValue
+serd_get_value_as(const SerdNode* const node,
+ const SerdValueType type,
+ const bool lossy)
{
- assert(node);
+ // Get the value as it is
+ const SerdValue value = serd_get_value(node);
+ if (!value.type || value.type == type) {
+ return value;
+ }
- float value = (float)NAN; // NOLINT(google-readability-casting)
- serd_node_get_value_as(node, EXESS_FLOAT, sizeof(value), &value);
+ const ExessCoercions coercions =
+ lossy ? (EXESS_REDUCE_PRECISION | EXESS_ROUND | EXESS_TRUNCATE)
+ : EXESS_LOSSLESS;
- return value;
-}
+ const ExessDatatype node_datatype = value_type_datatype(value.type);
+ const ExessDatatype datatype = value_type_datatype(type);
+ SerdValue result = {type, {false}};
-int64_t
-serd_get_integer(const SerdNode* const node)
-{
- assert(node);
+ // 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);
- int64_t value = 0;
- serd_node_get_value_as(node, EXESS_LONG, sizeof(value), &value);
+ if (r.status) {
+ result.type = SERD_NOTHING;
+ }
- return value;
+ return result;
}
size_t
@@ -784,45 +843,13 @@ serd_new_file_uri(SerdAllocator* const allocator,
}
SerdNode*
-serd_new_double(SerdAllocator* const allocator, const double d)
-{
- SerdWriteResult r = serd_node_construct_double(0, NULL, d);
- SerdNode* const node = serd_node_try_malloc(allocator, r);
-
- if (node) {
- r = serd_node_construct_double(r.count, node, d);
- MUST_SUCCEED(r.status);
- assert(serd_node_length(node) == strlen(serd_node_string(node)));
- serd_node_check_padding(node);
- }
-
- return node;
-}
-
-SerdNode*
-serd_new_float(SerdAllocator* const allocator, const float f)
-{
- SerdWriteResult r = serd_node_construct_float(0, NULL, f);
- SerdNode* const node = serd_node_try_malloc(allocator, r);
-
- if (node) {
- r = serd_node_construct_float(r.count, node, f);
- MUST_SUCCEED(r.status);
- assert(serd_node_length(node) == strlen(serd_node_string(node)));
- serd_node_check_padding(node);
- }
-
- return node;
-}
-
-SerdNode*
-serd_new_boolean(SerdAllocator* const allocator, bool b)
+serd_new_value(SerdAllocator* const allocator, const SerdValue value)
{
- SerdWriteResult r = serd_node_construct_boolean(0, NULL, b);
+ SerdWriteResult r = serd_node_construct_value(0, NULL, value);
SerdNode* const node = serd_node_try_malloc(allocator, r);
if (node) {
- r = serd_node_construct_boolean(r.count, node, b);
+ r = serd_node_construct_value(r.count, node, value);
MUST_SUCCEED(r.status);
assert(serd_node_length(node) == strlen(serd_node_string(node)));
serd_node_check_padding(node);
diff --git a/src/node.h b/src/node.h
index 751b827a..4e40c530 100644
--- a/src/node.h
+++ b/src/node.h
@@ -17,7 +17,6 @@
#ifndef SERD_NODE_H
#define SERD_NODE_H
-#include "exess/exess.h"
#include "serd/serd.h"
#include <assert.h>
@@ -121,10 +120,4 @@ serd_node_total_size(const SerdNode* SERD_NONNULL node);
void
serd_node_zero_pad(SerdNode* SERD_NONNULL node);
-ExessResult
-serd_node_get_value_as(const SerdNode* SERD_NONNULL node,
- ExessDatatype value_type,
- size_t value_size,
- void* SERD_NONNULL value);
-
#endif // SERD_NODE_H
diff --git a/src/nodes.c b/src/nodes.c
index 90dd4f2c..c048863b 100644
--- a/src/nodes.c
+++ b/src/nodes.c
@@ -415,12 +415,12 @@ try_intern(SerdNodes* const nodes,
}
const SerdNode*
-serd_nodes_boolean(SerdNodes* const nodes, bool value)
+serd_nodes_value(SerdNodes* const nodes, const SerdValue value)
{
StaticNode key = empty_static_node;
return try_intern(
- nodes, serd_node_construct_boolean(sizeof(key), &key, value), &key.node);
+ nodes, serd_node_construct_value(sizeof(key), &key, value), &key.node);
}
const SerdNode*
@@ -433,24 +433,6 @@ serd_nodes_decimal(SerdNodes* const nodes, const double value)
}
const SerdNode*
-serd_nodes_double(SerdNodes* const nodes, const double value)
-{
- StaticNode key = empty_static_node;
-
- return try_intern(
- nodes, serd_node_construct_double(sizeof(key), &key, value), &key.node);
-}
-
-const SerdNode*
-serd_nodes_float(SerdNodes* const nodes, const float value)
-{
- StaticNode key = empty_static_node;
-
- return try_intern(
- nodes, serd_node_construct_float(sizeof(key), &key, value), &key.node);
-}
-
-const SerdNode*
serd_nodes_integer(SerdNodes* const nodes, const int64_t value)
{
StaticNode key = empty_static_node;
diff --git a/src/value.c b/src/value.c
new file mode 100644
index 00000000..bd6320bf
--- /dev/null
+++ b/src/value.c
@@ -0,0 +1,114 @@
+/*
+ Copyright 2022 David Robillard <d@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.
+*/
+
+#include "serd/serd.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/test/test_node.c b/test/test_node.c
index c1d39053..5cba7013 100644
--- a/test/test_node.c
+++ b/test/test_node.c
@@ -57,54 +57,156 @@
#endif
static void
+test_value(void)
+{
+ static const double double_one = 1.0;
+ static const float float_two = 2.0f;
+
+ SerdNode* const null_node = serd_new_value(NULL, serd_nothing());
+ SerdNode* const bool_node = serd_new_value(NULL, serd_bool(false));
+ SerdNode* const double_node = serd_new_value(NULL, serd_double(1.0));
+ SerdNode* const float_node = serd_new_value(NULL, serd_float(2.0f));
+ SerdNode* const long_node = serd_new_value(NULL, serd_long(3));
+ SerdNode* const int_node = serd_new_value(NULL, serd_int(4));
+ SerdNode* const short_node = serd_new_value(NULL, serd_short(5));
+ SerdNode* const byte_node = serd_new_value(NULL, serd_byte(6));
+ SerdNode* const ulong_node = serd_new_value(NULL, serd_ulong(7u));
+ SerdNode* const uint_node = serd_new_value(NULL, serd_uint(8u));
+ SerdNode* const ushort_node = serd_new_value(NULL, serd_ushort(9u));
+ SerdNode* const ubyte_node = serd_new_value(NULL, serd_ubyte(10u));
+
+ assert(!null_node);
+
+ assert(!strcmp(serd_node_string(bool_node), "false"));
+ assert(serd_get_value(bool_node).type == SERD_BOOL);
+ assert(serd_get_value(bool_node).data.as_bool == false);
+
+ assert(!strcmp(serd_node_string(double_node), "1.0E0"));
+ assert(serd_get_value(double_node).type == SERD_DOUBLE);
+ {
+ const double double_value = serd_get_value(double_node).data.as_double;
+ assert(!memcmp(&double_value, &double_one, sizeof(double)));
+ }
+
+ assert(!strcmp(serd_node_string(float_node), "2.0E0"));
+ assert(serd_get_value(float_node).type == SERD_FLOAT);
+ {
+ const float float_value = serd_get_value(float_node).data.as_float;
+ assert(!memcmp(&float_value, &float_two, sizeof(float)));
+ }
+
+ assert(!strcmp(serd_node_string(long_node), "3"));
+ assert(serd_get_value(long_node).type == SERD_LONG);
+ assert(serd_get_value(long_node).data.as_long == 3);
+
+ assert(!strcmp(serd_node_string(int_node), "4"));
+ assert(serd_get_value(int_node).type == SERD_INT);
+ assert(serd_get_value(int_node).data.as_int == 4);
+
+ assert(!strcmp(serd_node_string(short_node), "5"));
+ assert(serd_get_value(short_node).type == SERD_SHORT);
+ assert(serd_get_value(short_node).data.as_short == 5);
+
+ assert(!strcmp(serd_node_string(byte_node), "6"));
+ assert(serd_get_value(byte_node).type == SERD_BYTE);
+ assert(serd_get_value(byte_node).data.as_byte == 6);
+
+ assert(!strcmp(serd_node_string(ulong_node), "7"));
+ assert(serd_get_value(ulong_node).type == SERD_ULONG);
+ assert(serd_get_value(ulong_node).data.as_ulong == 7u);
+
+ assert(!strcmp(serd_node_string(uint_node), "8"));
+ assert(serd_get_value(uint_node).type == SERD_UINT);
+ assert(serd_get_value(uint_node).data.as_uint == 8u);
+
+ assert(!strcmp(serd_node_string(ushort_node), "9"));
+ assert(serd_get_value(ushort_node).type == SERD_USHORT);
+ assert(serd_get_value(ushort_node).data.as_ushort == 9u);
+
+ assert(!strcmp(serd_node_string(ubyte_node), "10"));
+ assert(serd_get_value(ubyte_node).type == SERD_UBYTE);
+ assert(serd_get_value(ubyte_node).data.as_ubyte == 10u);
+
+ serd_node_free(NULL, bool_node);
+ serd_node_free(NULL, double_node);
+ serd_node_free(NULL, float_node);
+ serd_node_free(NULL, long_node);
+ serd_node_free(NULL, int_node);
+ serd_node_free(NULL, short_node);
+ serd_node_free(NULL, byte_node);
+ serd_node_free(NULL, ulong_node);
+ serd_node_free(NULL, uint_node);
+ serd_node_free(NULL, ushort_node);
+ serd_node_free(NULL, ubyte_node);
+}
+
+static void
test_boolean(void)
{
- SerdNode* const true_node = serd_new_boolean(NULL, true);
- assert(!strcmp(serd_node_string(true_node), "true"));
- assert(serd_get_boolean(true_node));
-
- const SerdNode* const true_datatype = serd_node_datatype(true_node);
- assert(true_datatype);
- assert(!strcmp(serd_node_string(true_datatype), NS_XSD "boolean"));
- serd_node_free(NULL, true_node);
-
- SerdNode* const false_node = serd_new_boolean(NULL, false);
- assert(!strcmp(serd_node_string(false_node), "false"));
- assert(!serd_get_boolean(false_node));
-
- const SerdNode* const false_datatype = serd_node_datatype(false_node);
- assert(false_datatype);
- assert(!strcmp(serd_node_string(false_datatype), NS_XSD "boolean"));
- serd_node_free(NULL, false_node);
+ {
+ SerdNode* const true_node = serd_new_value(NULL, serd_bool(true));
+ assert(true_node);
+ assert(!strcmp(serd_node_string(true_node), "true"));
+ assert(serd_get_value(true_node).data.as_bool);
+
+ const SerdNode* const true_datatype = serd_node_datatype(true_node);
+ assert(true_datatype);
+ assert(!strcmp(serd_node_string(true_datatype), NS_XSD "boolean"));
+ serd_node_free(NULL, true_node);
+ }
+ {
+ SerdNode* const false_node = serd_new_value(NULL, serd_bool(false));
+ assert(false_node);
+ assert(!strcmp(serd_node_string(false_node), "false"));
+ assert(!serd_get_value(false_node).data.as_bool);
+
+ const SerdNode* const false_datatype = serd_node_datatype(false_node);
+ assert(false_datatype);
+ assert(!strcmp(serd_node_string(false_datatype), NS_XSD "boolean"));
+ serd_node_free(NULL, false_node);
+ }
}
static void
-check_get_boolean(const char* string,
- const char* datatype_uri,
- const bool expected)
+check_get_bool(const char* string,
+ const char* datatype_uri,
+ const bool lossy,
+ const SerdValueType value_type,
+ const bool expected)
{
SerdNode* const node = serd_new_literal(
NULL, SERD_STRING(string), SERD_HAS_DATATYPE, SERD_STRING(datatype_uri));
assert(node);
- assert(serd_get_boolean(node) == expected);
+
+ const SerdValue value = serd_get_value_as(node, SERD_BOOL, lossy);
+
+ assert(value.type == value_type);
+ assert(value.data.as_bool == expected);
serd_node_free(NULL, node);
}
static void
-test_get_boolean(void)
+test_get_bool(void)
{
- check_get_boolean("false", NS_XSD "boolean", false);
- check_get_boolean("true", NS_XSD "boolean", true);
- check_get_boolean("0", NS_XSD "boolean", false);
- check_get_boolean("1", NS_XSD "boolean", true);
- check_get_boolean("0", NS_XSD "integer", false);
- check_get_boolean("1", NS_XSD "integer", true);
- check_get_boolean("0.0", NS_XSD "double", false);
- check_get_boolean("1.0", NS_XSD "double", true);
- check_get_boolean("unknown", NS_XSD "string", false);
- check_get_boolean("!invalid", NS_XSD "long", false);
+ check_get_bool("false", NS_XSD "boolean", false, SERD_BOOL, false);
+ check_get_bool("true", NS_XSD "boolean", false, SERD_BOOL, true);
+ check_get_bool("0", NS_XSD "boolean", false, SERD_BOOL, false);
+ check_get_bool("1", NS_XSD "boolean", false, SERD_BOOL, true);
+ check_get_bool("0", NS_XSD "integer", false, SERD_BOOL, false);
+ check_get_bool("1", NS_XSD "integer", false, SERD_BOOL, true);
+ check_get_bool("0.0", NS_XSD "double", false, SERD_BOOL, false);
+ check_get_bool("1.0", NS_XSD "double", false, SERD_BOOL, true);
+
+ check_get_bool("2", NS_XSD "integer", false, SERD_NOTHING, false);
+ check_get_bool("1.5", NS_XSD "double", false, SERD_NOTHING, false);
+
+ check_get_bool("2", NS_XSD "integer", true, SERD_BOOL, true);
+ check_get_bool("1.5", NS_XSD "double", true, SERD_BOOL, true);
+
+ check_get_bool("unknown", NS_XSD "string", true, SERD_NOTHING, false);
+ check_get_bool("!invalid", NS_XSD "long", true, SERD_NOTHING, false);
}
static void
@@ -134,8 +236,8 @@ test_decimal(void)
assert(datatype);
assert(!strcmp(serd_node_string(datatype), NS_XSD "decimal"));
- const double value = serd_get_double(node);
- assert(!memcmp(&value, &test_values[i], sizeof(value)));
+ const SerdValue value = serd_get_value(node);
+ assert(!memcmp(&value.data.as_double, &test_values[i], sizeof(double)));
serd_node_free(NULL, node);
}
}
@@ -148,7 +250,7 @@ test_double(void)
"0.0E0", "-0.0E0", "1.2E0", "-2.3E0", "4.56789E6"};
for (size_t i = 0; i < sizeof(test_values) / sizeof(double); ++i) {
- SerdNode* node = serd_new_double(NULL, test_values[i]);
+ SerdNode* node = serd_new_value(NULL, serd_double(test_values[i]));
const char* node_str = serd_node_string(node);
assert(!strcmp(node_str, test_strings[i]));
@@ -159,24 +261,35 @@ test_double(void)
assert(datatype);
assert(!strcmp(serd_node_string(datatype), NS_XSD "double"));
- const double value = serd_get_double(node);
- assert(!memcmp(&value, &test_values[i], sizeof(value)));
+ const SerdValue value = serd_get_value(node);
+ assert(!memcmp(&value.data.as_double, &test_values[i], sizeof(double)));
serd_node_free(NULL, node);
}
}
static void
-check_get_double(const char* string,
- const char* datatype_uri,
- const double expected)
+check_get_double(const char* string,
+ const char* datatype_uri,
+ const bool lossy,
+ const SerdValueType value_type,
+ const double expected)
{
SerdNode* const node = serd_new_literal(
NULL, SERD_STRING(string), SERD_HAS_DATATYPE, SERD_STRING(datatype_uri));
assert(node);
- const double value = serd_get_double(node);
- assert(!memcmp(&value, &expected, sizeof(value)));
+ const SerdValue value = serd_get_value_as(node, SERD_DOUBLE, lossy);
+
+ assert(value.type == value_type);
+
+ SERD_DISABLE_CONVERSION_WARNINGS
+
+ assert(value_type == SERD_NOTHING ||
+ ((isnan(value.data.as_double) && isnan(expected)) ||
+ !memcmp(&value.data.as_double, &expected, sizeof(double))));
+
+ SERD_RESTORE_WARNINGS
serd_node_free(NULL, node);
}
@@ -184,34 +297,19 @@ check_get_double(const char* string,
static void
test_get_double(void)
{
- check_get_double("1.2", NS_XSD "double", 1.2);
- check_get_double("-.5", NS_XSD "float", -0.5);
- check_get_double("-67", NS_XSD "long", -67.0);
- check_get_double("8.9", NS_XSD "decimal", 8.9);
- check_get_double("false", NS_XSD "boolean", 0.0);
- check_get_double("true", NS_XSD "boolean", 1.0);
-
- static const uint8_t blob[] = {1u, 2u, 3u, 4u};
+ check_get_double("1.2", NS_XSD "double", false, SERD_DOUBLE, 1.2);
+ check_get_double("-.5", NS_XSD "float", false, SERD_DOUBLE, -0.5);
+ check_get_double("-67", NS_XSD "long", false, SERD_DOUBLE, -67.0);
+ check_get_double("67", NS_XSD "unsignedLong", false, SERD_DOUBLE, 67.0);
+ check_get_double("8.9", NS_XSD "decimal", false, SERD_DOUBLE, 8.9);
+ check_get_double("false", NS_XSD "boolean", false, SERD_DOUBLE, 0.0);
+ check_get_double("true", NS_XSD "boolean", false, SERD_DOUBLE, 1.0);
SERD_DISABLE_CONVERSION_WARNINGS
-
- SerdNode* const nan = serd_new_string(NULL, SERD_STRING("unknown"));
- assert(isnan(serd_get_double(nan)));
- serd_node_free(NULL, nan);
-
- SerdNode* const invalid = serd_new_literal(NULL,
- SERD_STRING("!invalid"),
- SERD_HAS_DATATYPE,
- SERD_STRING(NS_XSD "long"));
-
- assert(isnan(serd_get_double(invalid)));
- serd_node_free(NULL, invalid);
-
- SerdNode* const base64 = serd_new_base64(NULL, blob, sizeof(blob));
-
- assert(isnan(serd_get_double(base64)));
- serd_node_free(NULL, base64);
-
+ check_get_double("str", NS_XSD "string", true, SERD_NOTHING, NAN);
+ check_get_double("!invalid", NS_XSD "long", true, SERD_NOTHING, NAN);
+ check_get_double("D3AD", NS_XSD "hexBinary", true, SERD_NOTHING, NAN);
+ check_get_double("Zm9v", NS_XSD "base64Binary", true, SERD_NOTHING, NAN);
SERD_RESTORE_WARNINGS
}
@@ -223,7 +321,7 @@ test_float(void)
"0.0E0", "-0.0E0", "1.5E0", "-2.5E0", "4.56789E6"};
for (size_t i = 0; i < sizeof(test_values) / sizeof(float); ++i) {
- SerdNode* node = serd_new_float(NULL, test_values[i]);
+ SerdNode* node = serd_new_value(NULL, serd_float(test_values[i]));
const char* node_str = serd_node_string(node);
assert(!strcmp(node_str, test_strings[i]));
@@ -234,24 +332,35 @@ test_float(void)
assert(datatype);
assert(!strcmp(serd_node_string(datatype), NS_XSD "float"));
- const float value = serd_get_float(node);
- assert(!memcmp(&value, &test_values[i], sizeof(value)));
+ const SerdValue value = serd_get_value(node);
+ assert(!memcmp(&value.data.as_float, &test_values[i], sizeof(float)));
serd_node_free(NULL, node);
}
}
static void
-check_get_float(const char* string,
- const char* datatype_uri,
- const float expected)
+check_get_float(const char* string,
+ const char* datatype_uri,
+ const bool lossy,
+ const SerdValueType value_type,
+ const float expected)
{
SerdNode* const node = serd_new_literal(
NULL, SERD_STRING(string), SERD_HAS_DATATYPE, SERD_STRING(datatype_uri));
assert(node);
- const float value = serd_get_float(node);
- assert(!memcmp(&value, &expected, sizeof(value)));
+ const SerdValue value = serd_get_value_as(node, SERD_FLOAT, lossy);
+
+ assert(value.type == value_type);
+
+ SERD_DISABLE_CONVERSION_WARNINGS
+
+ assert(value_type == SERD_NOTHING ||
+ ((isnan(value.data.as_float) && isnan(expected)) ||
+ !memcmp(&value.data.as_float, &expected, sizeof(float))));
+
+ SERD_RESTORE_WARNINGS
serd_node_free(NULL, node);
}
@@ -259,29 +368,20 @@ check_get_float(const char* string,
static void
test_get_float(void)
{
- check_get_float("1.2", NS_XSD "float", 1.2f);
- check_get_float("-.5", NS_XSD "float", -0.5f);
- check_get_float("-67", NS_XSD "long", -67.0f);
- check_get_float("1.5", NS_XSD "decimal", 1.5f);
- check_get_float("false", NS_XSD "boolean", 0.0f);
- check_get_float("true", NS_XSD "boolean", 1.0f);
-
- SERD_DISABLE_CONVERSION_WARNINGS
+ check_get_float("1.2", NS_XSD "float", false, SERD_FLOAT, 1.2f);
+ check_get_float("-.5", NS_XSD "float", false, SERD_FLOAT, -0.5f);
+ check_get_float("-67", NS_XSD "long", false, SERD_FLOAT, -67.0f);
+ check_get_float("false", NS_XSD "boolean", false, SERD_FLOAT, 0.0f);
+ check_get_float("true", NS_XSD "boolean", false, SERD_FLOAT, 1.0f);
- SerdNode* const nan = serd_new_string(NULL, SERD_STRING("unknown"));
- assert(isnan(serd_get_float(nan)));
- serd_node_free(NULL, nan);
-
- SerdNode* const invalid = serd_new_literal(NULL,
- SERD_STRING("!invalid"),
- SERD_HAS_DATATYPE,
- SERD_STRING(NS_XSD "long"));
-
- assert(isnan(serd_get_double(invalid)));
+ check_get_float("1.5", NS_XSD "decimal", true, SERD_FLOAT, 1.5f);
+ SERD_DISABLE_CONVERSION_WARNINGS
+ check_get_float("str", NS_XSD "string", true, SERD_NOTHING, NAN);
+ check_get_float("!invalid", NS_XSD "long", true, SERD_NOTHING, NAN);
+ check_get_float("D3AD", NS_XSD "hexBinary", true, SERD_NOTHING, NAN);
+ check_get_float("Zm9v", NS_XSD "base64Binary", true, SERD_NOTHING, NAN);
SERD_RESTORE_WARNINGS
-
- serd_node_free(NULL, invalid);
}
static void
@@ -302,21 +402,27 @@ test_integer(void)
assert(datatype);
assert(!strcmp(serd_node_string(datatype), NS_XSD "integer"));
- assert(serd_get_integer(node) == test_values[i]);
+ assert(serd_get_value(node).data.as_long == test_values[i]);
serd_node_free(NULL, node);
}
}
static void
-check_get_integer(const char* string,
- const char* datatype_uri,
- const int64_t expected)
+check_get_integer(const char* string,
+ const char* datatype_uri,
+ const bool lossy,
+ const SerdValueType value_type,
+ const int64_t expected)
{
SerdNode* const node = serd_new_literal(
NULL, SERD_STRING(string), SERD_HAS_DATATYPE, SERD_STRING(datatype_uri));
assert(node);
- assert(serd_get_integer(node) == expected);
+
+ const SerdValue value = serd_get_value_as(node, SERD_LONG, lossy);
+
+ assert(value.type == value_type);
+ assert(value_type == SERD_NOTHING || value.data.as_long == expected);
serd_node_free(NULL, node);
}
@@ -324,14 +430,23 @@ check_get_integer(const char* string,
static void
test_get_integer(void)
{
- check_get_integer("12", NS_XSD "long", 12);
- check_get_integer("-34", NS_XSD "long", -34);
- check_get_integer("56", NS_XSD "integer", 56);
- check_get_integer("false", NS_XSD "boolean", 0);
- check_get_integer("true", NS_XSD "boolean", 1);
- check_get_integer("78.0", NS_XSD "decimal", 78);
- check_get_integer("unknown", NS_XSD "string", 0);
- check_get_integer("!invalid", NS_XSD "long", 0);
+ check_get_integer("12", NS_XSD "long", false, SERD_LONG, 12);
+ check_get_integer("-34", NS_XSD "long", false, SERD_LONG, -34);
+ check_get_integer("56", NS_XSD "integer", false, SERD_LONG, 56);
+ check_get_integer("false", NS_XSD "boolean", false, SERD_LONG, 0);
+ check_get_integer("true", NS_XSD "boolean", false, SERD_LONG, 1);
+ check_get_integer("78.0", NS_XSD "decimal", false, SERD_LONG, 78);
+
+ check_get_integer("0", NS_XSD "nonPositiveInteger", false, SERD_LONG, 0);
+ check_get_integer("-1", NS_XSD "negativeInteger", false, SERD_LONG, -1);
+ check_get_integer("2", NS_XSD "nonNegativeInteger", false, SERD_LONG, 2);
+ check_get_integer("3", NS_XSD "positiveInteger", false, SERD_LONG, 3);
+
+ check_get_integer("78.5", NS_XSD "decimal", false, SERD_NOTHING, 0);
+ check_get_integer("78.5", NS_XSD "decimal", true, SERD_LONG, 78);
+
+ check_get_integer("unknown", NS_XSD "string", true, SERD_NOTHING, 0);
+ check_get_integer("!invalid", NS_XSD "long", true, SERD_NOTHING, 0);
}
static void
@@ -592,10 +707,11 @@ test_compare(void)
SerdNode* hallo = serd_new_literal(
NULL, SERD_STRING("Hallo"), SERD_HAS_LANGUAGE, SERD_STRING("de"));
- SerdNode* hello = serd_new_string(NULL, SERD_STRING("Hello"));
- SerdNode* universe = serd_new_string(NULL, SERD_STRING("Universe"));
- SerdNode* integer = serd_new_integer(NULL, 4);
- SerdNode* blank = serd_new_token(NULL, SERD_BLANK, SERD_STRING("b1"));
+ SerdNode* hello = serd_new_string(NULL, SERD_STRING("Hello"));
+ SerdNode* universe = serd_new_string(NULL, SERD_STRING("Universe"));
+ SerdNode* integer = serd_new_integer(NULL, 4);
+ SerdNode* short_integer = serd_new_value(NULL, serd_short(4));
+ SerdNode* blank = serd_new_token(NULL, SERD_BLANK, SERD_STRING("b1"));
SerdNode* uri = serd_new_uri(NULL, SERD_STRING("http://example.org/"));
@@ -621,12 +737,14 @@ test_compare(void)
assert(serd_node_compare(angst, angst_de) < 0);
assert(serd_node_compare(angst_de, angst_en) < 0);
assert(serd_node_compare(aardvark, badger) < 0);
+ assert(serd_node_compare(integer, short_integer) < 0);
+ serd_node_free(NULL, badger);
+ serd_node_free(NULL, aardvark);
serd_node_free(NULL, uri);
serd_node_free(NULL, blank);
+ serd_node_free(NULL, short_integer);
serd_node_free(NULL, integer);
- serd_node_free(NULL, badger);
- serd_node_free(NULL, aardvark);
serd_node_free(NULL, universe);
serd_node_free(NULL, hello);
serd_node_free(NULL, hallo);
@@ -639,8 +757,9 @@ test_compare(void)
int
main(void)
{
+ test_value();
test_boolean();
- test_get_boolean();
+ test_get_bool();
test_decimal();
test_double();
test_get_double();
diff --git a/test/test_node_syntax.c b/test/test_node_syntax.c
index 09037363..a8e0a163 100644
--- a/test/test_node_syntax.c
+++ b/test/test_node_syntax.c
@@ -130,12 +130,12 @@ test_common(SerdWorld* const world, const SerdSyntax syntax)
assert(check(world,
syntax,
- serd_new_double(NULL, 1.25),
+ serd_new_value(NULL, serd_double(1.25)),
"\"1.25E0\"^^<http://www.w3.org/2001/XMLSchema#double>"));
assert(check(world,
syntax,
- serd_new_float(NULL, 1.25),
+ serd_new_value(NULL, serd_float(1.25f)),
"\"1.25E0\"^^<http://www.w3.org/2001/XMLSchema#float>"));
assert(
@@ -186,12 +186,12 @@ test_ntriples(void)
assert(check(world,
SERD_NTRIPLES,
- serd_new_boolean(NULL, true),
+ serd_new_value(NULL, serd_bool(true)),
"\"true\"^^<http://www.w3.org/2001/XMLSchema#boolean>"));
assert(check(world,
SERD_NTRIPLES,
- serd_new_boolean(NULL, false),
+ serd_new_value(NULL, serd_bool(false)),
"\"false\"^^<http://www.w3.org/2001/XMLSchema#boolean>"));
serd_world_free(world);
@@ -212,8 +212,11 @@ test_turtle(void)
assert(check(world, SERD_TURTLE, serd_new_decimal(NULL, 1.25), "1.25"));
assert(check(world, SERD_TURTLE, serd_new_integer(NULL, 1234), "1234"));
- assert(check(world, SERD_TURTLE, serd_new_boolean(NULL, true), "true"));
- assert(check(world, SERD_TURTLE, serd_new_boolean(NULL, false), "false"));
+ assert(
+ check(world, SERD_TURTLE, serd_new_value(NULL, serd_bool(true)), "true"));
+
+ assert(
+ check(world, SERD_TURTLE, serd_new_value(NULL, serd_bool(false)), "false"));
serd_world_free(world);
}
diff --git a/test/test_nodes.c b/test/test_nodes.c
index 19dcee01..482c7727 100644
--- a/test/test_nodes.c
+++ b/test/test_nodes.c
@@ -232,10 +232,10 @@ test_boolean(void)
SerdNodes* const nodes = serd_nodes_new(allocator);
- const SerdNode* const false1 = serd_nodes_boolean(nodes, false);
- const SerdNode* const false2 = serd_nodes_boolean(nodes, false);
- const SerdNode* const true1 = serd_nodes_boolean(nodes, true);
- const SerdNode* const true2 = serd_nodes_boolean(nodes, true);
+ const SerdNode* const false1 = serd_nodes_value(nodes, serd_bool(false));
+ const SerdNode* const false2 = serd_nodes_value(nodes, serd_bool(false));
+ const SerdNode* const true1 = serd_nodes_value(nodes, serd_bool(true));
+ const SerdNode* const true2 = serd_nodes_value(nodes, serd_bool(true));
assert(false1 == false2);
assert(true1 == true2);
@@ -285,8 +285,8 @@ test_double(void)
SerdNodes* const nodes = serd_nodes_new(allocator);
- const SerdNode* const a = serd_nodes_double(nodes, -1.2E3);
- const SerdNode* const b = serd_nodes_double(nodes, -1.2E3);
+ const SerdNode* const a = serd_nodes_value(nodes, serd_double(-1.2E3));
+ const SerdNode* const b = serd_nodes_value(nodes, serd_double(-1.2E3));
assert(a == b);
assert(!strcmp(serd_node_string(a), "-1.2E3"));
@@ -303,8 +303,8 @@ test_float(void)
SerdNodes* const nodes = serd_nodes_new(allocator);
- const SerdNode* const a = serd_nodes_float(nodes, -1.2E3f);
- const SerdNode* const b = serd_nodes_float(nodes, -1.2E3f);
+ const SerdNode* const a = serd_nodes_value(nodes, serd_float(-1.2E3f));
+ const SerdNode* const b = serd_nodes_value(nodes, serd_float(-1.2E3f));
assert(a == b);
assert(!strcmp(serd_node_string(a), "-1.2E3"));