Chandra

 view release on metacpan or  search on metacpan

xs/shortcut.xs  view on Meta::CPAN

    /* Validate combo */
    if (!SvOK(combo_sv)) {
        croak("bind() requires a combo string");
    }

    /* Parse optional %opts */
    for (i = 3; i + 1 < items; i += 2) {
        const char *key = SvPV_nolen(ST(i));
        if (strEQ(key, "prevent_default")) {
            prevent_default = SvIV(ST(i + 1));
        }
    }

    /* Normalize combo */
    {
        dSP;
        int count;
        ENTER; SAVETMPS;
        PUSHMARK(SP);
        XPUSHs(self);
        XPUSHs(combo_sv);
        PUTBACK;
        count = call_method("_normalize_combo", G_SCALAR);
        SPAGAIN;
        norm_combo = (count > 0) ? newSVsv(POPs) : newSVsv(combo_sv);
        PUTBACK;
        FREETMPS; LEAVE;
    }

    norm_str = SvPV(norm_combo, norm_len);

    /* Create entry: { handler, enabled, prevent_default } */
    entry_hv = newHV();
    (void)hv_stores(entry_hv, "handler", newSVsv(handler));
    (void)hv_stores(entry_hv, "enabled", newSViv(1));
    (void)hv_stores(entry_hv, "prevent_default", newSViv(prevent_default));
    (void)hv_stores(entry_hv, "combo", newSVsv(norm_combo));

    /* Store in bindings hash */
    bindings_svp = hv_fetchs(hv, "bindings", 0);
    if (bindings_svp && SvROK(*bindings_svp)) {
        bindings_hv = (HV *)SvRV(*bindings_svp);
    } else {
        bindings_hv = newHV();
        (void)hv_stores(hv, "bindings", newRV_noinc((SV *)bindings_hv));
    }
    (void)hv_store(bindings_hv, norm_str, norm_len,
        newRV_noinc((SV *)entry_hv), 0);

    /* Bind __chandra_shortcut dispatch if not already done */
    {
        SV **db_svp = hv_fetchs(hv, "_dispatch_bound", 0);
        if (!db_svp || !SvIV(*db_svp)) {
            SV **app_svp = hv_fetchs(hv, "app", 0);
            if (app_svp && SvOK(*app_svp)) {
                /* Create dispatch callback that references self */
                CV *wrapper_cv;
                SV *self_ref;

                self_ref = newSVsv(self);
                sv_rvweaken(self_ref); /* weak ref to avoid circular */

                wrapper_cv = newXS(NULL, xs_shortcut_dispatch_callback, __FILE__);
                CvXSUBANY(wrapper_cv).any_ptr = (void *)self_ref;

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

                (void)hv_stores(hv, "_dispatch_bound", newSViv(1));
            }
        }
    }

    SvREFCNT_dec(norm_combo);
    RETVAL = SvREFCNT_inc(self);
}
OUTPUT:
    RETVAL

 # ---- unbind($combo) ----

SV *
unbind(self, combo_sv)
    SV *self
    SV *combo_sv
CODE:
{
    HV *hv = (HV *)SvRV(self);
    SV **bindings_svp;
    SV *norm_combo;
    const char *norm_str;
    STRLEN norm_len;

    /* Normalize combo */
    {
        dSP;
        int count;
        ENTER; SAVETMPS;
        PUSHMARK(SP);
        XPUSHs(self);
        XPUSHs(combo_sv);
        PUTBACK;
        count = call_method("_normalize_combo", G_SCALAR);
        SPAGAIN;
        norm_combo = (count > 0) ? newSVsv(POPs) : newSVsv(combo_sv);
        PUTBACK;
        FREETMPS; LEAVE;
    }

    norm_str = SvPV(norm_combo, norm_len);

    bindings_svp = hv_fetchs(hv, "bindings", 0);



( run in 1.690 second using v1.01-cache-2.11-cpan-364913b4093 )