#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

typedef struct {
  uint32_t x, y;
} struct_t;

inline char * struct_to_string(char * str, struct_t s) {
  return str + sprintf(str, "{x: %u, y: %u}", s.x, s.y);
}

inline char * int_to_string(char * str, int i) {
  return str + sprintf(str, "%i", i);
}

inline char * string_to_string(char * str, char * s) {
  uint64_t len = strlen(s);
  return memcpy(str, s, len) + len;
}

#define to(type, x) ({__auto_type ret = x; *(type *)((void *) &ret);})

#define to_string(str, x) _Generic((x),\
  int : int_to_string(str, to(int, x)),\
  char * : string_to_string(str, to(char *, x)),\
  struct_t : struct_to_string(str, to(struct_t, x))\
)

#define FIRST(a, ...) a
#define SECOND(a, b, ...) b

#define EMPTY()

#define EVAL(...) EVAL32(__VA_ARGS__)
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__

#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define DEFER3(m) m EMPTY EMPTY EMPTY()()()
#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()()()

#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1

#define CAT(a,b) a ## b

#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()

#define BOOL(x) NOT(NOT(x))

#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)

#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...)             _IF_0_ELSE

#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__

#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0

#define MAP(m, first, ...)           \
  m(first)                           \
  IF_ELSE(HAS_ARGS(__VA_ARGS__))(    \
    DEFER2(_MAP)()(m, __VA_ARGS__)   \
  )(                                 \
    /* Do nothing, just terminate */ \
  )
#define _MAP() MAP

#define op(x) str = to_string(str, x);

#define fprintf_proturbo(file, ...) ({\
  char * str = malloc(1000500), * s = str;\
  EVAL(MAP(op, __VA_ARGS__));\
  *str = 0;\
  int i = fprintf(file, "%s", s);\
  free(s);\
  i;\
})


int main(void) {
  struct_t st = {10, 23};
  fprintf_proturbo(stderr, 234235, " ", 523523, "\n", st, " ", 423523, "\n");
}