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.