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 )