# "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((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($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)";
        \"";
    };
    INIT: SV* self = NULL;
    static xs::payload_marker_t* __${var}_marker = xs::sv_payload_marker("$p{basetype}");
    $arg = xs::_typemap_out_oext(self, $p{_pp}{downgraded}, CLASS, __${var}_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 (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 (${\($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($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($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!!;
        if ($p{nocast} || $p{basetype} eq $type) {
            $code = qq!xs::_typemap_in_oext($arg, &$var, __${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($arg, &downgraded, __${var}_marker$destroy);\n!.
                    qq!        $var = $cast_op(downgraded);!;
        }
        $p{_pp}{code} = $code;
        \q!!;
    }
    static xs::payload_marker_t* __${var}_marker = xs::sv_payload_marker(\"$p{basetype}\");
    {
        $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

