1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
|
/* 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
|