aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/exess/src/variant.c
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/exess/src/variant.c')
-rw-r--r--subprojects/exess/src/variant.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/subprojects/exess/src/variant.c b/subprojects/exess/src/variant.c
new file mode 100644
index 00000000..d8977abd
--- /dev/null
+++ b/subprojects/exess/src/variant.c
@@ -0,0 +1,431 @@
+/*
+ Copyright 2019-2021 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 "read_utils.h"
+#include "write_utils.h"
+
+#include "exess/exess.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+// Constructors
+
+ExessVariant
+exess_make_nothing(const ExessStatus status)
+{
+ ExessVariant v = {EXESS_NOTHING, .value.as_status = status};
+ return v;
+}
+
+ExessVariant
+exess_make_boolean(const bool value)
+{
+ ExessVariant v = {EXESS_BOOLEAN, .value.as_bool = value};
+ return v;
+}
+
+ExessVariant
+exess_make_decimal(const double value)
+{
+ ExessVariant v = {EXESS_DECIMAL, .value.as_double = value};
+ return v;
+}
+
+ExessVariant
+exess_make_double(const double value)
+{
+ ExessVariant v = {EXESS_DOUBLE, .value.as_double = value};
+ return v;
+}
+
+ExessVariant
+exess_make_float(const float value)
+{
+ ExessVariant v = {EXESS_FLOAT, .value.as_float = value};
+ return v;
+}
+
+ExessVariant
+exess_make_long(const int64_t value)
+{
+ ExessVariant v = {EXESS_LONG, .value.as_long = value};
+ return v;
+}
+
+ExessVariant
+exess_make_int(const int32_t value)
+{
+ ExessVariant v = {EXESS_INT, .value.as_int = value};
+ return v;
+}
+
+ExessVariant
+exess_make_short(const int16_t value)
+{
+ ExessVariant v = {EXESS_SHORT, .value.as_short = value};
+ return v;
+}
+
+ExessVariant
+exess_make_byte(const int8_t value)
+{
+ ExessVariant v = {EXESS_BYTE, .value.as_byte = value};
+ return v;
+}
+
+ExessVariant
+exess_make_ulong(const uint64_t value)
+{
+ ExessVariant v = {EXESS_ULONG, .value.as_ulong = value};
+ return v;
+}
+
+ExessVariant
+exess_make_uint(const uint32_t value)
+{
+ ExessVariant v = {EXESS_UINT, .value.as_uint = value};
+ return v;
+}
+
+ExessVariant
+exess_make_ushort(const uint16_t value)
+{
+ ExessVariant v = {EXESS_USHORT, .value.as_ushort = value};
+ return v;
+}
+
+ExessVariant
+exess_make_ubyte(const uint8_t value)
+{
+ ExessVariant v = {EXESS_UBYTE, .value.as_ubyte = value};
+ return v;
+}
+
+ExessVariant
+exess_make_duration(const ExessDuration value)
+{
+ ExessVariant v = {EXESS_DURATION, .value.as_duration = value};
+ return v;
+}
+
+ExessVariant
+exess_make_datetime(const ExessDateTime value)
+{
+ ExessVariant v = {EXESS_DATETIME, .value.as_datetime = value};
+ return v;
+}
+
+ExessVariant
+exess_make_time(const ExessTime value)
+{
+ ExessVariant v = {EXESS_TIME, .value.as_time = value};
+ return v;
+}
+
+ExessVariant
+exess_make_date(const ExessDate value)
+{
+ ExessVariant v = {EXESS_DATE, .value.as_date = value};
+ return v;
+}
+
+ExessVariant
+exess_make_hex(const ExessBlob blob)
+{
+ ExessVariant v = {EXESS_HEX, .value.as_blob = blob};
+ return v;
+}
+
+ExessVariant
+exess_make_base64(const ExessBlob blob)
+{
+ ExessVariant v = {EXESS_BASE64, .value.as_blob = blob};
+ return v;
+}
+
+// Accessors
+
+ExessStatus
+exess_get_status(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_NOTHING ? variant->value.as_status
+ : EXESS_SUCCESS;
+}
+const bool*
+exess_get_boolean(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_BOOLEAN ? &variant->value.as_bool : NULL;
+}
+
+const double*
+exess_get_double(const ExessVariant* const variant)
+{
+ return (variant->datatype == EXESS_DECIMAL ||
+ variant->datatype == EXESS_DOUBLE)
+ ? &variant->value.as_double
+ : NULL;
+}
+
+const float*
+exess_get_float(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_FLOAT ? &variant->value.as_float : NULL;
+}
+
+const int64_t*
+exess_get_long(const ExessVariant* const variant)
+{
+ return (variant->datatype >= EXESS_INTEGER && variant->datatype <= EXESS_LONG)
+ ? &variant->value.as_long
+ : NULL;
+}
+
+const int32_t*
+exess_get_int(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_INT ? &variant->value.as_int : NULL;
+}
+
+const int16_t*
+exess_get_short(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_SHORT ? &variant->value.as_short : NULL;
+}
+
+const int8_t*
+exess_get_byte(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_BYTE ? &variant->value.as_byte : NULL;
+}
+
+const uint64_t*
+exess_get_ulong(const ExessVariant* const variant)
+{
+ return (variant->datatype == EXESS_NON_NEGATIVE_INTEGER ||
+ variant->datatype == EXESS_ULONG ||
+ variant->datatype == EXESS_POSITIVE_INTEGER)
+ ? &variant->value.as_ulong
+ : NULL;
+}
+
+const uint32_t*
+exess_get_uint(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_UINT ? &variant->value.as_uint : NULL;
+}
+
+const uint16_t*
+exess_get_ushort(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_USHORT ? &variant->value.as_ushort : NULL;
+}
+
+const uint8_t*
+exess_get_ubyte(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_UBYTE ? &variant->value.as_ubyte : NULL;
+}
+
+const ExessBlob*
+exess_get_blob(const ExessVariant* const variant)
+{
+ return (variant->datatype == EXESS_HEX || variant->datatype == EXESS_BASE64)
+ ? &variant->value.as_blob
+ : NULL;
+}
+
+const ExessDuration*
+exess_get_duration(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_DURATION ? &variant->value.as_duration
+ : NULL;
+}
+
+const ExessDateTime*
+exess_get_datetime(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_DATETIME ? &variant->value.as_datetime
+ : NULL;
+}
+
+const ExessTime*
+exess_get_time(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_TIME ? &variant->value.as_time : NULL;
+}
+
+const ExessDate*
+exess_get_date(const ExessVariant* const variant)
+{
+ return variant->datatype == EXESS_DATE ? &variant->value.as_date : NULL;
+}
+
+// Reading and Writing
+
+ExessResult
+exess_read_variant(ExessVariant* const out,
+ ExessDatatype datatype,
+ const char* const str)
+{
+ ExessResult r = {EXESS_UNSUPPORTED, 0};
+
+ out->datatype = datatype;
+
+ switch (datatype) {
+ case EXESS_NOTHING:
+ break;
+ case EXESS_BOOLEAN:
+ return exess_read_boolean(&out->value.as_bool, str);
+ case EXESS_DECIMAL:
+ return exess_read_decimal(&out->value.as_double, str);
+ case EXESS_DOUBLE:
+ return exess_read_double(&out->value.as_double, str);
+ case EXESS_FLOAT:
+ return exess_read_float(&out->value.as_float, str);
+ case EXESS_INTEGER:
+ return exess_read_long(&out->value.as_long, str);
+
+ case EXESS_NON_POSITIVE_INTEGER:
+ if (!(r = exess_read_long(&out->value.as_long, str)).status) {
+ if (out->value.as_long > 0) {
+ return result(EXESS_OUT_OF_RANGE, r.count);
+ }
+ }
+ break;
+
+ case EXESS_NEGATIVE_INTEGER:
+ if (!(r = exess_read_long(&out->value.as_long, str)).status) {
+ if (out->value.as_long >= 0) {
+ return result(EXESS_OUT_OF_RANGE, r.count);
+ }
+ }
+ break;
+
+ case EXESS_LONG:
+ return exess_read_long(&out->value.as_long, str);
+ case EXESS_INT:
+ return exess_read_int(&out->value.as_int, str);
+ case EXESS_SHORT:
+ return exess_read_short(&out->value.as_short, str);
+ case EXESS_BYTE:
+ return exess_read_byte(&out->value.as_byte, str);
+ case EXESS_NON_NEGATIVE_INTEGER:
+ case EXESS_ULONG:
+ return exess_read_ulong(&out->value.as_ulong, str);
+ case EXESS_UINT:
+ return exess_read_uint(&out->value.as_uint, str);
+ case EXESS_USHORT:
+ return exess_read_ushort(&out->value.as_ushort, str);
+ case EXESS_UBYTE:
+ return exess_read_ubyte(&out->value.as_ubyte, str);
+
+ case EXESS_POSITIVE_INTEGER:
+ if (!(r = exess_read_ulong(&out->value.as_ulong, str)).status) {
+ if (out->value.as_ulong <= 0) {
+ return result(EXESS_OUT_OF_RANGE, r.count);
+ }
+ }
+ break;
+
+ case EXESS_DURATION:
+ return exess_read_duration(&out->value.as_duration, str);
+ case EXESS_DATETIME:
+ return exess_read_datetime(&out->value.as_datetime, str);
+ case EXESS_TIME:
+ return exess_read_time(&out->value.as_time, str);
+ case EXESS_DATE:
+ return exess_read_date(&out->value.as_date, str);
+ case EXESS_HEX:
+ return exess_read_hex(&out->value.as_blob, str);
+ case EXESS_BASE64:
+ return exess_read_base64(&out->value.as_blob, str);
+ }
+
+ return r;
+}
+
+ExessResult
+exess_write_variant(const ExessVariant variant,
+ const size_t buf_size,
+ char* const buf)
+{
+ if (buf_size > 0) {
+ buf[0] = '\0';
+ }
+
+ switch (variant.datatype) {
+ case EXESS_NOTHING:
+ break;
+ case EXESS_BOOLEAN:
+ return exess_write_boolean(variant.value.as_bool, buf_size, buf);
+ case EXESS_DECIMAL:
+ return exess_write_decimal(variant.value.as_double, buf_size, buf);
+ case EXESS_DOUBLE:
+ return exess_write_double(variant.value.as_double, buf_size, buf);
+ case EXESS_FLOAT:
+ return exess_write_float(variant.value.as_float, buf_size, buf);
+ case EXESS_INTEGER:
+ case EXESS_NON_POSITIVE_INTEGER:
+ case EXESS_NEGATIVE_INTEGER:
+ case EXESS_LONG:
+ return exess_write_long(variant.value.as_long, buf_size, buf);
+ case EXESS_INT:
+ return exess_write_int(variant.value.as_int, buf_size, buf);
+ case EXESS_SHORT:
+ return exess_write_short(variant.value.as_short, buf_size, buf);
+ case EXESS_BYTE:
+ return exess_write_byte(variant.value.as_byte, buf_size, buf);
+ case EXESS_NON_NEGATIVE_INTEGER:
+ case EXESS_ULONG:
+ return exess_write_ulong(variant.value.as_ulong, buf_size, buf);
+ case EXESS_UINT:
+ return exess_write_uint(variant.value.as_uint, buf_size, buf);
+ case EXESS_USHORT:
+ return exess_write_ushort(variant.value.as_ushort, buf_size, buf);
+ case EXESS_UBYTE:
+ return exess_write_ubyte(variant.value.as_ubyte, buf_size, buf);
+ case EXESS_POSITIVE_INTEGER:
+ return exess_write_ulong(variant.value.as_ulong, buf_size, buf);
+ case EXESS_DURATION:
+ return exess_write_duration(variant.value.as_duration, buf_size, buf);
+ case EXESS_DATETIME:
+ return exess_write_datetime(variant.value.as_datetime, buf_size, buf);
+ case EXESS_TIME:
+ return exess_write_time(variant.value.as_time, buf_size, buf);
+ case EXESS_DATE:
+ return exess_write_date(variant.value.as_date, buf_size, buf);
+ case EXESS_HEX:
+ if (variant.value.as_blob.data) {
+ return exess_write_hex(variant.value.as_blob.size,
+ (void*)variant.value.as_blob.data,
+ buf_size,
+ buf);
+ }
+ break;
+ case EXESS_BASE64:
+ if (variant.value.as_blob.data) {
+ return exess_write_base64(variant.value.as_blob.size,
+ (void*)variant.value.as_blob.data,
+ buf_size,
+ buf);
+ }
+ break;
+ }
+
+ return end_write(EXESS_BAD_VALUE, buf_size, buf, 0);
+}