Mirai's Miscellaneous Misadventures

M38 / core / coroutines.c

// copyright 2022 zamfofex
// license: AGPLv3 or later

#include <mimimi/coroutines.h>
#include <mimimi/coroutine-providers.h>
#include <mimimi/compound-behaviors.h>
#include <mimimi/behaviors.h>
#include <mimimi/allocators.h>

struct mimimi_coroutine
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_behavior *compound0;
	struct mimimi_behavior *compound;
	struct mimimi_behavior *result;
	void (*start)(struct mimimi_behavior *behavior, struct mimimi_behavior *compound, void *data);
	void *data;
	unsigned char finished;
};

static void mimimi_coroutine_start(struct mimimi_behavior *behavior, void *data)
{
	struct mimimi_coroutine *coroutine = data;
	(*coroutine->start)(behavior, coroutine->compound, coroutine->data);
}

static void mimimi_coroutine_finish_behavior(void *data)
{
	struct mimimi_coroutine *coroutine = data;
	mimimi_compound_remove(coroutine->compound0, coroutine->result);
	(*coroutine->behavior->finish)(coroutine->behavior->data);
	(*coroutine->compound->finish)(coroutine->compound->data);
	mimimi_deallocate(coroutine->allocator, coroutine->result);
	mimimi_deallocate(coroutine->allocator, coroutine);
}

static void mimimi_coroutine_finish(void *data)
{
	struct mimimi_coroutine *coroutine = data;
	coroutine->finished = 1;
	if (mimimi_compound_empty(coroutine->compound) != 0)
		mimimi_coroutine_finish_behavior(data);
}

static void mimimi_coroutine_behave(void *data)
{
	struct mimimi_coroutine *coroutine = data;
	if (coroutine->finished == 0)
		(*coroutine->behavior->behave)(coroutine->behavior->data);
	(*coroutine->compound->behave)(coroutine->compound->data);
	
	if (coroutine->finished != 0)
	if (mimimi_compound_empty(coroutine->compound) != 0)
		mimimi_coroutine_finish_behavior(data);
}

void mimimi_coroutine(struct mimimi_coroutine_provider *coroutines, struct mimimi_behavior *compound, void (*start)(struct mimimi_behavior *behavior, struct mimimi_behavior *compound, void *data), void *data, struct mimimi_allocator *allocator)
{
	struct mimimi_coroutine *coroutine = mimimi_allocate(allocator, sizeof *coroutine);
	coroutine->start = start;
	coroutine->data = data;
	coroutine->allocator = allocator;
	coroutine->compound0 = compound;
	coroutine->compound = mimimi_compound_behavior(allocator);
	coroutine->finished = 0;
	
	struct mimimi_behavior *behavior = (*coroutines->create)(&mimimi_coroutine_start, &mimimi_coroutine_finish, coroutine, coroutines->data);
	coroutine->behavior = behavior;
	
	struct mimimi_behavior *result = mimimi_allocate(allocator, sizeof *result);
	result->behave = &mimimi_coroutine_behave;
	result->finish = &mimimi_coroutine_finish_behavior;
	result->data = coroutine;
	coroutine->result = result;
	
	mimimi_compound(compound, result);
}