Hypersonic

 view release on metacpan or  search on metacpan

lib/Hypersonic/UA.pm  view on Meta::CPAN

        ->line('SvREFCNT_inc(future);')
      ->endif
      ->blank
      ->line('PUTBACK;')
      ->line('FREETMPS; LEAVE;')
      ->blank
      ->comment('Start async request via Hypersonic::UA::Async')
      ->comment('Pass self_sv so start_request can auto-tick')
      ->line('ENTER; SAVETMPS;')
      ->line('PUSHMARK(SP);')
      ->line('XPUSHs(method_sv);')
      ->line('XPUSHs(url_sv);')
      ->line('XPUSHs(body_sv);')
      ->line('XPUSHs(future);')
      ->line('XPUSHs(self_sv);')
      ->line('PUTBACK;')
      ->blank
      ->line('count = call_pv("Hypersonic::UA::Async::start_request", G_SCALAR);')
      ->line('SPAGAIN;')
      ->blank
      ->line('int async_slot = -1;')
      ->if('count > 0')
        ->line('async_slot = POPi;')
      ->endif
      ->blank
      ->line('PUTBACK;')
      ->line('FREETMPS; LEAVE;')
      ->blank
      ->comment('Store async slot in UA for polling')
      ->if('async_slot >= 0')
        ->comment('Associate slot with self for run() to find')
        ->line('HV *ua_hv = (HV *)SvRV(self_sv);')
        ->line('AV *pending_av;')
        ->line('SV **pending_svp = hv_fetch(ua_hv, "_async_pending", 14, 0);')
        ->if('pending_svp && SvROK(*pending_svp)')
          ->line('pending_av = (AV *)SvRV(*pending_svp);')
        ->else
          ->line('pending_av = newAV();')
          ->line('hv_store(ua_hv, "_async_pending", 14, newRV_noinc((SV *)pending_av), 0);')
        ->endif
        ->line('av_push(pending_av, newSViv(async_slot));')
      ->endif
      ->blank
      ->line('ST(0) = sv_2mortal(future);')
      ->xs_return('1')
      ->xs_end
      ->blank;
}

sub gen_xs_run {
    my ($class, $builder) = @_;

    $builder->comment('Run all pending async requests to completion')
      ->xs_function('xs_ua_run')
      ->xs_preamble
      ->line('if (items < 1) croak("Usage: $ua->run()");')
      ->blank
      ->line('SV *self_sv = ST(0);')
      ->blank
      ->comment('Poll until all pending requests complete')
      ->line('int iterations = 0;')
      ->line('int max_iterations = 10000;')
      ->blank
      ->line('SPAGAIN;')
      ->line('while (iterations++ < max_iterations) {')
      ->line('    ENTER; SAVETMPS;')
      ->line('    PUSHMARK(SP);')
      ->line('    XPUSHs(self_sv);')
      ->line('    PUTBACK;')
      ->blank
      ->line('    call_method("pending", G_SCALAR);')
      ->line('    SPAGAIN;')
      ->blank
      ->line('    int pending = POPi;')
      ->line('    PUTBACK;')
      ->line('    FREETMPS; LEAVE;')
      ->blank
      ->line('    if (pending == 0) break;')
      ->blank
      ->comment('    Tick once')
      ->line('    ENTER; SAVETMPS;')
      ->line('    PUSHMARK(SP);')
      ->line('    XPUSHs(self_sv);')
      ->line('    PUTBACK;')
      ->line('    call_method("tick", G_DISCARD);')
      ->line('    FREETMPS; LEAVE;')
      ->line('}')
      ->blank
      ->xs_return('0')
      ->xs_end
      ->blank;
}

sub gen_xs_run_one {
    my ($class, $builder) = @_;

    $builder->comment('Run one async request to completion')
      ->xs_function('xs_ua_run_one')
      ->xs_preamble
      ->line('if (items < 2) croak("Usage: $ua->run_one($future)");')
      ->blank
      ->line('SV *self_sv = ST(0);')
      ->line('SV *future_sv = ST(1);')
      ->blank
      ->comment('Poll until this specific future resolves')
      ->line('int iterations = 0;')
      ->line('int max_iterations = 10000;')
      ->blank
      ->line('SPAGAIN;')
      ->line('while (iterations++ < max_iterations) {')
      ->comment('    Check if future is done')
      ->line('    ENTER; SAVETMPS;')
      ->line('    PUSHMARK(SP);')
      ->line('    XPUSHs(future_sv);')
      ->line('    PUTBACK;')
      ->blank
      ->line('    call_method("is_ready", G_SCALAR);')
      ->line('    SPAGAIN;')
      ->blank
      ->line('    int ready = POPi;')
      ->line('    PUTBACK;')
      ->line('    FREETMPS; LEAVE;')
      ->blank
      ->line('    if (ready) break;')
      ->blank
      ->comment('    Tick once')
      ->line('    ENTER; SAVETMPS;')
      ->line('    PUSHMARK(SP);')
      ->line('    XPUSHs(self_sv);')
      ->line('    PUTBACK;')
      ->line('    call_method("tick", G_DISCARD);')
      ->line('    FREETMPS; LEAVE;')
      ->line('}')
      ->blank
      ->comment('Return the future result')
      ->line('ENTER; SAVETMPS;')
      ->line('PUSHMARK(SP);')
      ->line('XPUSHs(future_sv);')
      ->line('PUTBACK;')
      ->blank
      ->line('call_method("get", G_SCALAR);')
      ->line('SPAGAIN;')
      ->blank
      ->line('SV *result = POPs;')
      ->line('SvREFCNT_inc(result);')
      ->line('PUTBACK;')
      ->line('FREETMPS; LEAVE;')
      ->blank
      ->line('ST(0) = sv_2mortal(result);')
      ->xs_return('1')
      ->xs_end
      ->blank;
}

sub gen_xs_parallel {
    my ($class, $builder) = @_;

    $builder->comment('Run multiple requests in parallel, wait for all')
      ->xs_function('xs_ua_parallel')
      ->xs_preamble
      ->line('int i;')
      ->line('if (items < 2) croak("Usage: $ua->parallel(@futures)");')
      ->blank
      ->line('SV *self_sv = ST(0);')
      ->blank
      ->comment('Collect futures')
      ->line('AV *futures = newAV();')
      ->line('for (i = 1; i < items; i++) {')
      ->line('    av_push(futures, SvREFCNT_inc(ST(i)));')
      ->line('}')



( run in 2.004 seconds using v1.01-cache-2.11-cpan-4ab04211f4c )