XS::Ob...::Magic(3pm)

πŸ’– NAME

XS::Object::Magic β€” Opaque, extensible XS pointer backed objects using sv_magic. That's the manual page <pink>XS::Ob...::Magic(3pm)</pink> from the User Contributed Perl Documentation crew, bestie, and she is a whole vibe. Sit down, grab a boba, we're attaching structs to Perl objects the ✨correct✨ way.


✨ VERSION

version 0.05

(yes, only 0.05, and yes, she gets the job done 😌)


🌈 SYNOPSIS

Okay so picture this. You want a Perl object that secretly carries a C struct around, iykyk. Here's the whole flow:

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 over in XS land:

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 */
BESTIE. Do not forget the destructor. The comment is literally right there in the code: after you Safefree that thingy, xs_object_magic_get_struct() will happily still hand you back a pointer that is now invalid. πŸ’€ Free it and stop using it.

πŸ¦‹ DESCRIPTION

This way of associating structs with Perl space objects is designed to supersede 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.

Obsessed. Any object type, any representation, structs riding shotgun. 🫢

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).

FR FR, this is the whole point. With T_PTROBJ some innocent-looking Perl code like $$ptr_obj = 0 can scramble your pointer and then boom, segfault, main character death scene 😭. Not on our watch.


πŸ‘‘ 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.

(so like… "not found" and "found, and it's NULL" look identical. Just so you know. πŸ‘€)

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

Constructor in like four lines, we love a shortcut that actually slaps. πŸ’…

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, void *ptr)

Removes the XS::Object::Magic magic with attached pointer ptr from the given SV. Returns the number of elements removed if something is removed, 0 otherwise.

Supplying NULL as ptr will result in all XS::Object::Magic magic being removed.

int xs_object_magic_detach_struct_rv(aTHX_ SV *self, void *ptr)

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.

ptr is passwd to xs_object_magic_detach_struct unmodified.


πŸŽ€ 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:
        ...
Heads up bestie: 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. No cap.

🫢 SUPPORT

Bugs may be submitted through the RT bug tracker at https://rt.cpan.org/Public/Dist/Display.html?Name=XS-Object-Magic (or by mailing bug-XS-Object-Magic@rt.cpan.org).


🌸 AUTHOR

Χ™Χ•Χ‘Χœ Χ§Χ•Χ’'מן (Yuval Kogman) <nothingmuch@woobling.org>

iconic. legendary. we stan. πŸ‘‘


⭐ CONTRIBUTORS

  • Florian Ragwitz <rafl@debian.org>
  • Jonathan Rockway <jon@jrock.us>
  • Karen Etheridge <ether@cpan.org>
  • Emmanuel Rodriguez <emmanuel.rodriguez@gmail.com>
  • Jeremiah C. Foster <jeremiah@jeremiahfoster.com>

This software is copyright (c) 2009 by Χ™Χ•Χ‘Χœ Χ§Χ•Χ’'מן (Yuval Kogman).

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.


and that's the whole page, babes πŸ¦‹βœ¨ this doc dropped from perl v5.42.3, dated 2026-08-19, served up fresh in the XS::Ob...::Magic(3pm) manual. go free your structs, be safe, and always write the destructor πŸ’–

πŸ“¦ where this page comes from