| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* XSBind.h -- Functions to help bind Clownfish to Perl XS api. |
| */ |
| |
| #ifndef H_CFISH_XSBIND |
| #define H_CFISH_XSBIND 1 |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #include "charmony.h" |
| #include "Lucy/Object/Obj.h" |
| #include "Lucy/Object/ByteBuf.h" |
| #include "Lucy/Object/CharBuf.h" |
| #include "Lucy/Object/Err.h" |
| #include "Lucy/Object/Hash.h" |
| #include "Lucy/Object/Num.h" |
| #include "Lucy/Object/VArray.h" |
| #include "Lucy/Object/VTable.h" |
| |
| #include "EXTERN.h" |
| #include "perl.h" |
| #include "XSUB.h" |
| |
| #define NEED_newRV_noinc_GLOBAL |
| #include "ppport.h" |
| |
| /** Given either a class name or a perl object, manufacture a new Clownfish |
| * object suitable for supplying to a cfish_Foo_init() function. |
| */ |
| cfish_Obj* |
| cfish_XSBind_new_blank_obj(SV *either_sv); |
| |
| /** Test whether an SV is defined. Handles "get" magic, unlike SvOK on its |
| * own. |
| */ |
| static CHY_INLINE chy_bool_t |
| cfish_XSBind_sv_defined(SV *sv) { |
| if (!sv || !SvANY(sv)) { return false; } |
| if (SvGMAGICAL(sv)) { mg_get(sv); } |
| return SvOK(sv); |
| } |
| |
| /** If the SV contains a Clownfish object which passes an "isa" test against the |
| * passed-in VTable, return a pointer to it. If not, but |
| * <code>allocation</code> is non-NULL and a ZombieCharBuf would satisfy the |
| * "isa" test, stringify the SV, create a ZombieCharBuf using |
| * <code>allocation</code>, assign the SV's string to it, and return that |
| * instead. If all else fails, throw an exception. |
| */ |
| cfish_Obj* |
| cfish_XSBind_sv_to_cfish_obj(SV *sv, cfish_VTable *vtable, void *allocation); |
| |
| /** As XSBind_sv_to_cfish_obj above, but returns NULL instead of throwing an |
| * exception. |
| */ |
| cfish_Obj* |
| cfish_XSBind_maybe_sv_to_cfish_obj(SV *sv, cfish_VTable *vtable, |
| void *allocation); |
| |
| |
| /** Derive an SV from a Clownfish object. If the Clownfish object is NULL, the SV |
| * will be undef. |
| * |
| * The new SV has single refcount for which the caller must take |
| * responsibility. |
| */ |
| static CHY_INLINE SV* |
| cfish_XSBind_cfish_obj_to_sv(cfish_Obj *obj) { |
| return obj ? (SV*)Cfish_Obj_To_Host(obj) : newSV(0); |
| } |
| |
| /** XSBind_cfish_obj_to_sv, with a cast. |
| */ |
| #define CFISH_OBJ_TO_SV(_obj) cfish_XSBind_cfish_obj_to_sv((cfish_Obj*)_obj) |
| |
| /** As XSBind_cfish_obj_to_sv above, except decrements the object's refcount |
| * after creating the SV. This is useful when the Clownfish expression creates a new |
| * refcount, e.g. a call to a constructor. |
| */ |
| static CHY_INLINE SV* |
| cfish_XSBind_cfish_obj_to_sv_noinc(cfish_Obj *obj) { |
| SV *retval; |
| if (obj) { |
| retval = (SV*)Cfish_Obj_To_Host(obj); |
| Cfish_Obj_Dec_RefCount(obj); |
| } |
| else { |
| retval = newSV(0); |
| } |
| return retval; |
| } |
| |
| /** XSBind_cfish_obj_to_sv_noinc, with a cast. |
| */ |
| #define CFISH_OBJ_TO_SV_NOINC(_obj) \ |
| cfish_XSBind_cfish_obj_to_sv_noinc((cfish_Obj*)_obj) |
| |
| /** Deep conversion of Clownfish objects to Perl objects -- CharBufs to UTF-8 |
| * SVs, ByteBufs to SVs, VArrays to Perl array refs, Hashes to Perl hashrefs, |
| * and any other object to a Perl object wrapping the Clownfish Obj. |
| */ |
| SV* |
| cfish_XSBind_cfish_to_perl(cfish_Obj *obj); |
| |
| /** Deep conversion of Perl data structures to Clownfish objects -- Perl hash |
| * to Hash, Perl array to VArray, Clownfish objects stripped of their |
| * wrappers, and everything else stringified and turned to a CharBuf. |
| */ |
| cfish_Obj* |
| cfish_XSBind_perl_to_cfish(SV *sv); |
| |
| /** Convert a ByteBuf into a new string SV. |
| */ |
| SV* |
| cfish_XSBind_bb_to_sv(const cfish_ByteBuf *bb); |
| |
| /** Convert a CharBuf into a new UTF-8 string SV. |
| */ |
| SV* |
| cfish_XSBind_cb_to_sv(const cfish_CharBuf *cb); |
| |
| /** Turn on overloading for the supplied Perl object and its class. |
| */ |
| void |
| cfish_XSBind_enable_overload(void *pobj); |
| |
| /** Process hash-style params passed to an XS subroutine. The varargs must be |
| * a NULL-terminated series of ALLOT_ macros. |
| * |
| * cfish_XSBind_allot_params(stack, start, num_stack_elems, |
| * "Lucy::Search::TermQuery::new_PARAMS", |
| * ALLOT_OBJ(&field, "field", 5, LUCY_CHARBUF, true, alloca(cfish_ZCB_size()), |
| * ALLOT_OBJ(&term, "term", 4, LUCY_CHARBUF, true, alloca(cfish_ZCB_size()), |
| * NULL); |
| * |
| * The following ALLOT_ macros are available for primitive types: |
| * |
| * ALLOT_I8(ptr, key, keylen, required) |
| * ALLOT_I16(ptr, key, keylen, required) |
| * ALLOT_I32(ptr, key, keylen, required) |
| * ALLOT_I64(ptr, key, keylen, required) |
| * ALLOT_U8(ptr, key, keylen, required) |
| * ALLOT_U16(ptr, key, keylen, required) |
| * ALLOT_U32(ptr, key, keylen, required) |
| * ALLOT_U64(ptr, key, keylen, required) |
| * ALLOT_BOOL(ptr, key, keylen, required) |
| * ALLOT_CHAR(ptr, key, keylen, required) |
| * ALLOT_SHORT(ptr, key, keylen, required) |
| * ALLOT_INT(ptr, key, keylen, required) |
| * ALLOT_LONG(ptr, key, keylen, required) |
| * ALLOT_SIZE_T(ptr, key, keylen, required) |
| * ALLOT_F32(ptr, key, keylen, required) |
| * ALLOT_F64(ptr, key, keylen, required) |
| * |
| * The four arguments to these ALLOT_ macros have the following meanings: |
| * |
| * ptr -- A pointer to the variable to be extracted. |
| * key -- The name of the parameter as a C string. |
| * keylen -- The length of the parameter name in bytes. |
| * required -- A boolean indicating whether the parameter is required. |
| * |
| * If a required parameter is not present, allot_params() will immediately |
| * cease processing of parameters, set Err_error and return false. |
| * |
| * Use the following macro if a Clownfish object is desired: |
| * |
| * ALLOT_OBJ(ptr, key, keylen, required, vtable, allocation) |
| * |
| * The "vtable" argument must be the VTable corresponding to the class of the |
| * desired object. The "allocation" argument must be a blob of memory |
| * allocated on the stack sufficient to hold a ZombieCharBuf. (Use |
| * cfish_ZCB_size() to find the allocation size.) |
| * |
| * To extract a Perl scalar, use the following ALLOT_ macro: |
| * |
| * ALLOT_SV(ptr, key, keylen, required) |
| * |
| * @param stack The Perl stack. |
| * @param start Where on the Perl stack to start looking for params. For |
| * methods, this would typically be 1; for functions, most likely 0. |
| * @param num_stack_elems The number of arguments passed to the Perl function |
| * (generally, the XS variable "items"). |
| * @param params_hash_name The name of a package global hash. Any param |
| * labels which are not present in this hash will trigger an exception. |
| * @return true on success, false on failure (sets Err_error). |
| */ |
| chy_bool_t |
| cfish_XSBind_allot_params(SV** stack, int32_t start, |
| int32_t num_stack_elems, |
| char* params_hash_name, ...); |
| |
| #define XSBIND_WANT_I8 0x1 |
| #define XSBIND_WANT_I16 0x2 |
| #define XSBIND_WANT_I32 0x3 |
| #define XSBIND_WANT_I64 0x4 |
| #define XSBIND_WANT_U8 0x5 |
| #define XSBIND_WANT_U16 0x6 |
| #define XSBIND_WANT_U32 0x7 |
| #define XSBIND_WANT_U64 0x8 |
| #define XSBIND_WANT_BOOL 0x9 |
| #define XSBIND_WANT_F32 0xA |
| #define XSBIND_WANT_F64 0xB |
| #define XSBIND_WANT_OBJ 0xC |
| #define XSBIND_WANT_SV 0xD |
| |
| #if (CHY_SIZEOF_CHAR == 1) |
| #define XSBIND_WANT_CHAR XSBIND_WANT_I8 |
| #else |
| #error Can't build unless sizeof(char) == 1 |
| #endif |
| |
| #if (CHY_SIZEOF_SHORT == 2) |
| #define XSBIND_WANT_SHORT XSBIND_WANT_I16 |
| #else |
| #error Can't build unless sizeof(short) == 2 |
| #endif |
| |
| #if (CHY_SIZEOF_INT == 4) |
| #define XSBIND_WANT_INT XSBIND_WANT_I32 |
| #else // sizeof(int) == 8 |
| #define XSBIND_WANT_INT XSBIND_WANT_I64 |
| #endif |
| |
| #if (CHY_SIZEOF_LONG == 4) |
| #define XSBIND_WANT_LONG XSBIND_WANT_I32 |
| #else // sizeof(long) == 8 |
| #define XSBIND_WANT_LONG XSBIND_WANT_I64 |
| #endif |
| |
| #if (CHY_SIZEOF_SIZE_T == 4) |
| #define XSBIND_WANT_SIZE_T XSBIND_WANT_U32 |
| #else // sizeof(long) == 8 |
| #define XSBIND_WANT_SIZE_T XSBIND_WANT_U64 |
| #endif |
| |
| #define XSBIND_ALLOT_I8(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_I8, NULL, NULL |
| #define XSBIND_ALLOT_I16(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_I16, NULL, NULL |
| #define XSBIND_ALLOT_I32(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_I32, NULL, NULL |
| #define XSBIND_ALLOT_I64(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_I64, NULL, NULL |
| #define XSBIND_ALLOT_U8(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_U8, NULL, NULL |
| #define XSBIND_ALLOT_U16(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_U16, NULL, NULL |
| #define XSBIND_ALLOT_U32(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_U32, NULL, NULL |
| #define XSBIND_ALLOT_U64(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_U64, NULL, NULL |
| #define XSBIND_ALLOT_BOOL(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_BOOL, NULL, NULL |
| #define XSBIND_ALLOT_CHAR(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_CHAR, NULL, NULL |
| #define XSBIND_ALLOT_SHORT(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_SHORT, NULL, NULL |
| #define XSBIND_ALLOT_INT(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_INT, NULL, NULL |
| #define XSBIND_ALLOT_LONG(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_LONG, NULL, NULL |
| #define XSBIND_ALLOT_SIZE_T(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_SIZE_T, NULL, NULL |
| #define XSBIND_ALLOT_F32(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_F32, NULL, NULL |
| #define XSBIND_ALLOT_F64(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_F64, NULL, NULL |
| #define XSBIND_ALLOT_OBJ(ptr, key, keylen, required, vtable, allocation) \ |
| ptr, key, keylen, required, XSBIND_WANT_OBJ, vtable, allocation |
| #define XSBIND_ALLOT_SV(ptr, key, keylen, required) \ |
| ptr, key, keylen, required, XSBIND_WANT_SV, NULL, NULL |
| |
| /* Define short names for most of the symbols in this file. Note that these |
| * short names are ALWAYS in effect, since they are only used for Perl and we |
| * can be confident they don't conflict with anything. (It's prudent to use |
| * full symbols nevertheless in case someone else defines e.g. a function |
| * named "XSBind_sv_defined".) |
| */ |
| #define XSBind_new_blank_obj cfish_XSBind_new_blank_obj |
| #define XSBind_sv_defined cfish_XSBind_sv_defined |
| #define XSBind_sv_to_cfish_obj cfish_XSBind_sv_to_cfish_obj |
| #define XSBind_maybe_sv_to_cfish_obj cfish_XSBind_maybe_sv_to_cfish_obj |
| #define XSBind_cfish_obj_to_sv cfish_XSBind_cfish_obj_to_sv |
| #define XSBind_cfish_obj_to_sv_noinc cfish_XSBind_cfish_obj_to_sv_noinc |
| #define XSBind_cfish_to_perl cfish_XSBind_cfish_to_perl |
| #define XSBind_perl_to_cfish cfish_XSBind_perl_to_cfish |
| #define XSBind_bb_to_sv cfish_XSBind_bb_to_sv |
| #define XSBind_cb_to_sv cfish_XSBind_cb_to_sv |
| #define XSBind_enable_overload cfish_XSBind_enable_overload |
| #define XSBind_allot_params cfish_XSBind_allot_params |
| #define ALLOT_I8 XSBIND_ALLOT_I8 |
| #define ALLOT_I16 XSBIND_ALLOT_I16 |
| #define ALLOT_I32 XSBIND_ALLOT_I32 |
| #define ALLOT_I64 XSBIND_ALLOT_I64 |
| #define ALLOT_U8 XSBIND_ALLOT_U8 |
| #define ALLOT_U16 XSBIND_ALLOT_U16 |
| #define ALLOT_U32 XSBIND_ALLOT_U32 |
| #define ALLOT_U64 XSBIND_ALLOT_U64 |
| #define ALLOT_BOOL XSBIND_ALLOT_BOOL |
| #define ALLOT_CHAR XSBIND_ALLOT_CHAR |
| #define ALLOT_SHORT XSBIND_ALLOT_SHORT |
| #define ALLOT_INT XSBIND_ALLOT_INT |
| #define ALLOT_LONG XSBIND_ALLOT_LONG |
| #define ALLOT_SIZE_T XSBIND_ALLOT_SIZE_T |
| #define ALLOT_F32 XSBIND_ALLOT_F32 |
| #define ALLOT_F64 XSBIND_ALLOT_F64 |
| #define ALLOT_OBJ XSBIND_ALLOT_OBJ |
| #define ALLOT_SV XSBIND_ALLOT_SV |
| |
| /* Strip the prefix from some common ClownFish symbols where we know there's |
| * no conflict with Perl. It's a little inconsistent to do this rather than |
| * leave all symbols at full size, but the succinctness is worth it. |
| */ |
| #define THROW CFISH_THROW |
| #define WARN CFISH_WARN |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif // H_CFISH_XSBIND |
| |
| |