Affix

 view release on metacpan or  search on metacpan

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

        }

        size_t n, step;
        const infix_type * el_type;
        if (cat == INFIX_TYPE_COMPLEX) {
            n = 2;
            el_type = res->meta.complex_info.base_type;
            step = el_type->size;
        }
        else if (cat == INFIX_TYPE_ARRAY) {
            n = res->meta.array_info.num_elements;
            el_type = res->meta.array_info.element_type;
            step = resolve_type(aTHX_ el_type)->size;
        }
        else {
            n = res->meta.vector_info.num_elements;
            el_type = res->meta.vector_info.element_type;
            step = el_type->size;
        }

        if (!eager && n > LAZY_ARRAY_THRESHOLD) {
            SV * lazy_placeholder = newSV(0);
            bind_placeholder(aTHX_ lazy_placeholder, ptr, type, 0, 0, false, owner, arena, readonly, false);
            return lazy_placeholder;
        }

        AV * av = newAV();
        Affix_Pin_2_Point_Oh am = {.ptr = ptr, .type = type, .arena = arena, .readonly = readonly};
        sv_magicext((SV *)av, owner, PERL_MAGIC_ext, &vtbl_array, (char *)&am, sizeof(Affix_Pin_2_Point_Oh));

        for (size_t i = 0; i < n; i++) {
            SV * el = newSV(0);
            void * child_ptr = ptr ? ((char *)ptr + (i * step)) : nullptr;
            bind_placeholder(aTHX_ el, child_ptr, el_type, 0, 0, true, (SV *)av, nullptr, readonly, false);
            av_push(av, el);
        }
        return newRV_noinc((SV *)av);
    }
    return newSV(0);
}

/**
 * @brief Recursively constructs a Perl tree (Hash/Array) mapping to a C aggregate.
 * @param ptr Pointer to the raw C memory.
 * @param type The aggregate (struct/union/array) type.
 * @param owner The "root" SV that owns the C memory (lifeline).
 * @return A new reference to the constructed Perl aggregate.
 */
SV * bind_aggregate(pTHX_ void * ptr, const infix_type * type, SV * owner, bool readonly) {
    return _bind_aggregate_internal(aTHX_ ptr, type, owner, nullptr, false, readonly);
}

/**
 * @brief Public Strategy: Used by cast() to handle anonymous type lifecycle.
 */
SV * bind_aggregate_anon(pTHX_ void * ptr, const infix_type * type, SV * owner, infix_arena_t * arena, bool readonly) {
    return _bind_aggregate_internal(aTHX_ ptr, type, owner, arena, false, readonly);
}

/**
 * @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;

    SV * owner = (SvROK(in) && sv_derived_from(in, "Affix::Memory")) ? SvRV(in) : nullptr;
    infix_type * new_type = nullptr;
    infix_arena_t * local_arena = nullptr;



( run in 1.602 second using v1.01-cache-2.11-cpan-84de2e75c66 )