AnyEvent-XSPromises
view release on metacpan or search on metacpan
XSPromises.xs view on Meta::CPAN
SV** result;
int count;
int refs;
};
struct xspr_promise_s {
xspr_promise_state_t state;
int refs;
union {
struct {
xspr_callback_t** callbacks;
int callbacks_count;
} pending;
struct {
xspr_result_t *result;
} finished;
};
};
struct xspr_callback_queue_s {
xspr_promise_t* origin;
xspr_callback_t* callback;
XSPromises.xs view on Meta::CPAN
while (MY_CXT.queue_head != NULL) {
/* Save some typing... */
xspr_callback_queue_t *cur = MY_CXT.queue_head;
/* Process the callback. This could trigger some Perl code, meaning we
* could end up with additional queue entries after this */
xspr_callback_process(aTHX_ cur->callback, cur->origin);
/* Free-ing the callback structure could theoretically trigger DESTROY subs,
* enqueueing new callbacks, so we can't assume the loop ends here! */
MY_CXT.queue_head = cur->next;
if (cur->next == NULL) {
MY_CXT.queue_tail = NULL;
}
/* Destroy the structure */
xspr_callback_free(aTHX_ cur->callback);
xspr_promise_decref(aTHX_ cur->origin);
Safefree(cur);
}
XSPromises.xs view on Meta::CPAN
/* Invoke the user's perl code. We need to be really sure this doesn't return early via croak/next/etc. */
xspr_result_t* xspr_invoke_perl(pTHX_ SV* perl_fn, SV** input, int input_count)
{
dSP;
int count, i;
SV* error;
xspr_result_t* result;
if (!SvROK(perl_fn)) {
return xspr_result_from_error(aTHX_ "promise callbacks need to be a CODE reference");
}
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, input_count);
for (i = 0; i < input_count; i++) {
PUSHs(input[i]);
}
PUTBACK;
/* Clear $_ so that callbacks don't end up talking to each other by accident */
SAVE_DEFSV;
DEFSV_set(sv_newmortal());
count = call_sv(perl_fn, G_EVAL|G_ARRAY);
SPAGAIN;
error = ERRSV;
if (SvTRUE(error)) {
result = xspr_result_new(aTHX_ XSPR_RESULT_REJECTED, 1);
result->result[0] = newSVsv(error);
XSPromises.xs view on Meta::CPAN
}
Safefree(result->result);
Safefree(result);
}
}
/* Transitions a promise from pending to finished, using the given result */
void xspr_promise_finish(pTHX_ xspr_promise_t* promise, xspr_result_t* result)
{
assert(promise->state == XSPR_STATE_PENDING);
xspr_callback_t** pending_callbacks = promise->pending.callbacks;
int count = promise->pending.callbacks_count;
promise->state = XSPR_STATE_FINISHED;
promise->finished.result = result;
xspr_result_incref(aTHX_ promise->finished.result);
int i;
for (i = 0; i < count; i++) {
xspr_queue_add(aTHX_ pending_callbacks[i], promise);
}
Safefree(pending_callbacks);
}
/* Create a new xspr_result_t object with the given number of item slots */
xspr_result_t* xspr_result_new(pTHX_ xspr_result_state_t state, int count)
{
xspr_result_t* result;
Newxz(result, 1, xspr_result_t);
Newxz(result->result, count, SV*);
result->state = state;
result->refs = 1;
XSPromises.xs view on Meta::CPAN
{
(promise->refs)++;
}
/* Decrements the ref count for the xspr_promise_t, freeing the structure if needed */
void xspr_promise_decref(pTHX_ xspr_promise_t *promise)
{
if (--(promise->refs) == 0) {
if (promise->state == XSPR_STATE_PENDING) {
/* XXX: is this a bad thing we should warn for? */
int count = promise->pending.callbacks_count;
xspr_callback_t **callbacks = promise->pending.callbacks;
int i;
for (i = 0; i < count; i++) {
xspr_callback_free(aTHX_ callbacks[i]);
}
Safefree(callbacks);
} else if (promise->state == XSPR_STATE_FINISHED) {
xspr_result_decref(aTHX_ promise->finished.result);
} else {
assert(0);
}
Safefree(promise);
}
XSPromises.xs view on Meta::CPAN
callback->type = XSPR_CALLBACK_CHAIN;
callback->chain = chain;
xspr_promise_incref(aTHX_ chain);
return callback;
}
/* Adds a then to the promise. Takes ownership of the callback */
void xspr_promise_then(pTHX_ xspr_promise_t* promise, xspr_callback_t* callback)
{
if (promise->state == XSPR_STATE_PENDING) {
promise->pending.callbacks_count++;
Renew(promise->pending.callbacks, promise->pending.callbacks_count, xspr_callback_t*);
promise->pending.callbacks[promise->pending.callbacks_count-1] = callback;
} else if (promise->state == XSPR_STATE_FINISHED) {
xspr_queue_add(aTHX_ callback, promise);
} else {
assert(0);
}
}
/* Returns a promise if the given SV is a thenable. Ownership handed to the caller! */
( run in 0.923 second using v1.01-cache-2.11-cpan-9b1e4054eb1 )