Download
64 lines 1.6 KiBTomoModified 2025-11-29 raw
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
# This is a coroutine library that uses libaco (https://libaco.org)
#
# Lua programmers will recognize this as similar to Lua's stackful coroutines.
#
# Async/Await programmers will weep at its beauty and gnash their teeth and
# rend their garments in despair at what they could have had.

use ./aco.h
use ./aco.c
use ./acoyield.S

func main()
    say("Example usage")
    co := Coroutine(func()
        say("I'm in the coroutine!")
        yield()
        say("I'm back in the coroutine!")
    )
    >> co
    say("I'm in the main func")
    >> co.resume()
    say("I'm back in the main func")
    >> co.resume()
    say("I'm back in the main func again")
    >> co.resume()

_main_co : @Memory? = none
_shared_stack : @Memory? = none

struct Coroutine(co:@Memory)
    convert(fn:func() -> Coroutine)
        if not _main_co
            _init()

        main_co := _main_co
        shared_stack := _shared_stack
        aco_ptr := C_code:@Memory`
            aco_create(@main_co, @shared_stack, 0, (void*)@fn.fn, @fn.userdata)
        `
        return Coroutine(aco_ptr)

    func is_finished(co:Coroutine->Bool; inline)
        return C_code:Bool`((aco_t*)@(co.co))->is_finished`

    func resume(co:Coroutine->Bool)
        if co.is_finished()
            return no
        C_code `aco_resume(@co.co);`
        return yes

func _init()
    C_code `
        aco_set_allocator(GC_malloc, NULL);
        aco_thread_init(aco_exit_fn);
    `
    _main_co = C_code:@Memory`aco_create(NULL, NULL, 0, NULL, NULL)`

    _shared_stack = C_code:@Memory`aco_shared_stack_new(0)`

func yield(; inline)
    C_code `
        aco_yield();
    `