diff options
Diffstat (limited to 'src/stdlib/metamethods.c')
| -rw-r--r-- | src/stdlib/metamethods.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/stdlib/metamethods.c b/src/stdlib/metamethods.c new file mode 100644 index 00000000..c0e11cfc --- /dev/null +++ b/src/stdlib/metamethods.c @@ -0,0 +1,124 @@ +// Metamethods are methods that all types share for hashing, equality, comparison, and textifying + +#include <stdint.h> +#include <string.h> + +#include "arrays.h" +#include "bools.h" +#include "bytes.h" +#include "functiontype.h" +#include "integers.h" +#include "metamethods.h" +#include "optionals.h" +#include "pointers.h" +#include "siphash.h" +#include "tables.h" +#include "text.h" +#include "types.h" +#include "util.h" + +PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type) +{ + if (type->metamethods.hash) + return type->metamethods.hash(obj, type); + + return siphash24((void*)obj, (size_t)(type->size)); +} + +PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo_t *type) +{ + if (x == y) return 0; + + if (type->metamethods.compare) + return type->metamethods.compare(x, y, type); + + return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size)); +} + +PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_t *type) +{ + if (x == y) return true; + + if (type->metamethods.equal) + return type->metamethods.equal(x, y, type); + + return (generic_compare(x, y, type) == 0); +} + +public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type) +{ + if (!type->metamethods.as_text) + fail("No text metamethod provided for type!"); + + return type->metamethods.as_text(obj, colorize, type); +} + +public void _serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) +{ + if (type->metamethods.serialize) + return type->metamethods.serialize(obj, out, pointers, type); + + fwrite(obj, (size_t)type->size, 1, out); +} + +public Array_t generic_serialize(const void *x, const TypeInfo_t *type) +{ + char *buf = NULL; + size_t size = 0; + FILE *stream = open_memstream(&buf, &size); + Table_t pointers = {}; + _serialize(x, stream, &pointers, type); + fclose(stream); + Array_t bytes = { + .data=GC_MALLOC_ATOMIC(size), + .length=(int64_t)size, + .stride=1, + .atomic=1, + }; + memcpy(bytes.data, buf, size); + free(buf); + return bytes; +} + +public void _deserialize(FILE *input, void *outval, Array_t *pointers, const TypeInfo_t *type) +{ + if (type->metamethods.deserialize) { + type->metamethods.deserialize(input, outval, pointers, type); + return; + } + + fread(outval, (size_t)type->size, 1, input); +} + +public void generic_deserialize(Array_t bytes, void *outval, const TypeInfo_t *type) +{ + if (bytes.stride != 1) + Array$compact(&bytes, 1); + + FILE *input = fmemopen(bytes.data, (size_t)bytes.length, "r"); + Array_t pointers = {}; + _deserialize(input, outval, &pointers, type); + fclose(input); +} + +public int generic_print(const void *obj, bool colorize, const TypeInfo_t *type) +{ + Text_t text = generic_as_text(obj, colorize, type); + return Text$print(stdout, text) + printf("\n"); +} + +__attribute__((noreturn)) +public void cannot_serialize(const void*, FILE*, Table_t*, const TypeInfo_t *type) +{ + Text_t typestr = generic_as_text(NULL, false, type); + fail("Values of type %k cannot be serialized or deserialized!", &typestr); +} + +__attribute__((noreturn)) +public void cannot_deserialize(FILE*, void*, Array_t*, const TypeInfo_t *type) +{ + Text_t typestr = generic_as_text(NULL, false, type); + fail("Values of type %k cannot be serialized or deserialized!", &typestr); +} + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 |
