Affix

 view release on metacpan or  search on metacpan

lib/Affix/marshal.c  view on Meta::CPAN

/**
 * @brief Registers multiple types into the global Infix Type Registry.
 * @param defs The Infix type definition string.
 */
void define_types(pTHX_ const char * defs) {
    dMY_CXT;
    if (infix_register_types(MY_CXT.registry, defs) != INFIX_SUCCESS)
        croak("Parse Error");
}

/**
 * @brief Returns the layout size of a type by name.
 * @param name Type name or AST signature.
 * @return Size in bytes.
 */
IV sizeof_type(pTHX_ const char * name) {
    dMY_CXT;
    const infix_type * t = infix_registry_lookup_type(MY_CXT.registry, name);
    if (!t) {
        infix_arena_t * ta;
        infix_type * tt;
        if (infix_type_from_signature(&tt, &ta, name, MY_CXT.registry) == INFIX_SUCCESS) {
            size_t s = tt->size;
            infix_arena_destroy(ta);
            return s;
        }
    }
    return t ? t->size : 0;
}

/**
 * @brief Returns the byte offset of a member in a struct/union.
 * @param type_name The aggregate type name.
 * @param member_name The member field name.
 * @return Offset in bytes, or -1 if not found.
 */
IV offsetof_member(pTHX_ const char * type_name, const char * member_name) {
    dMY_CXT;
    const infix_type * t = resolve_type(aTHX_ infix_registry_lookup_type(MY_CXT.registry, type_name));
    if (!t || (t->category != INFIX_TYPE_STRUCT && t->category != INFIX_TYPE_UNION))
        return -1;
    for (size_t i = 0; i < t->meta.aggregate_info.num_members; i++)
        if (strEQ(t->meta.aggregate_info.members[i].name, member_name))
            return (IV)t->meta.aggregate_info.members[i].offset;
    return -1;
}

/**
 * @brief Casts a raw pointer (or memory block) to a magic-bound Perl variable mapping its layout.
 * @param in The input SV (integer address or Affix::Memory managed object).
 * @param name The struct or primitive type name to cast the memory into.
 * @return A magic-bound SV tracking the memory block natively.
 */
SV * cast(pTHX_ SV * in, const char * name) {
    dMY_CXT;
    void * addr = get_address_v2(aTHX_ in);
    if (!addr)
        return &PL_sv_undef;

    /* Keep the blessed Affix::Memory object itself as the lifeline so the pin
       holds a strong reference to it. This keeps the memory alive for as long as
       any derived pin exists and lets free()/DESTROY locate the owner. */
    SV * owner = (SvROK(in) && sv_derived_from(in, "Affix::Memory")) ? in : nullptr;
    infix_type * new_type = nullptr;
    infix_arena_t * local_arena = nullptr;

    if (infix_type_from_signature(&new_type, &local_arena, name, MY_CXT.registry) != INFIX_SUCCESS)
        croak("Type not found: %s", name);

    const infix_type * resolved = resolve_type(aTHX_ new_type);
    infix_type_category cat = infix_type_get_category(resolved);

    /* AGGREGATES: Return a Reference (HashRef, ArrayRef, or ScalarRef for strings) */
    if (cat == INFIX_TYPE_STRUCT || cat == INFIX_TYPE_UNION || cat == INFIX_TYPE_ARRAY || cat == INFIX_TYPE_VECTOR ||
        cat == INFIX_TYPE_COMPLEX) {
        return bind_aggregate_anon(aTHX_ addr, new_type, owner, local_arena, false);
    }

    /* PRIMITIVES: Return a scalar reference ($$ptr) to allow writes back to C */
    SV * sv = newSV(0);
    bind_placeholder(aTHX_ sv, addr, new_type, 0, 0, true, owner, local_arena, false, true);
    return newRV_noinc(sv);
}

/**
 * @brief Wraps an existing C pointer with a custom destructor callback into an object payload.
 * @param ptr_iv The raw pointer (as integer).
 * @param dtor_iv The destructor callback pointer (as integer).
 * @return An Affix::Memory object representing the mapped block.
 */
SV * wrap_owned(pTHX_ UV ptr_uv, UV dtor_uv) {
    AV * av = newAV();
    av_push(av, newSVuv(ptr_uv));  /* Use UV */
    av_push(av, newSVuv(dtor_uv)); /* Use UV */
    SV * rv = newRV_noinc((SV *)av);
    sv_bless(rv, gv_stashpv("Affix::Memory", GV_ADD));
    return rv;
}
/**
 * @brief Allocates zeroed C memory and wraps it into a Perl Affix::Memory object.
 * @param size Memory allocation size in bytes.
 * @return An Affix::Memory object representation.
 */
SV * alloc_owned(pTHX_ UV size) {
    void * ptr = safecalloc(1, size);
    SV * sv = newSVuv(PTR2UV(ptr)); /* Use UV */
    SV * rv = newRV_noinc(sv);
    sv_bless(rv, gv_stashpv("Affix::Memory", GV_ADD));
    return rv;
}

/**
 * @brief Garbage Collector Hook: Frees C memory owned by an Affix::Memory object.
 * @details Can fall back to standard `safefree` or use a custom C++ destructor mapping if passed via `wrap_owned`.
 * @param rv The Affix::Memory reference triggered by DESTROY.
 */
void free_owned(pTHX_ SV * rv) {
    if (!rv || !SvROK(rv))
        return;
    SV * sv = SvRV(rv);
    if (SvTYPE(sv) == SVt_PVAV) {



( run in 2.440 seconds using v1.01-cache-2.11-cpan-14f38c9f855 )