NAME
    XS::Object::Magic - Opaque, extensible XS pointer backed objects using
    "sv_magic"

SYNOPSIS
            package MyObject;

            use XS::Object::Magic;

            sub new {
                    my $class = shift;

                    # create any object representation you like
                    my $self = bless {}, $class;

                    $self->build_struct;

                    return $self;
            }


            # or using Moose

            package MyObject;
            use Moose;

            sub BUILD {
                    shift->build_struct;
            }


            # then in XS

            MODULE = MyObject  PACKAGE = MyObject

            void build_struct (SV *self)
                    PREINIT:
                            my_struct_t *thingy;
                    CODE:
                            thingy = create_whatever();

                            /* note that we dereference self first. This
                             * can be done using an XS typemap of course */
                            xs_object_magic_attach_struct(aTHX_ SvRV(self), thingy);


            void foo (SV *self)
                    PREINIT:
                            my_struct_t *thingy;
                    INIT:
                            thingy = xs_object_magic_get_struct_rv(aTHX_ self);
                    CODE:
                            my_struct_foo(thingy); /* delegate to C api */


            /* using typemap */
            void foo (my_struct_t *thingy)
                    CODE:
                            my_struct_foo(thingy);

            /* or better yet */
            PREFIX = my_struct_

            void
            my_struct_foo (thingy)
                    my_struct_t *thingy;


            /* don't forget a destructor */
            void
            DESTROY (my_struct_t *thingy)
                    CODE:
                            Safefree(thingy);

                            /* note that xs_object_magic_get_struct() will
                             * still return a pointe which is now invalid */

DESCRPTION
    This way of associating structs with Perl space objects is designed to
    supercede Perl's builtin "T_PTROBJ" with something that is designed to
    be:

    Extensible
        The association of the pointer using "sv_magicext" can be done on
        any data type, so you can associate C structs with any
        representation type.

        This means that you can add pointers to any object (hand coded,
        Moose or otherwise), while still having instance data in regular
        hashes.

    Opaque
        The C pointer is neither visible nor modifiable from Perl space.

        This prevents accidental corruption which could lead to segfaults
        using "T_PTROBJ" (e.g. "$$ptr_obj = 0").

C API
    void *xs_object_magic_get_struct_rv(aTHX_ SV *sv)
        When called on the object reference it will check that the "sv" is a
        reference, dereference it and return the associated pointer using
        "xs_object_magic_get_struct".

        Basically the same as "xs_object_magic_get_struct(aTHX_ SvRV(sv)"
        but croaks if no magic was found.

        Note that storing a "NULL" pointer will not cause an error.

    void *xs_object_magic_get_struct(aTHX_ SV *sv)
        Fetches the pointer associated with "sv".

        Returns "NULL" if no pointer is found. There is no way to
        distinguish this from having a "NULL" pointer.

    MAGIC *xs_object_magic_get_mg (aTHX_ SV *sv)
        Fetches the appropriate "MAGIC" entry for the struct pointer storage
        from "sv".

        This lets you manipulate "mg-"mg_ptr> if you need to.

    void xs_object_magic_attach_struct(aTHX_ SV *sv, void *ptr)
        Associates "ptr" with "sv" by adding a magic entry to "sv".

    SV *xs_object_magic_create(aTHX_ void *ptr, HV *stash)
        Convenience function that creates a hash object blessed to "stash"
        and associates it with "ptr".

        Can be used to easily create a constructor:

                SV *
                new(char *class)
                        CODE:
                                RETVAL = xs_object_magic_create(
                                        (void *)test_new(),
                                        gv_stashpv(class, 0)
                                );
                        OUTPUT: RETVAL

    int xs_object_magic_has_struct(aTHX_ SV *sv)
        Returns 1 if the SV has XS::Object::Magic magic, 0 otherwise.

    int xs_object_magic_has_struct_rv(aTHX_ SV *self)
        Returns 1 if the SV references an SV that has XS::Object::Magic
        magic, 0 otherwise.

        This lets you write a quick predicate method, like:

            void
            my_struct_has_struct (self)
                    SV *self;
                    PPCODE:
                            EXTEND(SP, 1);
                            if(xs_object_magic_has_struct_rv(aTHX_ self))
                                    PUSHs(&PL_sv_yes);
                            else
                                    PUSHs(&PL_sv_no);

        Then you can check for the existence of your struct from the Perl
        side:

            if( $object->has_struct ) { ... }

    int xs_object_magic_detach_struct(aTHX_ SV *sv)
        Removes the XS::Object::Magic magic from the given SV. Returns 1 if
        something is removed, 0 otherwise.

    int xs_object_magic_detach_struct_rv(aTHX_ SV *self)
        Likes "xs_object_magic_detach_struct", but takes a reference to the
        magic-containing SV instead of the SV itself. The reference to the
        SV is typically $self.

        Returns 0 if the SV is not a reference, otherwise returns whatever
        "xs_object_magic_detach_struct" returns.

TYPEMAP
    The included typemap provides a "T_PTROBJ_MG" entry which only supports
    the "INPUT" conversion.

    This typemap entry lets you declare methods that are invoked directly on
    the associated pointer. In your own typemap add an entry:

            TYPEMAP
            my_pointer_t *  T_PTROBJ_MG

    and then you can use "my_pointer_t" as the argument type of the
    invocant:

            I32
            method (self)
                    my_pointer_t *self;
                    CODE:
                            ...

    Note that there is no "OUTPUT" conversion. In order to return your
    object you need to use ST(0) or some other means of getting the
    invocant.

VERSION CONTROL
    <http://github.com/nothingmuch/xs-object-magic>

AUTHOR
    Florian Ragwitz, Yuval Kogman

COPYRIGHT & LICENSE
            Copyright (c) 2009 Florian Ragwitz, Yuval Kogman. All rights reserved
            This program is free software; you can redistribute
            it and/or modify it under the same terms as Perl itself.

