#ifndef HPy_H
#define HPy_H
#ifdef __cplusplus
extern "C" {
#endif
/* ~~~~~~~~~~~~~~~~ HPy ABI version ~~~~~~~~~~~~~~~ */
// NOTE: these must be kept on sync with the equivalent variables in hpy/devel/abitag.py
/**
* The ABI version.
*
* Minor version N+1 is binary compatible to minor version N. Major versions
* are not binary compatible (note: HPy can run several binary incompatible
* versions in one process).
*/
#define HPY_ABI_VERSION 0
#define HPY_ABI_VERSION_MINOR 0
#define HPY_ABI_TAG "hpy0"
/* ~~~~~~~~~~~~~~~~ HPy ABI macros ~~~~~~~~~~~~~~~~ */
/* The following macros are used to determine which kind of module we want to
compile. The build system must set one of these (e.g. by using `gcc
-D...`). This is the approach used by the setuptools support provided by
hpy.devel:
- HPY_ABI_CPYTHON
- HPY_ABI_UNIVERSAL
- HPY_ABI_HYBRID
In addition we also define HPY_ABI which is a string literal containing a
string representation of it.
*/
#if defined(HPY_ABI_CPYTHON)
# if defined(HPY_ABI_HYBRID)
# error "Conflicting macros are defined: HPY_ABI_CPYTHON and HPY_ABI_HYBRID"
# endif
# if defined(HPY_ABI_UNIVERSAL)
# error "Conflicting macros are defined: HPY_ABI_CPYTHON and HPY_ABI_UNIVERSAL"
# endif
# define HPY_ABI "cpython"
#elif defined(HPY_ABI_HYBRID)
# if defined(HPY_ABI_UNIVERSAL)
# error "Conflicting macros are defined: HPY_ABI_HYBRID and HPY_ABI_UNIVERSAL"
# endif
# define HPY_ABI "hybrid"
#elif defined(HPY_ABI_UNIVERSAL)
# define HPY_ABI "universal"
#else
# error "Cannot determine the desired HPy ABI: you must set one of HPY_ABI_CPYTHON, HPY_ABI_UNIVERSAL or HPY_ABI_HYBRID"
#endif
#if defined(HPY_ABI_CPYTHON) || defined(HPY_ABI_HYBRID)
# define PY_SSIZE_T_CLEAN
# include <Python.h>
#endif
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
/* ~~~~~~~~~~~~~~~~ useful macros ~~~~~~~~~~~~~~~~ */
#ifdef __GNUC__
# define _HPy_HIDDEN __attribute__((visibility("hidden")))
# define _HPy_UNUSED __attribute__((unused))
#else
# define _HPy_HIDDEN
# define _HPy_UNUSED
#endif /* __GNUC__ */
#define _HPy_UNUSED_ARG(x) (__HPy_UNUSED_TAGGED ## x) _HPy_UNUSED
#if defined(__clang__) || \
(defined(__GNUC__) && \
((__GNUC__ >= 3) || \
(__GNUC__ == 2) && (__GNUC_MINOR__ >= 5)))
# define _HPy_NO_RETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER)
# define _HPy_NO_RETURN __declspec(noreturn)
#else
# define _HPy_NO_RETURN
#endif
// clang and gcc supports __has_attribute, MSVC doesn't. This should be enough
// to be able to use it portably
#ifdef __has_attribute
# define _HPY_compiler_has_attribute(x) __has_attribute(x)
#else
# define _HPY_compiler_has_attribute(x) 0
#endif
#ifdef HPY_ABI_UNIVERSAL
# if _HPY_compiler_has_attribute(error)
// gcc, clang>=14
# define _HPY_LEGACY __attribute__((error("Cannot use legacy functions when targeting the HPy Universal ABI")))
# else
// we don't have any diagnostic feature, too bad
# define _HPY_LEGACY
# endif
#else
// in non-universal modes, we don't attach any attribute
# define _HPY_LEGACY
#endif
#if defined(_MSC_VER) && defined(__cplusplus) // MSVC C4576
# define _hconv(h) {h}
# define _hfconv(h) {h}
# define _htsconv(h) {h}
# define _hgconv(h) {h}
#else
# define _hconv(h) ((HPy){h})
# define _hfconv(h) ((HPyField){h})
# define _htsconv(h) ((HPyThreadState){h})
# define _hgconv(h) ((HPyGlobal){h})
#endif
/* ~~~~~~~~~~~~~~~~ HPyAPI declaration ~~~~~~~~~~~~~~~~ */
/* We have three different kind of API functions: */
/**
* Public API functions which are exposed to the user, e.g.
* ``HPy_Add`` or ``HPyType_FromSpec``. Generally speaking they are
* thin shims dispatching to the actual implementation:
*
* * In CPython-ABI mode they directly call the corresponding Py* or
* ``HPyAPI_IMPL`` equivalent, e.g. ``PyObject_Add`` or
* ``ctx_Type_FromSpec``.
*
* * In Universal-ABI mode, they always resolve to an indirect call
* through ``HPyContext *``, i.e. ``ctx->ctx_Add(...)``, which on CPython
* dispaches to ``ctx_Add``.
*/
#define HPyAPI_FUNC _HPy_UNUSED static inline
/** An alias for ``HPyAPI_FUNC`` so we can handle it properly in the docs. */
#define HPyAPI_INLINE_HELPER HPyAPI_FUNC
/**
* CPython implementations for ``HPyAPI_FUNC``
* functions. Generally speaking, they are put in ctx_*.c files and they are
* prefixed by ctx\_.
*
* Some of these functions are needed by the CPython ABI mode, and by
* CPython's implementation of hpy.universal: these can be found in
* hpy/devel/src/runtime/ctx_*.c, e.g. ``ctx_Type_FromSpec`` and
* ``ctx_Tuple_FromArray``.
*
* Some other are used ONLY by ``hpy.universal`` and can be found in
* hpy/universal/src/ctx_*.c.
*/
#define HPyAPI_IMPL _HPy_HIDDEN
/**
* These functions are part of the public API but **not** of
* the ABI. They are helpers which are meant to be compiled togeher with every
* extension. E.g. ``HPyArg_Parse`` and ``HPyHelpers_AddType``.
*/
#define HPyAPI_HELPER _HPy_HIDDEN
/* ~~~~~~~~~~~~~~~~ Definition of the type HPy ~~~~~~~~~~~~~~~~ */
/* HPy handles are fully opaque: depending on the implementation, the _i can
be either an integer or a pointer. A few examples:
* in CPython ABI mode, ._i is a PyObject*
* in Universal ABI mode, the meaning of ._i depends on the implementation:
- CPython (i.e., the code in hpy/universal/src/): ._i is the bitwise
invert of a PyObject*
- PyPy: ._i is an index into a list
- GraalPy: ._i is a tagged value, either an index into a list,
or an immediate integer or double value
- Debug mode: _i is a pointer to a DebugHandle, which contains a
another HPy among other stuff
*/
typedef struct _HPy_s { intptr_t _i; } HPy;
typedef struct { intptr_t _i; } HPyField;
typedef struct { intptr_t _i; } HPyGlobal;
typedef struct { intptr_t _lst; } HPyListBuilder;
typedef struct { intptr_t _tup; } HPyTupleBuilder;
typedef struct { intptr_t _i; } HPyTracker;
typedef struct { intptr_t _i; } HPyThreadState;
/* A null handle is officially defined as a handle whose _i is 0. This is true
in all ABI modes. */
#define HPy_NULL _hconv(0)
#define HPy_IsNull(h) ((h)._i == 0)
#define HPyField_NULL _hfconv(0)
#define HPyField_IsNull(f) ((f)._i == 0)
/* Convenience functions to cast between HPy and void*. We need to decide
whether these are part of the official API or not, and maybe introduce a
better naming convention. For now, they are needed for ujson. */
static inline HPy HPy_FromVoidP(void *p) { return _hconv((intptr_t)p); }
static inline void* HPy_AsVoidP(HPy h) { return (void*)h._i; }
/* ~~~~~~~~~~~~~~~~ Definition of other types ~~~~~~~~~~~~~~~~ */
typedef struct _HPyContext_s HPyContext;
[docs]/** An enumeration of the different kinds of source code strings. */
typedef enum {
[docs] /** Parse isolated expressions (e.g. ``a + b``). */
HPy_SourceKind_Expr = 0,
[docs] /**
* Parse sequences of statements as read from a file or other source. This
* is the symbol to use when compiling arbitrarily long Python source code.
*/
HPy_SourceKind_File = 1,
[docs] /**
* Parse a single statement. This is the mode used for the interactive
* interpreter loop.
*/
HPy_SourceKind_Single = 2,
} HPy_SourceKind;
#ifdef HPY_ABI_CPYTHON
typedef Py_ssize_t HPy_ssize_t;
typedef Py_hash_t HPy_hash_t;
typedef Py_UCS4 HPy_UCS4;
# define HPY_SSIZE_T_MAX PY_SSIZE_T_MAX
# define HPY_SSIZE_T_MIN PY_SSIZE_T_MIN
#else
typedef intptr_t HPy_ssize_t;
typedef intptr_t HPy_hash_t;
typedef uint32_t HPy_UCS4;
# define HPY_SSIZE_T_MAX INTPTR_MAX
# define HPY_SSIZE_T_MIN (-HPY_SSIZE_T_MAX-1)
/* HPyCapsule field keys */
typedef enum {
HPyCapsule_key_Pointer = 0,
HPyCapsule_key_Name = 1,
HPyCapsule_key_Context = 2,
HPyCapsule_key_Destructor = 3,
} _HPyCapsule_key;
#endif
/* ~~~~~~~~~~~~~~~~ Additional #includes ~~~~~~~~~~~~~~~~ */
#include "hpy/cpy_types.h"
#include "hpy/hpyexports.h"
#include "hpy/macros.h"
#include "hpy/hpyfunc.h"
#include "hpy/hpydef.h"
#include "hpy/hpytype.h"
#include "hpy/hpymodule.h"
#include "hpy/runtime/argparse.h"
#include "hpy/runtime/buildvalue.h"
#include "hpy/runtime/format.h"
#include "hpy/runtime/helpers.h"
#include "hpy/runtime/structseq.h"
#ifdef HPY_ABI_CPYTHON
# include "hpy/cpython/autogen_ctx.h"
# include "hpy/runtime/ctx_funcs.h"
# include "hpy/runtime/ctx_type.h"
# include "hpy/cpython/misc.h"
# include "hpy/cpython/autogen_api_impl.h"
#else
# include "hpy/universal/autogen_ctx.h"
# include "hpy/universal/autogen_trampolines.h"
# include "hpy/universal/misc_trampolines.h"
#endif
#include "hpy/inline_helpers.h"
#ifdef __cplusplus
}
#endif
#endif /* HPy_H */