{"id":15514628,"url":"https://github.com/fgasper/easyxs","last_synced_at":"2025-10-08T23:22:52.893Z","repository":{"id":141191292,"uuid":"464999628","full_name":"FGasper/easyxs","owner":"FGasper","description":"A library to simplify creation of Perl XS code","archived":false,"fork":false,"pushed_at":"2023-02-05T00:49:23.000Z","size":195,"stargazers_count":11,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-23T03:15:38.559Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FGasper.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-01T17:52:37.000Z","updated_at":"2024-10-19T10:10:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"2a51714b-c1ef-44ec-a299-d7653a55f0c0","html_url":"https://github.com/FGasper/easyxs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Feasyxs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Feasyxs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Feasyxs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Feasyxs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FGasper","download_url":"https://codeload.github.com/FGasper/easyxs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250360509,"owners_count":21417721,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T10:00:18.510Z","updated_at":"2025-10-08T23:22:47.857Z","avatar_url":"https://github.com/FGasper.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EasyXS\n\nThis library is a toolbox that assists with creation \u0026 maintenance\nof [Perl XS](https://perldoc.perl.org/perlxs) code.\n\n# Usage\n\n1. Make this repository a\n[git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules)\nof your own XS module.\n\n2. Replace the standard XS includes (`EXTERN.h`, `perl.h`, and `XSUB.h`)\nwith just `#include \"easyxs/easyxs.h\"`.\n\n… and that’s it! You now have a suite of tools that’ll make writing XS\neasier and safer.\n\n# Rationale\n\nPerl’s C API makes lots of things _possible_ without making them\n_easy_ (or _safe_).\n\nThis library attempts to provide shims around that API that make it easy\nand safe (or, at least, safe-_er_!) to write XS code … maybe even *fun!* :-)\n\n# Library Components\n\n## Initialization\n\n`init.h` includes the standard boilerplate code you normally stick at the\ntop of a `*.xs` file. It also includes a fix for the\n[torrent of warnings that clang 12 throws](https://github.com/Perl/perl5/issues/18780)\nin pre-5.36 perls. `easyxs.h` brings this in, but you can also\n`#include \"easyxs/init.h\"` on its own.\n\n`init.h` also includes a fairly up-to-date (as of this writing!) `ppport.h`.\n\n## Calling Perl\n\n### `void exs_call_sv_void(SV* callback, SV** args)`\n\nLike the Perl API’s `call_sv()` but simplifies argument-passing.\n`args` points to a NULL-terminated array of `SV*`s.\n(It may itself also be NULL.)\n\nThe callback is called in void context, so nothing is returned.\n\n**IMPORTANT CAVEATS:**\n\n- This does _not_ trap exceptions. Ensure either that the callback won’t\nthrow, or that no corruption will happen in the event of an exception.\n\n- This **mortalizes** each `args` member. That means Perl\nwill reduce each of those SVs’ reference counts at some point “soon” after.\nThis is often desirable, but not always; to counteract it, do `SvREFCNT_inc()`\naround whichever arguments you want to be unaffected by the mortalization.\n(They’ll still be mortalized, but the eventual reference-count reduction will\njust have zero net effect.)\n\n### `SV* exs_call_sv_scalar(SV* callback, SV** args)`\n\nLike `exs_call_sv_void()` but calls the callback in scalar context.\nThe result is returned.\n\n### `SV* exs_call_sv_scalar_trapped(SV* callback, SV** args, SV** error_svp)`\n\nLike `exs_call_sv_scalar()` but traps exceptions. If one happens,\nNULL is returned, and `*error_svp` will contain the error SV.\n(This SV is a **copy** of Perl’s `$@` and so **must be freed**.)\n\n### `void exs_call_sv_void_trapped(SV* callback, SV** args, SV** error_svp)`\n\nLike `exs_call_sv_scalar_trapped()` but calls the Perl callback in void\ncontext and doesn’t return anything.\n\n### `void exs_call_method_void(SV* object, const char* methname, SV** args)`\n\nLike `exs_call_sv_void()` but for calling object methods. See\nthe Perl API’s `call_method()` for more details.\n\n### `SV* exs_call_method_scalar(SV* object, const char* methname, SV** args)`\n\nLike `exs_call_method_void()` but calls the method in scalar context.\nThe result is returned.\n\n### `SV** exs_call_sv_list(SV* callback, SV** args)`\n\nLike `exs_call_sv_scalar` but calls the callback in list context.\n\nThe return is a pointer to a NUL-terminated array of `SV*`s. The pointer will\nbe freed automatically, but the SVs are non-mortals with reference count 1,\nso you’ll need to dispose of those however is best for you.\n\n### `SV** exs_call_sv_list_trapped(SV* callback, SV** args, SV** error_svp)`\n\nLike both `exs_call_sv_list` and `exs_call_sv_scalar_trapped`. If the\ncallback throws, this behaves as `exs_call_sv_scalar_trapped` does;\notherwise, this behaves as `exs_call_sv_list` does.\n\n## SV “Typing”\n\nPerl scalars are supposed to be “untyped”, at least insofar as\nstrings/numbers. When conversing with other languages, though, or\nserializing it’s usually helpful to break things down in greater\ndetail.\n\nEasyXS defines an `exs_sv_type` macro that takes an SV as argument\nand returns a member of `enum exs_sv_type_e` (typedef’d as just\n`exs_sv_type_e`; see `easyxs_scalar.h` for values). The logic is compatible\nwith the serialization logic formulated during Perl 5.36’s development cycle.\n\n## SV/Number Conversion\n\n### `UV* exs_SvUV(SV* sv)`\n\nLike `SvUV`, but if the SV’s content can’t be a UV\n(e.g., the IV is negative, or the string has non-numeric characters)\nan exception is thrown.\n\n## SV/String Conversion\n\n### `char* exs_SvPVbyte_nolen(SV* sv)`\n\nLike the Perl API’s `SvPVbyte_nolen`, but if there are any NULs in the\nstring then an exception is thrown.\n\n### `char* exs_SvPVutf8_nolen(SV* sv)`\n\nLike `exs_SvPVbyte_nolen()` but returns the code points as UTF-8 rather\nthan Latin-1/bytes.\n\n## Struct References\n\nIt’s common in XS code to need to persist a C struct via a Perl variable,\nthen free that struct once the Perl variable is garbage-collected. Perl’s\n`sv_setref_pv` and similar APIs present one way to do this: store a pointer\nto the struct in an SV, then pass around a blessed (Perl) reference to that\nSV, freeing the struct when the referent SV gets DESTROYed.\n\nEasyXS’s “struct references” are a slight simplification of this workflow:\nuse the referent SV’s PV to store the struct itself. Thus, Perl cleans up\nthe struct for you, and there’s no need for a DESTROY to free your struct.\n(You may, of course, still need a DESTROY to free blocks to which your\nstruct refers.)\n\n### `exs_new_structref(type, classname)`\n\nCreates a new structref for the given (C) `type` and (Perl) `classname`.\n\n### `exs_structref_ptr(svrv)`\n\nReturns a pointer to `svrv`’s contained struct.\n\n## Debugging\n\n### `exs_debug_sv_summary(SV* sv)`\n\nWrites a visual representation of the SV’s contents to `Perl_debug_log`.\n**NO** trailing newline is written.\n\n### `exs_debug_showstack(const char *pattern, ...)`\n\nWrites a visual representation of Perl’s argument stack\nto `Perl_debug_log`.\n\n# Usage Notes\n\nIf you use GitHub Actions or similar, ensure that you grab the submodule\nas part of your workflow’s checkout. If you use GitHub’s own\n[checkout](https://github.com/actions/checkout) workflow, that’s:\n\n    - with:\n        submodules: true  # (or `recursive`)\n\nAlternatively, run `git submodule init \u0026\u0026 git submodule update`\nduring the workflow’s repository setup.\n\n# License \u0026 Copyright\n\nCopyright 2022 by Gasper Software Consulting. All rights reserved.\n\nThis library is released under the terms of the\n[MIT License](https://mitlicense.org/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgasper%2Feasyxs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffgasper%2Feasyxs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgasper%2Feasyxs/lists"}