#ifndef HPY_UNIVERSAL_HPYDEF_H
#define HPY_UNIVERSAL_HPYDEF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h> /* to make sure "offsetof" is available for our users */
#include "hpy/hpyfunc.h"
#include "hpy/autogen_hpyslot.h"
#include "hpy/cpy_types.h"
typedef void* (*HPyCFunction)();
typedef void (*HPyFunc_Capsule_Destructor)(const char *name, void *pointer, void *context);
[docs]/**
* C structure to define an HPy slot.
*
* It is perfectly fine to fill this structure manually. However, the
* recommended and easier way is to use macro :c:macro:`HPyDef_SLOT`.
*/
typedef struct {
[docs] /**
* The slot to fill.
*/
HPySlot_Slot slot;
[docs] /** Function pointer to the slot's implementation */
HPyCFunction impl;
[docs] /**
* Function pointer to the CPython trampoline function which is used by
* CPython to call the actual HPy function ``impl``.
*/
cpy_PyCFunction cpy_trampoline;
} HPySlot;
[docs]/**
* C structure to define an HPy method.
*
* It is perfectly fine to fill this structure manually. However, the
* recommended and easier way is to use macro :c:macro:`HPyDef_METH`.
*/
typedef struct {
[docs] /** The name of Python attribute (UTF-8 encoded) */
const char *name;
[docs] /** Function pointer of the C function implementation */
HPyCFunction impl;
[docs] /**
* Function pointer to the CPython trampoline function which is used by
* CPython to call the actual HPy function ``impl``.
*/
cpy_PyCFunction cpy_trampoline;
[docs] /** Indicates the C function's expected signature */
HPyFunc_Signature signature;
[docs] /** Docstring of the method (UTF-8 encoded; may be ``NULL``) */
const char *doc;
} HPyMeth;
[docs]/**
* Describes the type (and therefore also the size) of an HPy member.
*/
typedef enum {
[docs] HPyMember_CHAR = 7, /* 1-character string */
[docs] HPyMember_BYTE = 8, /* 8-bit signed int */
/* unsigned variants: */
/* Added by Jack: strings contained in the structure */
[docs] HPyMember_STRING_INPLACE = 13,
/* Added by Lillo: bools contained in the structure (assumed char) */
[docs] HPyMember_OBJECT_EX = 16, /* Like T_OBJECT, but raises AttributeError
when the value is NULL, instead of
converting to None. */
[docs] HPyMember_LONGLONG = 17,
[docs] HPyMember_ULONGLONG = 18,
[docs] HPyMember_HPYSSIZET = 19, /* HPy_ssize_t */
[docs] HPyMember_NONE = 20, /* Value is always None */
} HPyMember_FieldType;
[docs]/**
* C structure to define an HPy member.
*
* It is perfectly fine to fill this structure manually. However, the
* recommended and easier way is to use macro :c:macro:`HPyDef_MEMBER`.
*/
typedef struct {
[docs] /** The name of Python attribute (UTF-8 encoded) */
const char *name;
[docs] /** The type of the HPy member (see enum ``HPyMember_FieldType``). */
HPyMember_FieldType type;
[docs] /**
* The location (byte offset) of the member. Usually computed with
* ``offsetof(type, field)``.
*/
HPy_ssize_t offset;
[docs] /** Flag indicating if the member is read-only */
int readonly;
[docs] /** Docstring of the member (UTF-8 encoded; may be ``NULL``) */
const char *doc;
} HPyMember;
[docs]/**
* C structure to define an HPy get/set descriptor.
*
* It is perfectly fine to fill this structure manually. However, the
* recommended and easier way is to use macros :c:macro:`HPyDef_GET` (to create
* a get descriptor only), :c:macro:`HPyDef_SET` (to create a set descriptor
* only), or :c:macro:`HPyDef_GETSET` (to create both).
*/
typedef struct {
[docs] /** The name of Python attribute (UTF-8 encoded) */
const char *name;
[docs] /** Function pointer of the C getter function (may be ``NULL``) */
HPyCFunction getter_impl;
[docs] /** Function pointer of the C setter function (may be ``NULL``) */
HPyCFunction setter_impl;
[docs] /**
* Function pointer to the CPython trampoline function for the getter (may
* be ``NULL`` if (and only if) ``getter_impl == NULL``)
*/
cpy_getter getter_cpy_trampoline;
[docs] /**
* Function pointer to the CPython trampoline function for the setter (may
* be ``NULL`` if (and only if) ``setter_impl == NULL``)
*/
cpy_setter setter_cpy_trampoline;
[docs] /** Docstring of the get/set descriptor (UTF-8 encoded; may be ``NULL``) */
const char *doc;
[docs] /**
* A value that will be passed to the ``getter_impl``/``setter_impl``
* functions.
*/
void *closure;
} HPyGetSet;
[docs]/**
* Enum to identify an HPy definition's kind.
*/
typedef enum {
[docs] HPyDef_Kind_Member = 3,
[docs] HPyDef_Kind_GetSet = 4,
} HPyDef_Kind;
[docs]/**
* Generic structure of an HPy definition.
*
* This struct can be used to define a slot, method, member, or get/set
* descriptor. For details, see embedded structures :c:struct:`HPySlot`,
* :c:struct:`HPyMeth`, :c:struct:`HPyMember`, or :c:struct:`HPyGetSet`.
*/
typedef struct {
[docs] /**
* The kind of this definition.
* The value of this field determines which one of the embedded members
* ``slot``, ``meth``, ``member``, or ``getset`` is used. Since those are
* combined in a union, only one can be used at a time.
*/
HPyDef_Kind kind;
union {
HPySlot slot;
HPyMeth meth;
HPyMember member;
HPyGetSet getset;
};
} HPyDef;
typedef struct {
cpy_PyCapsule_Destructor cpy_trampoline;
HPyFunc_Capsule_Destructor impl;
} HPyCapsule_Destructor;
typedef struct {
cpy_vectorcallfunc cpy_trampoline;
HPyFunc_keywords impl;
} HPyCallFunction;
// macros to automatically define HPyDefs of various kinds
/* ~~~ HPySlot_SIG ~~~
Macro-magic to automatically determine the HPyFunc_Signature from a
symbolic slot name such as HPy_tp_repr, HPy_nb_add, etc.
*/
#define HPySlot_SIG(SLOT) _HPySlot_SIG__##SLOT
// Macros such as _HPySlot_SIG__HPy_tp_add &co. are defined in autogen_hpyslot.h
/* ~~~ HPyDef_SLOT ~~~
This is the official version of HPyDef_SLOT, which automatically determines
the SIG from the SLOT. The anonymous enum is needed to get a nice
compile-time error in case we pass a SLOT which does not exist, see the
more detailed explanation in the comments around HPyFunc_DECLARE in
hpyfunc.h
*/
#define HPyDef_SLOT_IMPL(SYM, IMPL, SLOT) \
enum { SYM##_slot = SLOT }; \
_HPyDef_SLOT(SYM, IMPL, SLOT, HPySlot_SIG(SLOT))
[docs]/**
* A convenience macro and recommended way to create a definition for an HPy
* slot.
*
* The macro generates a C global variable and an appropriate CPython
* trampoline function. It will fill an :c:struct:`HPyDef` structure appropriately
* and store it in the global variable.
*
* This macro expects a C function ``SYM_impl`` that will be used as the
* implementing slot function.
*
* :param SYM: A C symbol name of the resulting global variable that will
* contain the generated HPy definition. The variable is defined
* as ``static``.
* :param SLOT: The HPy slot identifier.
*/
#define HPyDef_SLOT(SYM, SLOT) \
HPyDef_SLOT_IMPL(SYM, SYM##_impl, SLOT)
// this is the actual implementation, after we determined the SIG
#define _HPyDef_SLOT(SYM, IMPL, SLOT, SIG) \
HPyFunc_DECLARE(IMPL, SIG); \
HPyFunc_TRAMPOLINE(SYM##_trampoline, IMPL, SIG); \
HPyDef SYM = { \
.kind = HPyDef_Kind_Slot, \
.slot = { \
.slot = SLOT, \
.impl = (HPyCFunction)IMPL, \
.cpy_trampoline = (cpy_PyCFunction)SYM##_trampoline \
} \
};
#define HPyDef_METH_IMPL(SYM, NAME, IMPL, SIG, ...) \
HPyFunc_DECLARE(IMPL, SIG); \
HPyFunc_TRAMPOLINE(SYM##_trampoline, IMPL, SIG) \
HPyDef SYM = { \
.kind = HPyDef_Kind_Meth, \
.meth = { \
.name = NAME, \
.impl = (HPyCFunction)IMPL, \
.cpy_trampoline = (cpy_PyCFunction)SYM##_trampoline, \
.signature = SIG, \
__VA_ARGS__ \
} \
};
[docs]/**
* A convenience macro and recommended way to create a definition for an HPy
* method.
*
* The macro generates a C global variable and an appropriate CPython
* trampoline function. It will fill an :c:struct:`HPyDef` structure appropriately
* and store it in the global variable.
*
* This macro expects a C function ``SYM_impl`` that will be used as the
* implementing C function.
*
* :param SYM: A C symbol name of the resulting global variable that will
* contain the generated HPy definition. The variable is defined
* as ``static``.
* :param NAME: The Python attribute name (UTF-8 encoded).
* :param SIG: The implementation's C signature (see
* :c:enum:`HPyFunc_Signature`).
*/
#define HPyDef_METH(SYM, NAME, SIG, ...) \
HPyDef_METH_IMPL(SYM, NAME, SYM##_impl, SIG, __VA_ARGS__)
[docs]/**
* A convenience macro and recommended way to create a definition for an HPy
* member.
*
* The macro generates a C global variable. It will fill an :c:struct:`HPyDef`
* structure appropriately and store it in the global variable.
*
* :param SYM: A C symbol name of the resulting global variable that will
* contain the generated HPy definition. The variable is defined
* as ``static``.
* :param NAME: The Python attribute name (UTF-8 encoded).
* :param TYPE: The implementation's C signature (see
* :c:enum:`HPyFunc_Signature`).
* :param OFFSET: The Python attribute name (UTF-8 encoded).
* :param .readonly: Optional flag indicating if the member is read-only.
* :param .doc: Optional docstring (UTF-8 encoded).
*/
#define HPyDef_MEMBER(SYM, NAME, TYPE, OFFSET, ...) \
HPyDef SYM = { \
.kind = HPyDef_Kind_Member, \
.member = { \
.name = NAME, \
.type = TYPE, \
.offset = OFFSET, \
__VA_ARGS__ \
} \
};
#define HPyDef_GET_IMPL(SYM, NAME, GETIMPL, ...) \
HPyFunc_DECLARE(GETIMPL, HPyFunc_GETTER); \
HPyFunc_TRAMPOLINE(SYM##_get_trampoline, GETIMPL, HPyFunc_GETTER); \
HPyDef SYM = { \
.kind = HPyDef_Kind_GetSet, \
.getset = { \
.name = NAME, \
.getter_impl = (HPyCFunction)GETIMPL, \
.getter_cpy_trampoline = (cpy_getter)SYM##_get_trampoline, \
__VA_ARGS__ \
} \
};
[docs]/**
* A convenience macro and recommended way to create a definition for an HPy
* get descriptor.
*
* The macro generates a C global variable. It will fill an :c:struct:`HPyDef`
* structure appropriately and store it in the global variable.
*
* :param SYM: A C symbol name of the resulting global variable that will
* contain the generated HPy definition. The variable is defined
* as ``static``.
* :param NAME: The Python attribute name (UTF-8 encoded).
* :param .doc: Optional docstring (UTF-8 encoded).
* :param .closure: Optional pointer, providing additional data for the getter.
*/
#define HPyDef_GET(SYM, NAME, ...) \
HPyDef_GET_IMPL(SYM, NAME, SYM##_get, __VA_ARGS__)
#define HPyDef_SET_IMPL(SYM, NAME, SETIMPL, ...) \
HPyFunc_DECLARE(SETIMPL, HPyFunc_SETTER); \
HPyFunc_TRAMPOLINE(SYM##_set_trampoline, SETIMPL, HPyFunc_SETTER); \
HPyDef SYM = { \
.kind = HPyDef_Kind_GetSet, \
.getset = { \
.name = NAME, \
.setter_impl = (HPyCFunction)SETIMPL, \
.setter_cpy_trampoline = (cpy_setter)SYM##_set_trampoline, \
__VA_ARGS__ \
} \
};
[docs]/**
* A convenience macro and recommended way to create a definition for an HPy
* set descriptor.
*
* The macro generates a C global variable. It will fill an :c:struct:`HPyDef`
* structure appropriately and store it in the global variable.
*
* :param SYM: A C symbol name of the resulting global variable that will
* contain the generated HPy definition. The variable is defined
* as ``static``.
* :param NAME: The Python attribute name (UTF-8 encoded).
* :param .doc: Optional docstring (UTF-8 encoded).
* :param .closure: Optional pointer, providing additional data for the setter.
*/
#define HPyDef_SET(SYM, NAME, ...) \
HPyDef_SET_IMPL(SYM, NAME, SYM##_set, __VA_ARGS__)
#define HPyDef_GETSET_IMPL(SYM, NAME, GETIMPL, SETIMPL, ...) \
HPyFunc_DECLARE(GETIMPL, HPyFunc_GETTER); \
HPyFunc_TRAMPOLINE(SYM##_get_trampoline, GETIMPL, HPyFunc_GETTER); \
HPyFunc_DECLARE(SETIMPL, HPyFunc_SETTER); \
HPyFunc_TRAMPOLINE(SYM##_set_trampoline, SETIMPL, HPyFunc_SETTER); \
HPyDef SYM = { \
.kind = HPyDef_Kind_GetSet, \
.getset = { \
.name = NAME, \
.getter_impl = (HPyCFunction)GETIMPL, \
.setter_impl = (HPyCFunction)SETIMPL, \
.getter_cpy_trampoline = (cpy_getter)SYM##_get_trampoline, \
.setter_cpy_trampoline = (cpy_setter)SYM##_set_trampoline, \
__VA_ARGS__ \
} \
};
[docs]/**
* A convenience macro and recommended way to create a definition for an HPy
* get/set descriptor.
*
* The macro generates a C global variable. It will fill an :c:struct:`HPyDef`
* structure appropriately and store it in the global variable.
*
* :param SYM: A C symbol name of the resulting global variable that will
* contain the generated HPy definition. The variable is defined
* as ``static``.
* :param NAME: The Python attribute name (UTF-8 encoded).
* :param .doc: Optional docstring (UTF-8 encoded).
* :param .closure: Optional pointer, providing additional data for the getter
* and setter.
*/
#define HPyDef_GETSET(SYM, NAME, ...) \
HPyDef_GETSET_IMPL(SYM, NAME, SYM##_get, SYM##_set, __VA_ARGS__)
#define HPyCapsule_DESTRUCTOR(SYM) \
static void SYM##_impl(const char *name, void *pointer, void *context); \
HPyCapsule_DESTRUCTOR_TRAMPOLINE(SYM##_trampoline, SYM##_impl); \
static HPyCapsule_Destructor SYM = { \
.cpy_trampoline = SYM##_trampoline, \
.impl = SYM##_impl \
};
[docs]/**
* A convenience macro and the recommended way to create a call function
* definition.
*
* The macro generates a C global variable with name ``SYM``. It will fill an
* :c:struct:`HPyCallFunction` structure appropriately and store it in the
* global variable.
*
* This macro expects a C function ``SYM_impl`` that will be used as the
* implementing C function.
*
* :param SYM: A C symbol name of the resulting global variable that will
* contain the generated call function definition. The variable is
* defined as ``static``.
*/
#define HPyDef_CALL_FUNCTION(SYM) \
HPyFunc_DECLARE(SYM##_impl, HPyFunc_KEYWORDS); \
HPyFunc_TRAMPOLINE(SYM##_trampoline, SYM##_impl, HPyFunc_KEYWORDS); \
static HPyCallFunction SYM = { \
.cpy_trampoline = SYM##_trampoline, \
.impl = SYM##_impl \
};
#ifdef __cplusplus
}
#endif
#endif /* HPY_UNIVERSAL_HPYDEF_H */