.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "XS::Object::Magic 3pm" .TH XS::Object::Magic 3pm "2020-11-08" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" XS::Object::Magic \- Opaque, extensible XS pointer backed objects using "sv_magic" .SH "VERSION" .IX Header "VERSION" version 0.05 .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& 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\*(Aqt 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 */ .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This way of associating structs with Perl space objects is designed to supersede Perl's builtin \f(CW\*(C`T_PTROBJ\*(C'\fR with something that is designed to be: .IP "Extensible" 4 .IX Item "Extensible" The association of the pointer using \f(CW\*(C`sv_magicext\*(C'\fR can be done on any data type, so you can associate C structs with any representation type. .Sp This means that you can add pointers to any object (hand coded, Moose or otherwise), while still having instance data in regular hashes. .IP "Opaque" 4 .IX Item "Opaque" The C pointer is neither visible nor modifiable from Perl space. .Sp This prevents accidental corruption which could lead to segfaults using \&\f(CW\*(C`T_PTROBJ\*(C'\fR (e.g. \f(CW\*(C`$$ptr_obj = 0\*(C'\fR). .SH "C API" .IX Header "C API" .IP "void *xs_object_magic_get_struct_rv(aTHX_ \s-1SV\s0 *sv)" 4 .IX Item "void *xs_object_magic_get_struct_rv(aTHX_ SV *sv)" When called on the object reference it will check that the \f(CW\*(C`sv\*(C'\fR is a reference, dereference it and return the associated pointer using \&\f(CW\*(C`xs_object_magic_get_struct\*(C'\fR. .Sp Basically the same as \f(CW\*(C`xs_object_magic_get_struct(aTHX_ SvRV(sv)\*(C'\fR but croaks if no magic was found. .Sp Note that storing a \f(CW\*(C`NULL\*(C'\fR pointer will \fBnot\fR cause an error. .IP "void *xs_object_magic_get_struct(aTHX_ \s-1SV\s0 *sv)" 4 .IX Item "void *xs_object_magic_get_struct(aTHX_ SV *sv)" Fetches the pointer associated with \f(CW\*(C`sv\*(C'\fR. .Sp Returns \f(CW\*(C`NULL\*(C'\fR if no pointer is found. There is no way to distinguish this from having a \f(CW\*(C`NULL\*(C'\fR pointer. .IP "\s-1MAGIC\s0 *xs_object_magic_get_mg (aTHX_ \s-1SV\s0 *sv)" 4 .IX Item "MAGIC *xs_object_magic_get_mg (aTHX_ SV *sv)" Fetches the appropriate \f(CW\*(C`MAGIC\*(C'\fR entry for the struct pointer storage from \&\f(CW\*(C`sv\*(C'\fR. .Sp This lets you manipulate \f(CW\*(C`mg\-\*(C'\fRmg_ptr> if you need to. .IP "void xs_object_magic_attach_struct(aTHX_ \s-1SV\s0 *sv, void *ptr)" 4 .IX Item "void xs_object_magic_attach_struct(aTHX_ SV *sv, void *ptr)" Associates \f(CW\*(C`ptr\*(C'\fR with \f(CW\*(C`sv\*(C'\fR by adding a magic entry to \f(CW\*(C`sv\*(C'\fR. .IP "\s-1SV\s0 *xs_object_magic_create(aTHX_ void *ptr, \s-1HV\s0 *stash)" 4 .IX Item "SV *xs_object_magic_create(aTHX_ void *ptr, HV *stash)" Convenience function that creates a hash object blessed to \f(CW\*(C`stash\*(C'\fR and associates it with \f(CW\*(C`ptr\*(C'\fR. .Sp Can be used to easily create a constructor: .Sp .Vb 8 \& SV * \& new(char *class) \& CODE: \& RETVAL = xs_object_magic_create( \& (void *)test_new(), \& gv_stashpv(class, 0) \& ); \& OUTPUT: RETVAL .Ve .IP "int xs_object_magic_has_struct(aTHX_ \s-1SV\s0 *sv)" 4 .IX Item "int xs_object_magic_has_struct(aTHX_ SV *sv)" Returns 1 if the \s-1SV\s0 has XS::Object::Magic magic, 0 otherwise. .IP "int xs_object_magic_has_struct_rv(aTHX_ \s-1SV\s0 *self)" 4 .IX Item "int xs_object_magic_has_struct_rv(aTHX_ SV *self)" Returns 1 if the \s-1SV\s0 references an \s-1SV\s0 that has XS::Object::Magic magic, 0 otherwise. .Sp This lets you write a quick predicate method, like: .Sp .Vb 9 \& 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); .Ve .Sp Then you can check for the existence of your struct from the Perl side: .Sp .Vb 1 \& if( $object\->has_struct ) { ... } .Ve .IP "int xs_object_magic_detach_struct(aTHX_ \s-1SV\s0 *sv, void *ptr)" 4 .IX Item "int xs_object_magic_detach_struct(aTHX_ SV *sv, void *ptr)" Removes the XS::Object::Magic magic with attached pointer \f(CW\*(C`ptr\*(C'\fR from the given \s-1SV.\s0 Returns the number of elements removed if something is removed, 0 otherwise. .Sp Supplying \s-1NULL\s0 as \f(CW\*(C`ptr\*(C'\fR will result in all XS::Object::Magic magic being removed. .IP "int xs_object_magic_detach_struct_rv(aTHX_ \s-1SV\s0 *self, void *ptr)" 4 .IX Item "int xs_object_magic_detach_struct_rv(aTHX_ SV *self, void *ptr)" Likes \f(CW\*(C`xs_object_magic_detach_struct\*(C'\fR, but takes a reference to the magic-containing \s-1SV\s0 instead of the \s-1SV\s0 itself. The reference to the \s-1SV\s0 is typically \f(CW$self\fR. .Sp Returns 0 if the \s-1SV\s0 is not a reference, otherwise returns whatever \&\f(CW\*(C`xs_object_magic_detach_struct\*(C'\fR returns. .Sp \&\f(CW\*(C`ptr\*(C'\fR is passwd to xs_object_magic_detach_struct unmodified. .SH "TYPEMAP" .IX Header "TYPEMAP" The included typemap provides a \f(CW\*(C`T_PTROBJ_MG\*(C'\fR entry which only supports the \&\f(CW\*(C`INPUT\*(C'\fR conversion. .PP This typemap entry lets you declare methods that are invoked directly on the associated pointer. In your own typemap add an entry: .PP .Vb 2 \& TYPEMAP \& my_pointer_t * T_PTROBJ_MG .Ve .PP and then you can use \f(CW\*(C`my_pointer_t\*(C'\fR as the argument type of the invocant: .PP .Vb 5 \& I32 \& method (self) \& my_pointer_t *self; \& CODE: \& ... .Ve .PP Note that there is no \f(CW\*(C`OUTPUT\*(C'\fR conversion. In order to return your object you need to use \f(CWST(0)\fR or some other means of getting the invocant. .SH "SUPPORT" .IX Header "SUPPORT" Bugs may be submitted through the \s-1RT\s0 bug tracker (or bug\-XS\-Object\-Magic@rt.cpan.org ). .SH "AUTHOR" .IX Header "AUTHOR" יובל קוג'מן (Yuval Kogman) .SH "CONTRIBUTORS" .IX Header "CONTRIBUTORS" .IP "\(bu" 4 Florian Ragwitz .IP "\(bu" 4 Jonathan Rockway .IP "\(bu" 4 Karen Etheridge .IP "\(bu" 4 Emmanuel Rodriguez .IP "\(bu" 4 Jeremiah C. Foster .SH "COPYRIGHT AND LICENCE" .IX Header "COPYRIGHT AND LICENCE" This software is copyright (c) 2009 by יובל קוג'מן (Yuval Kogman). .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.