Ancient

 view release on metacpan or  search on metacpan

lib/object.pm  view on Meta::CPAN

that bypass Perl callback overhead entirely (~5 cycles vs ~100 cycles).

=head3 C API Reference

Include C<object_types.h> in your XS module:

    #include "object_types.h"

=head4 object_register_type_xs

    void object_register_type_xs(pTHX_ const char *name,
                                 ObjectTypeCheckFunc check,
                                 ObjectTypeCoerceFunc coerce);

Register a type with C-level check and optional coercion functions.
Call from your BOOT section. The type name can then be used in
C<object::define()> slot specifications.

Parameters:

=over 4

=item * C<name> - Type name (e.g., "PositiveInt", "Email")

=item * C<check> - C function to validate values (required)

=item * C<coerce> - C function to coerce values (optional, pass NULL)

=back

=head4 ObjectTypeCheckFunc

    typedef bool (*ObjectTypeCheckFunc)(pTHX_ SV *val);

Type check function signature. Return true if value passes the check.

=head4 ObjectTypeCoerceFunc

    typedef SV* (*ObjectTypeCoerceFunc)(pTHX_ SV *val);

Type coercion function signature. Return the coerced value (may be
the same SV or a new mortal). Return NULL if coercion fails.

=head4 object_get_registered_type

    RegisteredType* object_get_registered_type(pTHX_ const char *name);

Look up a registered type by name. Returns NULL if not found.
Useful for introspection or chaining type checks.

=head3 Complete Example

    /* MyTypes.xs */
    #define PERL_NO_GET_CONTEXT
    #include "EXTERN.h"
    #include "perl.h"
    #include "XSUB.h"
    #include "object_types.h"
    
    static bool check_positive_int(pTHX_ SV *val) {
        if (!SvIOK(val) && !(SvPOK(val) && looks_like_number(val)))
            return false;
        return SvIV(val) > 0;
    }
    
    static bool check_email(pTHX_ SV *val) {
        if (SvROK(val)) return false;
        STRLEN len;
        const char *pv = SvPV(val, len);
        const char *at = memchr(pv, '@', len);
        return at && at != pv && at != pv + len - 1;
    }
    
    static SV* coerce_trim(pTHX_ SV *val) {
        STRLEN len;
        const char *pv = SvPV(val, len);
        const char *start = pv;
        const char *end = pv + len;
        while (start < end && isSPACE(*start)) start++;
        while (end > start && isSPACE(*(end-1))) end--;
        return sv_2mortal(newSVpvn(start, end - start));
    }
    
    MODULE = MyTypes  PACKAGE = MyTypes
    
    BOOT:
        object_register_type_xs(aTHX_ "PositiveInt", check_positive_int, NULL);
        object_register_type_xs(aTHX_ "Email", check_email, NULL);
        object_register_type_xs(aTHX_ "TrimmedStr", NULL, coerce_trim);

Usage in Perl:

    use MyTypes;  # Registers types in BOOT
    use object;
    
    object::define('User',
        'id:PositiveInt:required',
        'email:Email',
        'bio:TrimmedStr',
    );
    
    my $user = new User id => 42, email => 'user@example.com';

=head3 Performance Tiers

    Type Source               Check Cost    Total Overhead
    --------------------------------------------------------
    Built-in (Str, Int)       ~0 cycles     inline switch
    Registered C function     ~5 cycles     function pointer
    Perl callback             ~100 cycles   call_sv overhead

=head3 Linking

Your XS module needs to link against the object module. The functions
are exported with C<PERL_CALLCONV> visibility.

=head2 new $class @args

Create a new object. Supports positional or named arguments.

    my $cat = new Cat 'Whiskers', 3;           # positional



( run in 0.684 second using v1.01-cache-2.11-cpan-39bf76dae61 )