#ifndef FWD_H
#define FWD_H

#include <fwd/mod.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>

#ifndef FWD_FRAME_SIZE
#error "no frame size defined, internal compiler error"
#endif

/* should probably add some compiler checks but good enough for now */
#define FWD_MUSTTAIL [[clang::musttail]]

typedef void *fwd_stack_t;
typedef void *fwd_args_t;
typedef fwd_stack_t (*fwd_call_t)(fwd_stack_t, fwd_args_t);

typedef struct {
	fwd_call_t call;
	fwd_args_t args;
} fwd_closure_t;

typedef struct {} fwd_start_t;

static inline fwd_stack_t create_fwd_stack()
{
	return NULL;
}

static inline void *fwd_stack_alloc(fwd_stack_t *top)
{
	if (*top) {
		fwd_stack_t *prev = *top;
		*top = *prev;
		return prev + 1;
	}

	fwd_stack_t *new = malloc(FWD_FRAME_SIZE + sizeof(fwd_stack_t));
	*new = NULL;
	return new + 1;
}

static inline void fwd_stack_free(fwd_stack_t *stack, void *loc)
{
	fwd_stack_t *freed = (fwd_stack_t *)loc - 1;
	*freed = *stack;
	*stack = freed;
}

static inline void destroy_fwd_stack(fwd_stack_t *stack)
{
	fwd_stack_t *prev = *stack;
	while (prev) {
		fwd_stack_t *cur = prev;
		prev = *cur;
		free(cur);
	}
}

#define FWD_CONTAINER_OF(ptr, type, member) \
	(type *)((char *)(ptr) - offsetof(type, member))

#endif /* FWD_H */