#pragma once #include "md.h" typedef struct { MD_b8 failed; MD_String8 why; } SerError; typedef struct { MD_u8 *data; // set to 0 to dry run and get maximum size. max doesn't matter in this case MD_u64 cur; MD_u64 max; MD_Arena *arena; // allocate everything new on this, so that if serialization fails allocations can be undone // Serializing should never allocate. So this can be null when you serialize int version; SerError cur_error; MD_Arena *error_arena; // all error messages are allocated here MD_b8 serializing; } SerState; void ser_bytes(SerState *ser, MD_u8 *bytes, MD_u64 bytes_size) { if(!ser->data && !ser->serializing) { ser->cur_error = (SerError){.failed = true, .why = MD_S8Lit("Deserializing but the data is null")}; } if(!ser->cur_error.failed) { if(ser->data) { // maximum doesn't matter unless writing to data if(ser->cur + bytes_size > ser->max) { ser->cur_error = (SerError){.failed = true, .why = MD_S8Lit("Too big bro")}; } else { if(ser->serializing) { memcpy(ser->data + ser->cur, bytes, bytes_size); } else { memcpy(bytes, ser->data + ser->cur, bytes_size); } } } ser->cur += bytes_size; } } #define SER_MAKE_FOR_TYPE(type) void ser_##type(SerState *ser, type *into) \ { \ ser_bytes(ser, (MD_u8*)into, sizeof(*into)); \ } SER_MAKE_FOR_TYPE(int); SER_MAKE_FOR_TYPE(MD_u64); // Embeds the string into the serialized binary. When deserializing copies the // deserialized data onto a newly allocated buffer void ser_MD_String8(SerState *ser, MD_String8 *s, MD_Arena *allocate_onto) { ser_MD_u64(ser, &s->size); if(ser->serializing) { ser_bytes(ser, s->str, s->size); } else { s->str = MD_ArenaPush(allocate_onto, s->size); ser_bytes(ser, s->str, s->size); } }