# "perlobject.map"  Crazy Panda

TYPEMAP

int32_t     T_IV
int16_t     T_IV
int8_t      T_IV
uint32_t    T_UV
uint16_t    T_UV
uint8_t     T_UV

# time_t should follow IV size of machine
time_t      T_IV

AV* T_AV
HV* T_HV
CV* T_CV
IO* T_IO

OSV*    T_OSV
OAV*    T_OAV
OHV*    T_OHV
OIO*    T_OIO

######################################################################
OUTPUT

T_REF
    $arg = NULL;
    $arg = $var ? newRV_noinc((SV*)$var) : &PL_sv_undef;
T_AV : T_REF
T_HV : T_REF
T_CV : T_REF
T_IO : T_REF

T_OREF
    $arg = NULL;
    $arg = xs::_typemap_out_oref(aTHX_ (SV*)$var, CLASS);
T_OSV : T_OREF
T_OAV : T_OREF
T_OHV : T_OREF
T_OIO : T_OREF
    
T_OPTR
    $arg = NULL;
    ${
        $type =~ s/\s+//g;
        $p{basetype} ||= $type;
        my $cast_op = $p{_shared_ptr} ? "panda::static_pointer_cast<$p{basetype}::element_type>" : "static_cast<$p{basetype}>";
        $p{_pp}{downgraded} = $p{nocast} || $p{basetype} eq $type ? $var : "$cast_op($var)";
        \"";
    };
    $arg = xs::_typemap_out_optr(aTHX_ $p{_pp}{downgraded}, CLASS);

T_OPTR_REFCNT : T_OPTR
    $var->retain();

T_OPTR_SHARED : T_OPTR(_shared_ptr=1)

T_OEXT
    $arg = NULL;
    ${
        $type =~ s/\s+//g;
        $p{basetype} ||= $type;
        my $cast_op = $p{_shared_ptr} ? "panda::static_pointer_cast<$p{basetype}::element_type>" : "static_cast<$p{basetype}>";
        $p{_pp}{downgraded} = $p{nocast} || $p{basetype} eq $type ? $var : "$cast_op($var)";
        $p{_pp}{marker} = "xs::SVPayloadMarker<$p{basetype}>";
        $p{_pp}{svdup} = '';
        if (my $func = $p{on_svdup}) {
            my $svdup_funcs = {
                '@clone'  => " xs::_typemap_oext_svdup_clone<$p{basetype}> ",
                '@retain' => " xs::_typemap_oext_svdup_retain<$p{basetype}> ",
            };
            $func = $svdup_funcs->{$func} if exists $svdup_funcs->{$func};
            $p{_pp}{marker} .= "::get(xs::_typemap_oext_svdup<$p{basetype}>($func).cb<$func>)";
        } else {
            $p{_pp}{marker} = "&$p{_pp}{marker}::marker";
        }
        \"";
    };
    INIT: SV* self = NULL;
    $arg = xs::_typemap_out_oext(aTHX_ self, $p{_pp}{downgraded}, CLASS, $p{_pp}{marker});
    
T_OEXT_AV : T_OEXT
    if (!self && $var) self = (SV*)newAV();
    
T_OEXT_HV : T_OEXT
    if (!self && $var) self = (SV*)newHV();
    
T_OEXT_REFCNT : T_OEXT
    $var->retain();

T_OEXT_SHARED : T_OEXT(_shared_ptr=1)

######################################################################
INPUT

