File-Raw

 view release on metacpan or  search on metacpan

include/file_plugin.h  view on Meta::CPAN

/*
 * file_plugin.h - Plugin system for File::Raw
 *
 * A "plugin" is a named bundle of
 * up to four phase callbacks (read / write / record / stream) that
 * downstream XS modules (or pure-Perl code via the bridge) register at
 * BOOT time. Callers opt in per call by passing
 *
 *     File::Raw::slurp($path, plugin => 'csv', sep => ';')
 *
 * Options after the positional args become an HV that is exposed to the
 * plugin via FilePluginContext::options. The HV is per-call and mortal:
 * a plugin must SvREFCNT_inc anything it intends to keep beyond return.
 *
 * Symbol layout follows the same RTLD_GLOBAL pattern as the rest of
 * File::Raw: declarations live here; the implementation lives in
 * file.c (Raw.so), and all other XS modules call into Raw.so through
 * the exported function symbols.
 */

#ifndef FILE_PLUGIN_H
#define FILE_PLUGIN_H

#include "EXTERN.h"
#include "perl.h"

/* Phase identifiers. A plugin only has to implement the phases it cares
 * about; unimplemented phases are NULL function pointers and any caller
 * that requests them gets a croak. */
typedef enum {
    FILE_PLUGIN_PHASE_READ      = 1,  /* whole-file slurp transform           */
    FILE_PLUGIN_PHASE_WRITE     = 2,  /* whole-file spew/append transform     */
    FILE_PLUGIN_PHASE_RECORD    = 3,  /* per-record dispatch (predicate/map)  */
    FILE_PLUGIN_PHASE_STREAM    = 4   /* chunked feed for streaming           */
} FilePluginPhase;

/* Per-call dispatch context. Lifetime: single dispatch call. */
typedef struct FilePluginContext {
    const char  *path;          /* file path, NUL-terminated, may be NULL    */
    SV          *data;          /* read: bytes from disk; write: payload     */
    SV          *callback;      /* per-record cb when streaming, else NULL   */
    HV          *options;       /* per-call opts; mortal; never NULL         */
    int          phase;         /* FILE_PLUGIN_PHASE_*                       */
    int          cancel;        /* set non-zero to cancel op                 */
    void        *plugin_state;  /* opaque, copied from FilePlugin::state     */
    void        *call_state;    /* NULL on entry; plugin scratch slot for    */
                                /* per-dispatch state. Survives across       */
                                /* chunks within one STREAM dispatch; reset  */
                                /* every fresh dispatch. Plugin owns the     */
                                /* alloc/free lifecycle.                     */
} FilePluginContext;

/* Phase function signatures. */
typedef SV*  (*file_plugin_read_fn)   (pTHX_ FilePluginContext *ctx);
typedef SV*  (*file_plugin_write_fn)  (pTHX_ FilePluginContext *ctx);
/* RECORD: returns the record (possibly transformed) to include, or
 * &PL_sv_undef to exclude (caller interprets - grep filters on truthi-
 * ness, map keeps everything non-NULL). Return NULL or set ctx->cancel
 * to abort iteration. */
typedef SV*  (*file_plugin_record_fn) (pTHX_ FilePluginContext *ctx, SV *record);
typedef int  (*file_plugin_stream_fn) (pTHX_ FilePluginContext *ctx,
                                       const char *chunk, size_t len, int eof);

/* Plugin registration block. The caller owns the storage - typically a
 * file-scope static in the BOOT TU - and must keep it alive for as long
 * as the plugin is registered. The registry stores the pointer, not a
 * copy. */
typedef struct FilePlugin {
    const char            *name;
    /* Field names are suffixed with _fn because plain `read`/`write` collide
     * with Perl's host-IO macros on Win32 (PerlLIO_read/PerlLIO_write), which
     * textually expand any `read`/`write` token followed by `(`. */
    file_plugin_read_fn    read_fn;
    file_plugin_write_fn   write_fn;
    file_plugin_record_fn  record_fn;
    file_plugin_stream_fn  stream_fn;
    void                  *state;
} FilePlugin;

/* ============================================
   C registry API (exported from Raw.so via RTLD_GLOBAL)
   ============================================ */

/* Register a plugin. Returns 1 on success, 0 if a plugin with the same
 * name is already registered (use file_unregister_plugin first), -1 on
 * invalid input (NULL plugin, NULL/empty name). */
int file_register_plugin(pTHX_ const FilePlugin *plugin);

/* Remove a plugin by name. Returns 1 if found and removed, 0 if not. */
int file_unregister_plugin(pTHX_ const char *name);

/* Look up a plugin by name. Returns the registered struct or NULL. */
const FilePlugin *file_lookup_plugin(pTHX_ const char *name);

/* ============================================
   Dispatch helpers used by File::Raw XSUBs

   Each helper:
   - extracts 'plugin' from the HV (croaks if missing)
   - looks up the plugin (croaks if unknown)
   - confirms the phase function pointer is non-NULL (croaks otherwise)



( run in 1.353 second using v1.01-cache-2.11-cpan-140bd7fdf52 )