/*
Copyright (C) 2005-2006, The Perl Foundation.
$Id: luauserdata.pmc 17096 2007-02-20 20:20:48Z paultcochrane $

=head1 NAME

pmc/luauserdata.pmc - Lua Userdata

=head1 DESCRIPTION

C<LuaUserdata> extends C<LuaAny> to provide a class with the behaviour of
the Lua C<Userdata> type.

=head2 Overloaded Methods

=over 4

=cut

*/

#include "parrot/parrot.h"

static STRING *luauserdata_name;
extern STRING *lua_metatable;
extern INTVAL dynpmc_LuaBoolean;
extern INTVAL dynpmc_LuaNil;
extern INTVAL dynpmc_LuaString;
extern INTVAL dynpmc_LuaTable;

extern PMC * find_meth(Interp* interp, PMC *obj, const char *name);


pmclass LuaUserdata
    extends LuaAny
    does scalar
    dynpmc
    group lua_group
    hll Lua {

/* Class initialization. Caches constant strings that will be used later.
*/
    void class_init() {
        if (pass) {
            luauserdata_name = const_string(INTERP, "userdata");
        }
    }

/*

=item C<void init()>

Initializes the userdata.

=cut

*/
    void init () {
        PMC_pmc_val(SELF) = NULL;
    }

/*

=item C<void mark()>

Marks the userdata as live.

=cut

*/
    void mark () {
        if (PMC_pmc_val(SELF))
            pobject_lives(INTERP, (PObj *)PMC_pmc_val(SELF));
    }

/*

=item C<STRING* get_string()>

=cut

*/
    STRING* get_string () {
        return Parrot_sprintf_c(INTERP, "userdata: %08X", SELF);
    }

/*

=item C<STRING* name()>

Return the string "userdata".

=cut

*/
    STRING* name () {
        return luauserdata_name;
    }

/*

=item C<PMC* clone()>

=cut

*/
    PMC* clone() {
        return SELF;
    }

/*

=item C<PMC* get_attr_str(STRING* key)>

=cut

*/
    PMC* get_attr_str(STRING* key) {
        return PMC_pmc_val(SELF);
    }

/*

=item C<void set_attr_str(STRING* key, PMC* value)>

=cut

*/
    void set_attr_str(STRING* key, PMC* value) {
        PMC_pmc_val(SELF) = value;
    }

/*

=back

=head2 non-Vtable Methods

=over 4

=item C<INTVAL is_equal (PMC* value)>

The C<==> operation. Compares reference (not in depth).

=cut

*/
    INTVAL is_equal (PMC* value) {
MMD_LuaUserdata: {
            PMC *meth = find_meth(INTERP, SELF, "__eq");
            if (meth != NULL) {
                PMC *retval = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                       SELF, value);
                if (NULL == retval) {
                    return (INTVAL)0;
                }
                return VTABLE_get_bool(INTERP, retval);
            }
            if (SELF == value)
                return (INTVAL)1;
            else
                return (INTVAL)0;
        }
MMD_DEFAULT: {
            return (INTVAL)0;
        }
    }

/*

=item C<INTVAL cmp (PMC *value)>

=cut

*/
    INTVAL cmp (PMC* value) {
MMD_LuaUserdata: {
            real_exception(INTERP, NULL, ILL_INHERIT,
                    "attempt to compare two userdata values");
            return (INTVAL)0;
        }
MMD_DEFAULT: {
            real_exception(INTERP, NULL, ILL_INHERIT,
                    "attempt to compare userdata with %s",
                    string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return (INTVAL)0;
        }
    }

/*

=back

=head2 Specific Methods

=over 4

=item C<PMC *get_metatable()>

=cut

*/
    METHOD PMC* get_metatable() {
        PMC *retval = VTABLE_getprop(INTERP, SELF, lua_metatable);
        if (retval != NULL && retval->vtable->base_type == dynpmc_LuaTable)
            return retval;
        else
            return pmc_new(INTERP, dynpmc_LuaNil);
    }

/*

=item C<PMC* rawequal (PMC* value)>

=cut

*/
    METHOD PMC* rawequal (PMC* value) {
        PMC* retval = pmc_new(INTERP, dynpmc_LuaBoolean);
        if (SELF->vtable->base_type == value->vtable->base_type
         && SELF == value)
            PMC_int_val(retval) = 1;
        else
            PMC_int_val(retval) = 0;
        return retval;
    }

/*

=item C<void set_metatable(PMC *meta)>

=cut

*/
    METHOD void set_metatable(PMC *meta) {
        if (dynpmc_LuaNil == meta->vtable->base_type) {
            VTABLE_delprop(INTERP, SELF, lua_metatable);
        }
        else {
            VTABLE_setprop(INTERP, SELF, lua_metatable, meta);
        }
    }

}

/*

=back

=head1 AUTHORS

Francois Perrad.

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
