Async-Trampoline

 view release on metacpan or  search on metacpan

lib/Async/Trampoline.xs++  view on Meta::CPAN

                continuation = async_from_sv(aTHX_ (SV*) data.at(0));

            if (!continuation)
                throw std::runtime_error(
                        "generator Async must have Async as first value");

            AsyncRef next_map = make_gen_map(
                    aTHX_
                    std::move(continuation), InvokeCV(body));

            DestructibleTuple body_args = destructible_tuple_tail(1, data);

            AsyncRef result = body(body_args);

            return make_async_yield(aTHX_ std::move(next_map), std::move(result));
        }
    } gen_map_thunk { std::move(body) };

    AsyncRef await = Async::alloc();
    await->set_to_Thunk(gen_map_thunk, std::move(gen));
    return await;
}

static AsyncRef concat_fold_right(pTHX_ ssize_t i, AV* array)
{
    if (i > av_len(array))
        return nullptr;

    AsyncRef left;
    if (SV** left_sv = av_fetch(array, i, 0))
        left = async_from_sv(aTHX_ *left_sv);

    if (!left)
        throw std::runtime_error(
                "all dependencies must be Asyncs");

    AsyncRef right = concat_fold_right(aTHX_ i + 1, array);

    if (!right)
        return left;

    AsyncRef concat = Async::alloc();
    concat->set_to_Concat(std::move(left), std::move(right));
    return concat;
};


#define ASYNC_TYPE_GET(name) (static_cast<I32>(Async_Type::name))
#define ASYNC_TYPE_CATEGORY_COMPLETE    ASYNC_TYPE_GET(CATEGORY_COMPLETE)
#define ASYNC_TYPE_CATEGORY_RESOLVED    ASYNC_TYPE_GET(CATEGORY_RESOLVED)
#define ASYNC_TYPE_IS_CANCEL            ASYNC_TYPE_GET(IS_CANCEL)
#define ASYNC_TYPE_IS_ERROR             ASYNC_TYPE_GET(IS_ERROR)
#define ASYNC_TYPE_IS_VALUE             ASYNC_TYPE_GET(IS_VALUE)

MODULE = Async::Trampoline PACKAGE = Async::Trampoline

void
Async::run_until_completion()
    INIT:
        CXX_TRY
    PPCODE:
    {
        Async_run_until_completion(THIS);

        Async& result = THIS->ptr_follow();

        if (!result.has_category(Async_Type::CATEGORY_COMPLETE))
        {
            croak(  "run_until_completion() did not complete " ASYNC_FORMAT,
                    ASYNC_FORMAT_ARGS(&result));
        }
        else if (result.has_type(Async_Type::IS_CANCEL))
        {
            croak("run_until_completion(): Async was cancelled");
        }
        else if (result.has_type(Async_Type::IS_ERROR))
        {
            croak_sv((SV*) result.as_error.data);
        }
        else if (result.has_type(Async_Type::IS_VALUE))
        {
            ASYNC_LOG_DEBUG("returning to Perl: " ASYNC_FORMAT "\n",
                    ASYNC_FORMAT_ARGS(&result));

            DestructibleTuple& values = result.as_value;
            XSprePUSH;  // to fix weird XS+PPCODE argument handling
            EXTEND(SP, static_cast<ssize_t>(values.size));
            for (auto value : values)
            {
                ASYNC_LOG_DEBUG("  - " DESTRUCTIBLE_FORMAT "\n",
                        DESTRUCTIBLE_FORMAT_ARGS_BORROWED(values.vtable, value));
                PUSHs(sv_mortalcopy((SV*) value));
            }

            ASYNC_LOG_DEBUG("result end\n");

            XSRETURN(values.size);
        }
        else
        {
            assert(0);
        }
    }
    CXX_CATCH

void
Async::DESTROY()
    INIT:
        CXX_TRY
    CODE:
        THIS->unref();
    CLEANUP:
        CXX_CATCH

Async*
async(body)
        CV* body
    PROTOTYPE: &
    INIT:
        CXX_TRY
    CODE:
    {
        AsyncRef self = Async::alloc();
        self->set_to_Thunk(InvokeCV{aTHX_ body}, nullptr);
        RETVAL = std::move(self).ptr_with_ownership();
    }
    OUTPUT: RETVAL
    CLEANUP:
        CXX_CATCH

Async*
await(deps, body)
        SV* deps
        CV* body
    PROTOTYPE: $&
    INIT:
        CXX_TRY
    CODE:
    {
        auto get_arrayref = [](SV* sv) -> AV*
        {
            if (!SvROK(sv))
                return nullptr;

            sv = SvRV(sv);



( run in 0.682 second using v1.01-cache-2.11-cpan-71847e10f99 )