Chandra

 view release on metacpan or  search on metacpan

xs/protocol.xs  view on Meta::CPAN

    scheme = SvPV(scheme_sv, scheme_len);
    clean_len = scheme_len;
    if (clean_len > 3 && scheme[clean_len - 3] == ':' && scheme[clean_len - 2] == '/' && scheme[clean_len - 1] == '/') {
        clean_len -= 3;
    } else if (clean_len > 1 && scheme[clean_len - 1] == ':') {
        clean_len -= 1;
    }
    if (clean_len >= sizeof(clean_scheme)) {
        clean_len = sizeof(clean_scheme) - 1;
    }
    Copy(scheme, clean_scheme, clean_len, char);
    clean_scheme[clean_len] = '\0';

    /* Store handler in protocols hash */
    protocols_svp = hv_fetchs(hv, "protocols", 0);
    if (protocols_svp && SvROK(*protocols_svp)) {
        protocols_hv = (HV *)SvRV(*protocols_svp);
        (void)hv_store(protocols_hv, clean_scheme, clean_len, newSVsv(handler), 0);
    }

    /* Create XS callback with CvXSUBANY for handler + JSON encoder */
    {
        SV **app_svp = hv_fetchs(hv, "app", 0);
        if (app_svp && SvOK(*app_svp)) {
            ProtocolBindCtx *ctx;
            CV *wrapper_cv;
            SV *json_enc;
            SV *bind_name = sv_2mortal(newSVpvf("__protocol_%s", clean_scheme));

            json_enc = get_sv("Chandra::Protocol::_xs_json", 0);

            Newxz(ctx, 1, ProtocolBindCtx);
            ctx->handler = SvREFCNT_inc(handler);
            ctx->json_encoder = SvREFCNT_inc(json_enc);

            wrapper_cv = newXS(NULL, xs_protocol_bound_callback, __FILE__);
            CvXSUBANY(wrapper_cv).any_ptr = (void *)ctx;

            {
                dSP;
                ENTER; SAVETMPS;
                PUSHMARK(SP);
                XPUSHs(*app_svp);
                XPUSHs(bind_name);
                XPUSHs(sv_2mortal(newRV_noinc((SV *)wrapper_cv)));
                PUTBACK;
                call_method("bind", G_DISCARD);
                FREETMPS; LEAVE;
            }
        }
    }

    RETVAL = SvREFCNT_inc(self);
}
OUTPUT:
    RETVAL

void
schemes(self)
    SV *self
PPCODE:
{
    HV *hv = (HV *)SvRV(self);
    SV **protocols_svp;

    protocols_svp = hv_fetchs(hv, "protocols", 0);
    if (protocols_svp && SvROK(*protocols_svp)) {
        HV *protocols_hv = (HV *)SvRV(*protocols_svp);
        I32 num_keys = hv_iterinit(protocols_hv);

        if (GIMME_V == G_SCALAR) {
            mXPUSHi(num_keys);
            XSRETURN(1);
        } else {
            HE *entry;
            while ((entry = hv_iternext(protocols_hv)) != NULL) {
                XPUSHs(sv_2mortal(newSVhek(HeKEY_hek(entry))));
            }
        }
    } else {
        if (GIMME_V == G_SCALAR) {
            mXPUSHi(0);
            XSRETURN(1);
        }
    }
}

SV *
is_registered(self, scheme_sv)
    SV *self
    SV *scheme_sv
CODE:
{
    HV *hv = (HV *)SvRV(self);
    SV **protocols_svp;
    char *scheme;
    STRLEN scheme_len;
    char clean_scheme[256];
    STRLEN clean_len;

    scheme = SvPV(scheme_sv, scheme_len);
    clean_len = scheme_len;
    if (clean_len > 3 && scheme[clean_len - 3] == ':' && scheme[clean_len - 2] == '/' && scheme[clean_len - 1] == '/') {
        clean_len -= 3;
    } else if (clean_len > 1 && scheme[clean_len - 1] == ':') {
        clean_len -= 1;
    }
    if (clean_len >= sizeof(clean_scheme)) {
        clean_len = sizeof(clean_scheme) - 1;
    }
    Copy(scheme, clean_scheme, clean_len, char);
    clean_scheme[clean_len] = '\0';

    protocols_svp = hv_fetchs(hv, "protocols", 0);
    if (protocols_svp && SvROK(*protocols_svp)) {
        HV *protocols_hv = (HV *)SvRV(*protocols_svp);
        RETVAL = hv_exists(protocols_hv, clean_scheme, clean_len) ? &PL_sv_yes : &PL_sv_no;
    } else {
        RETVAL = &PL_sv_no;
    }
}



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