T_AV
    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVAV) $var = (AV*)SvRV($arg);
    else if (SvOK($arg)) croak(\"${Package}::$func_name() -- $var is not an ARRAY reference\");
    else $var = NULL;
    
T_HV
    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVHV) $var = (HV*)SvRV($arg);
    else if (SvOK($arg)) croak(\"${Package}::$func_name() -- $var is not a HASH reference\");
    else $var = NULL;

T_CV
    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVCV) $var = (CV*)SvRV($arg);
    else if (SvOK($arg)) croak(\"${Package}::$func_name() -- $var is not a CODE reference\");
    else $var = NULL;

T_IO
    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVIO) $var = (IO*)SvRV($arg);
    else if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVGV && ($var = GvIO(SvRV($arg)))) {} 
    else if (SvOK($arg)) croak(\"${Package}::$func_name() -- $var is not an IO reference\");
    else $var = NULL;

T_OSV
    if (sv_isobject($arg) && SvTYPE(SvRV($arg)) <= SVt_PVMG) $var = SvRV($arg);
    else if (${\($var eq q!THIS! ? q!1! : qq!SvOK($arg)!)}) croak(\"${Package}::$func_name() -- $var is not a blessed SCALAR reference\");
    else $var = NULL;

T_OAV
    if (sv_isobject($arg) && SvTYPE(SvRV($arg)) == SVt_PVAV) $var = (AV*)SvRV($arg);
    else if (${\($var eq q!THIS! ? q!1! : qq!SvOK($arg)!)}) croak(\"${Package}::$func_name() -- $var is not a blessed ARRAY reference\");
    else $var = NULL;
    
T_OHV
    if (sv_isobject($arg) && SvTYPE(SvRV($arg)) == SVt_PVHV) $var = (HV*)SvRV($arg);
    else if (${\($var eq q!THIS! ? q!1! : qq!SvOK($arg)!)}) croak(\"${Package}::$func_name() -- $var is not a blessed HASH reference\");
    else $var = NULL;

T_OIO
    if (sv_isobject($arg) && SvTYPE(SvRV($arg)) == SVt_PVIO) $var = (IO*)SvRV($arg);
    else if (sv_isobject($arg) && SvTYPE(SvRV($arg)) == SVt_PVGV && ($var = GvIO(SvRV($arg)))) {}
    else if (${\($var eq q!THIS! ? q!1! : qq!SvOK($arg)!)}) croak(\"${Package}::$func_name() -- $var is not a blessed IO reference\");
    else $var = NULL;

T_OPTR
    ${
        $type =~ s/\s+//g;
        $p{basetype} ||= $type;
        my $code;
        my $destroy = ($func_name eq q!DESTROY! && $var eq q!THIS! && $p{_shared_ptr}) ? q!, true! : q!!;
        if ($p{nocast} || $p{basetype} eq $type) {
            $code = qq!xs::_typemap_in_optr(aTHX_ $arg, &$var$destroy)!;
        } else {
            my $cast_op = $p{_shared_ptr} ? qq!panda::dynamic_pointer_cast<${type}::element_type>! : qq!dynamic_cast<$type>!;
            $code = qq!$p{basetype} downgraded;\n!.
                    qq!        xs::_typemap_in_optr(aTHX_ $arg, &downgraded$destroy);\n!.
                    qq!        $var = $cast_op(downgraded)!;
        }
        $p{_pp}{code} = $code;
        \q!!;
    }
    {
        $p{_pp}{code};
        if (!$var${\($var eq q!THIS! ? q!! : qq! && SvOK($arg)!)}) croak( \"${Package}::$func_name() -- $var($arg) is not a valid object\" );
    }	

T_OPTR_REFCNT : T_OPTR
    @PREVENT_DEFAULT_DELETE_ON_EMPTY_DESTROY
    ${\( ($func_name eq q!DESTROY! && $var eq 'THIS') ?
        qq!panda::shared_ptr<$subtype> _pxs_autorelease_$var($var); $var->release();! : q!!
    )}

T_OPTR_SHARED : T_OPTR(_shared_ptr=1)
    @PREVENT_DEFAULT_DELETE_ON_EMPTY_DESTROY

T_OEXT
    ${
        $type =~ s/\s+//g;
        $p{basetype} ||= $type;
        my $code;
        my $destroy = ($func_name eq q!DESTROY! && $var eq q!THIS! && $p{_shared_ptr}) ? q!, true! : q!!;
        my $marker  = qq!&xs::SVPayloadMarker<$p{basetype}>::marker!;
        if ($p{nocast} || $p{basetype} eq $type) {
            $code = qq!xs::_typemap_in_oext(aTHX_ $arg, &$var, $marker $destroy);!;
        } else {
            my $cast_op = $p{_shared_ptr} ? qq!panda::dynamic_pointer_cast<${type}::element_type>! : qq!dynamic_cast<$type>!;
            $code = qq!$p{basetype} downgraded;\n!.
                    qq!        xs::_typemap_in_oext(aTHX_ $arg, &downgraded, $marker $destroy);\n!.
                    qq!        $var = $cast_op(downgraded);!;
        }
        $p{_pp}{code} = $code;
        \q!!;
    }
    {
        $p{_pp}{code};
        if (!$var${\($var eq q!THIS! ? q!! : qq! && SvOK($arg)!)}) croak( \"${Package}::$func_name() -- $var($arg) is not a valid object\" );
    }
T_OEXT_AV : T_OEXT
T_OEXT_HV : T_OEXT

T_OEXT_REFCNT : T_OEXT
    @PREVENT_DEFAULT_DELETE_ON_EMPTY_DESTROY
    ${\( ($func_name eq q!DESTROY! && $var eq 'THIS') ?
        qq!panda::shared_ptr<$subtype> _pxs_autorelease_$var($var); $var->release();! : q!!
    )}

T_OEXT_SHARED : T_OEXT(_shared_ptr=1)
    @PREVENT_DEFAULT_DELETE_ON_EMPTY_DESTROY

