Mouse

 view release on metacpan or  search on metacpan

xs-src/Mouse.xs  view on Meta::CPAN

{
    SV* const package = get_slot(self, mouse_package); /* $self->{package} */
    SV* const methods = get_slot(self, mouse_methods); /* $self->{methods} */
    GV* gv;
    SV* code_ref;

    if(!(package && SvOK(package))){
        croak("No package name defined");
    }

    must_defined(name, "a method name");
    must_ref    (code, "a CODE reference", SVt_NULL); /* any reftype is OK */

    code_ref = code;
    if(SvTYPE(SvRV(code_ref)) != SVt_PVCV){
        SV*  sv = code_ref;  /* used in tryAMAGICunDEREF */
        SV** sp = &sv;       /* used in tryAMAGICunDEREF */
        tryAMAGICunDEREF(to_cv); /* try \&{$code} */
        must_ref(code, "a CODE reference", SVt_PVCV);
        code_ref = sv;
    }

    /*  *{$package . '::' . $name} -> *gv */
    gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV);
    mouse_install_sub(aTHX_ gv, code_ref);
    /* CvMETHOD_on((CV*)SvRV(code_ref)); */
    (void)set_slot(methods, name, code); /* $self->{methods}{$name} = $code */
}

MODULE = Mouse  PACKAGE = Mouse::Meta::Class

BOOT:
{
    CV* xsub;

    INSTALL_SIMPLE_READER(Class, roles);
    INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id);
    INSTALL_SIMPLE_READER(Class, is_immutable);

    INSTALL_INHERITABLE_CLASS_ACCESSOR(strict_constructor);

    INSTALL_CLASS_HOLDER(Class, method_metaclass,     "Mouse::Meta::Method");
    INSTALL_CLASS_HOLDER(Class, attribute_metaclass,  "Mouse::Meta::Attribute");
    INSTALL_CLASS_HOLDER(Class, constructor_class,    "Mouse::Meta::Method::Constructor::XS");
    INSTALL_CLASS_HOLDER(Class, destructor_class,     "Mouse::Meta::Method::Destructor::XS");

    xsub = newXS("Mouse::Meta::Method::Constructor::XS::_generate_constructor",
        XS_Mouse_value_holder, file);
    CvXSUBANY(xsub).any_ptr
        = newRV_inc((SV*)get_cvs("Mouse::Object::new", GV_ADD));

    xsub = newXS("Mouse::Meta::Method::Destructor::XS::_generate_destructor",
        XS_Mouse_value_holder, file);
    CvXSUBANY(xsub).any_ptr
        = newRV_inc((SV*)get_cvs("Mouse::Object::DESTROY", GV_ADD));
}


void
linearized_isa(SV* self)
PPCODE:
{
    /* MOUSE_xc_stash() is not available because the xc system depends on
       linearized_isa() */
    HV* const stash          = mouse_get_namespace(aTHX_ self);
    AV* const linearized_isa = mro_get_linear_isa(stash);
    I32 const            len = AvFILLp(linearized_isa) + 1;
    I32 i;
    EXTEND(SP, len);
    for(i = 0; i < len; i++){
        PUSHs(AvARRAY(linearized_isa)[i]);
    }
}

void
get_all_attributes(SV* self)
PPCODE:
{
    AV* const xc        = mouse_get_xc(aTHX_ self);
    AV* const all_attrs = MOUSE_xc_attrall(xc);
    I32 const len       = AvFILLp(all_attrs) + 1;
    I32 i;

    EXTEND(SP, len);
    for(i = 0; i < len; i++){
        PUSHs( MOUSE_av_at(all_attrs, i) );
    }
}

void
new_object(SV* meta, ...)
CODE:
{
    AV* const xc   = mouse_get_xc(aTHX_ meta);
    HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax, items);
    SV* object;

    object = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
    mouse_class_initialize_object(aTHX_ meta, object, args, FALSE);
    mouse_buildall(aTHX_ xc, object, sv_2mortal(newRV_inc((SV*)args)));
    ST(0) = object; /* because object is mortal, we should return it as is */
    XSRETURN(1);
}

