diff --git a/m-variant.h b/m-variant.h index 2e2f78c0..78076a2c 100644 --- a/m-variant.h +++ b/m-variant.h @@ -83,6 +83,10 @@ (VARIANTI_DEFINE_OUT_STR(name, __VA_ARGS__),) \ VARIANTI_IF_ALL2(IN_STR, INIT, __VA_ARGS__) \ (VARIANTI_DEFINE_IN_STR(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(OUT_SERIAL, __VA_ARGS__) \ + (VARIANTI_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL2(IN_SERIAL, INIT, __VA_ARGS__) \ + (VARIANTI_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \ VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ (VARIANTI_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \ VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ @@ -107,9 +111,11 @@ #define VARIANTI_GET_HASH(f,t,o) M_GET_HASH o #define VARIANTI_GET_EQUAL(f,t,o) M_GET_EQUAL o #define VARIANTI_GET_STR(f,t,o) M_GET_GET_STR o +#define VARIANTI_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o #define VARIANTI_GET_OUT_STR(f,t,o) M_GET_OUT_STR o #define VARIANTI_GET_IN_STR(f,t,o) M_GET_IN_STR o -#define VARIANTI_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o +#define VARIANTI_GET_OUT_SERIAL(f,t,o) M_GET_OUT_SERIAL o +#define VARIANTI_GET_IN_SERIAL(f,t,o) M_GET_IN_SERIAL o #define VARIANTI_GET_SWAP(f,t,o) M_GET_SWAP o #define VARIANTI_CALL_INIT(t, ...) M_APPLY_API(VARIANTI_GET_INIT t, VARIANTI_GET_OPLIST t, __VA_ARGS__) @@ -122,9 +128,11 @@ #define VARIANTI_CALL_HASH(t, ...) M_APPLY_API(VARIANTI_GET_HASH t, VARIANTI_GET_OPLIST t, __VA_ARGS__) #define VARIANTI_CALL_EQUAL(t, ...) M_APPLY_API(VARIANTI_GET_EQUAL t, VARIANTI_GET_OPLIST t, __VA_ARGS__) #define VARIANTI_CALL_GET_STR(t, ...) M_APPLY_API(VARIANTI_GET_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__) +#define VARIANTI_CALL_PARSE_STR(t, ...) M_APPLY_API(VARIANTI_GET_PARSE_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__) #define VARIANTI_CALL_OUT_STR(t, ...) M_APPLY_API(VARIANTI_GET_OUT_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__) #define VARIANTI_CALL_IN_STR(t, ...) M_APPLY_API(VARIANTI_GET_IN_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__) -#define VARIANTI_CALL_PARSE_STR(t, ...) M_APPLY_API(VARIANTI_GET_PARSE_STR t, VARIANTI_GET_OPLIST t, __VA_ARGS__) +#define VARIANTI_CALL_OUT_SERIAL(t, ...) M_APPLY_API(VARIANTI_GET_OUT_SERIAL t, VARIANTI_GET_OPLIST t, __VA_ARGS__) +#define VARIANTI_CALL_IN_SERIAL(t, ...) M_APPLY_API(VARIANTI_GET_IN_SERIAL t, VARIANTI_GET_OPLIST t, __VA_ARGS__) #define VARIANTI_CALL_SWAP(t, ...) M_APPLY_API(VARIANTI_GET_SWAP t, VARIANTI_GET_OPLIST t, __VA_ARGS__) #define VARIANTI_DEFINE_TYPE(name, ...) \ @@ -402,6 +410,46 @@ break; +#define VARIANTI_DEFINE_PARSE_STR(name, ...) \ + static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \ + const char str[], \ + const char **endp) { \ + assert (str != NULL && el != NULL); \ + bool success = false; \ + char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \ + int c = *str++; \ + unsigned int i = 0; \ + M_C(name, _clean)(el); \ + if (c != '@') goto exit; \ + /* First read the name of the type */ \ + c = *str++; \ + while (c != '@' && c != 0 && i < sizeof(variantTypeBuf) - 1) { \ + variantTypeBuf[i++] = c; \ + c = *str++; \ + } \ + if (c != '@') goto exit; \ + variantTypeBuf[i++] = 0; \ + assert(i < sizeof(variantTypeBuf)); \ + /* In function of the type */ \ + if (strcmp(variantTypeBuf, "EMPTY") == 0) { \ + el->type = M_C(name, _EMPTY); \ + } \ + M_MAP2(VARIANTI_DEFINE_PARSE_STR_FUNC , name, __VA_ARGS__) \ + else goto exit; \ + success = (*str++ == '@'); \ + exit: \ + if (endp) *endp = str; \ + return success; \ + } +#define VARIANTI_DEFINE_PARSE_STR_FUNC(name, a) \ + else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \ + el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ + VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ + bool b = VARIANTI_CALL_PARSE_STR(a, el -> value . VARIANTI_GET_FIELD a, str, &str); \ + if (!b) goto exit; \ + } + + #define VARIANTI_DEFINE_OUT_STR(name, ...) \ static inline void M_C(name, _out_str)(FILE *f, \ M_C(name,_t) const el) { \ @@ -424,10 +472,11 @@ static inline bool M_C(name, _in_str)(M_C(name,_t) el, \ FILE *f) { \ assert (f != NULL && el != NULL); \ - /* A buffer of 400 bytes should be more than enough for all variant names... */ \ - char variantTypeBuf[400]; \ + char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \ + M_C(name, _clean)(el); \ if (fgetc(f) != '@') return false; \ /* First read the name of the type */ \ + bool b = true; \ int c = fgetc(f); \ unsigned int i = 0; \ while (c != '@' && c != EOF && i < sizeof(variantTypeBuf) - 1) { \ @@ -437,63 +486,80 @@ if (c != '@') return false; \ variantTypeBuf[i++] = 0; \ assert(i < sizeof(variantTypeBuf)); \ - M_C(name, _clear)(el); \ /* In function of the type */ \ if (strcmp(variantTypeBuf, "EMPTY") == 0) { \ el->type = M_C(name, _EMPTY); \ } \ M_MAP2(VARIANTI_DEFINE_IN_STR_FUNC , name, __VA_ARGS__) \ - else return false; \ - return fgetc(f) == '@'; \ + else { b = false; } \ + return b && (fgetc(f) == '@'); \ } #define VARIANTI_DEFINE_IN_STR_FUNC(name, a) \ else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \ el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ - bool b = VARIANTI_CALL_IN_STR(a, el -> value . VARIANTI_GET_FIELD a, f); \ - if (!b) return false; \ + b = VARIANTI_CALL_IN_STR(a, el -> value . VARIANTI_GET_FIELD a, f); \ } -#define VARIANTI_DEFINE_PARSE_STR(name, ...) \ - static inline bool M_C(name, _parse_str)(M_C(name,_t) el, \ - const char str[], \ - const char **endp) { \ - assert (str != NULL && el != NULL); \ - bool success = false; \ - /* A buffer of 400 bytes should be more than enough for all variant names... */ \ - char variantTypeBuf[400]; \ - int c = *str++; \ - unsigned int i = 0; \ - if (c != '@') goto exit; \ - /* First read the name of the type */ \ - c = *str++; \ - while (c != '@' && c != 0 && i < sizeof(variantTypeBuf) - 1) { \ - variantTypeBuf[i++] = c; \ - c = *str++; \ +#define VARIANTI_STRINGIFY_NAME(a) \ + M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a) + +#define VARIANTI_DEFINE_OUT_SERIAL(name, ...) \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, \ + M_C(name,_t) const el) { \ + const int field_max = M_NARGS(__VA_ARGS__); \ + static const char *const field_name[] = \ + { M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \ + assert (f != NULL && f->interface != NULL && el != NULL); \ + m_serial_return_code_t ret; \ + switch (el->type) { \ + case M_C(name, _EMPTY): \ + return f->interface->write_variant_start(f, field_name, field_max, -1); \ + break; \ + M_MAP2(VARIANTI_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ } \ - if (c != '@') goto exit; \ - variantTypeBuf[i++] = 0; \ - assert(i < sizeof(variantTypeBuf)); \ - M_C(name, _clear)(el); \ - /* In function of the type */ \ - if (strcmp(variantTypeBuf, "EMPTY") == 0) { \ - el->type = M_C(name, _EMPTY); \ - } \ - M_MAP2(VARIANTI_DEFINE_PARSE_STR_FUNC , name, __VA_ARGS__) \ - else goto exit; \ - success = (*str++ == '@'); \ - exit: \ - if (endp) *endp = str; \ - return success; \ + ret |= f->interface->write_variant_end(f); \ + return ret & M_SERIAL_FAIL; \ } -#define VARIANTI_DEFINE_PARSE_STR_FUNC(name, a) \ - else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \ - el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ +#define VARIANTI_DEFINE_OUT_SERIAL_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + ret = f->interface->write_variant_start(f, field_name, field_max, \ + M_C4(name, _, VARIANTI_GET_FIELD a, _value) -1); \ + VARIANTI_CALL_OUT_SERIAL(a, f, el -> value . VARIANTI_GET_FIELD a); \ + break; + + +#define VARIANTI_DEFINE_IN_SERIAL(name, ...) \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(M_C(name,_t) el, \ + m_serial_read_t f) { \ + const int field_max = M_NARGS(__VA_ARGS__); \ + static const char *const field_name[] = \ + { M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \ + assert (f != NULL && f->interface != NULL && el != NULL); \ + m_serial_return_code_t ret; \ + int id = -1; \ + M_C(name, _clean)(el); \ + ret = f->interface->read_variant_start(f, field_name, field_max, &id); \ + if (ret != M_SERIAL_OK_CONTINUE) return ret; \ + assert (id >= 0 && id < field_max); \ + el->type = id+1; \ + switch (id+1) { \ + M_MAP2(VARIANTI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + if (ret != M_SERIAL_OK_DONE) \ + ret = f->interface->read_variant_end(f); \ + return ret; \ + } +#define VARIANTI_DEFINE_IN_SERIAL_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ - bool b = VARIANTI_CALL_PARSE_STR(a, el -> value . VARIANTI_GET_FIELD a, str, &str); \ - if (!b) goto exit; \ - } + ret = VARIANTI_CALL_IN_SERIAL(a, el -> value . VARIANTI_GET_FIELD a, f); \ + break; \ #define VARIANTI_DEFINE_CLEAN_FUNC(name, ...) \