void
clone_object(SV* meta, SV* object, ...)
CODE:
{
    AV* const xc   = mouse_get_xc(aTHX_ meta);
    HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax + 1, items - 1);
    SV* proto;

    if(!mouse_is_an_instance_of(aTHX_ MOUSE_xc_stash(xc), object)) {
        mouse_throw_error(meta, object,
            "You must pass an instance of the metaclass (%"SVf"), not (%"SVf")",
            mcall0(meta, mouse_name), object);
    }

    proto = mouse_instance_clone(aTHX_ object);
    mouse_class_initialize_object(aTHX_ meta, proto, args, TRUE);
    ST(0) = proto; /* because object is mortal, we should return it as is */
    XSRETURN(1);
}

void
_initialize_object(SV* meta, SV* object, HV* args, bool is_cloning = FALSE)
CODE:
{
    mouse_class_initialize_object(aTHX_ meta, object, args, is_cloning);
}

void
_invalidate_metaclass_cache(SV* meta)
CODE:
{
    AV* const xc = mouse_get_xc_if_fresh(aTHX_ meta);
    if(xc) {
        SV* const gen = MOUSE_xc_gen(xc);
        sv_setuv(gen, 0U);
    }
    delete_slot(meta, newSVpvs_flags("_mouse_cache_", SVs_TEMP));
}


MODULE = Mouse  PACKAGE = Mouse::Meta::Role

BOOT:
    INSTALL_SIMPLE_READER_WITH_KEY(Role, get_roles, roles);
    INSTALL_SIMPLE_PREDICATE_WITH_KEY(Role, is_anon_role, anon_serial_id);

    INSTALL_CLASS_HOLDER(Role, method_metaclass,  "Mouse::Meta::Role::Method");

void
add_before_modifier(SV* self, SV* name, SV* modifier)
CODE:
{
    av_push(mouse_get_modifier_storage(aTHX_ self, (enum mouse_modifier_t)ix, name), newSVsv(modifier));
}
ALIAS:
    add_before_method_modifier = MOUSE_M_BEFORE
    add_around_method_modifier = MOUSE_M_AROUND
    add_after_method_modifier  = MOUSE_M_AFTER

void
get_before_modifiers(SV* self, SV* name)
ALIAS:
    get_before_method_modifiers = MOUSE_M_BEFORE
    get_around_method_modifiers = MOUSE_M_AROUND
    get_after_method_modifiers  = MOUSE_M_AFTER
PPCODE:
{
    AV* const storage = mouse_get_modifier_storage(aTHX_ self,
                            (enum mouse_modifier_t)ix, name);
    I32 const len     = av_len(storage) + 1;
    if(GIMME_V == G_ARRAY) {
        I32 i;
        EXTEND(SP, len);
        for(i = 0; i < len; i++){
            PUSHs(*av_fetch(storage, i, TRUE));
        }
    }
    else{
        mPUSHi(len);
    }
}

void
add_metaclass_accessor(SV* self, SV* name)
CODE:
{
    SV* const klass = mcall0(self, mouse_name);
    const char* fq_name = form("%"SVf"::%"SVf, klass, name);
    STRLEN keylen;
    const char* const key = SvPV_const(name, keylen);
    mouse_simple_accessor_generate(aTHX_ fq_name, key, keylen,
        XS_Mouse_inheritable_class_accessor, NULL, 0);
}

MODULE = Mouse  PACKAGE = Mouse::Object

void
new(SV* klass, ...)
CODE:
{
    SV* const meta = mouse_initialize_metaclass(aTHX_ klass);
    AV* const xc   = mouse_get_xc(aTHX_ meta);
    UV const flags = MOUSE_xc_flags(xc);
    SV* args;
    SV* object;

    /* BUILDARGS */
    if(flags & MOUSEf_XC_HAS_BUILDARGS){
        I32 i;
        SPAGAIN;

        PUSHMARK(SP);
        EXTEND(SP, items);
        for(i = 0; i < items; i++){
            PUSHs(ST(i));
        }

        PUTBACK;
        call_method_safes("BUILDARGS", G_SCALAR);

        SPAGAIN;
        args = POPs;
        PUTBACK;

        if(!IsHashRef(args)){
            croak("BUILDARGS did not return a HASH reference");



( run in 0.876 second using v1.01-cache-2.11-cpan-5511b514fd6 )