Make TradWeight a simple subclass and deprecate
[xapian.git] / xapian-bindings / lua / util.i
blob4793b6a6bee7ceac8b17fff3b1e77bc72508ccc6
1 /* lua/util.i: custom lua typemaps for xapian-bindings
3 * Copyright (C) 2011 Xiaona Han
4 * Copyright (C) 2011,2012,2017,2019,2020 Olly Betts
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA
23 // We use std::unique_ptr<> to avoid leaks.
24 #include <memory>
27 // "end" is a keyword in Lua, so we rename it to "_end"
28 %rename("_end") end;
30 %rename("__tostring") get_description;
32 // On platforms where (sizeof(long) == 4), SWIG by default wraps
33 // Xapian::BAD_VALUENO as a negative constant in Lua, which is then rejected by
34 // a check which disallows passing negative values for unsigned C++ types.
35 // This %apply wraps it as a double constant, and also eliminates the negative
36 // value check.
37 %apply double { Xapian::valueno };
40 #if LUA_VERSION_NUM-0 >= 502
41 // luaL_typerror was removed in Lua 5.2.
42 int luaL_typerror (lua_State *L, int narg, const char *tname) {
43 const char *msg = lua_pushfstring(L, "%s expected, got %s",
44 tname, luaL_typename(L, narg));
45 return luaL_argerror(L, narg, msg);
47 #endif
50 %define SUB_CLASS(NS, CLASS)
52 class lua##CLASS : public NS::CLASS {
53 int r;
54 lua_State* L;
56 public:
57 lua##CLASS(lua_State* S) {
58 L = S;
59 if (!lua_isfunction(L, -1)) {
60 luaL_typerror(L, -1, "function");
62 r = luaL_ref(L, LUA_REGISTRYINDEX);
65 ~lua##CLASS() {
66 luaL_unref(L, LUA_REGISTRYINDEX, r);
69 bool operator()(const std::string& term) const override {
70 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
71 if (!lua_isfunction(L, -1)) {
72 luaL_typerror(L, -1, "function");
75 lua_pushlstring(L, term.data(), term.length());
76 if (lua_pcall(L, 1, 1, 0) != 0) {
77 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
79 if (!lua_isboolean(L, -1)) {
80 luaL_error(L, "function must return a boolean");
82 bool result = lua_toboolean(L, -1);
83 lua_pop(L, 1);
84 return result;
89 %enddef
91 SUB_CLASS(Xapian, ExpandDecider)
92 SUB_CLASS(Xapian, Stopper)
95 class luaMatchDecider : public Xapian::MatchDecider {
96 int r;
97 lua_State* L;
99 public:
100 luaMatchDecider(lua_State* S) {
101 L = S;
102 if (!lua_isfunction(L, -1)) {
103 luaL_typerror(L, -1, "function");
105 r = luaL_ref(L, LUA_REGISTRYINDEX);
108 ~luaMatchDecider() {
109 luaL_unref(L, LUA_REGISTRYINDEX, r);
112 bool operator()(const Xapian::Document& doc) const override {
113 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
114 if (!lua_isfunction(L, -1)) {
115 luaL_typerror(L, -1, "function");
118 SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
119 if (lua_pcall(L, 1, 1, 0) != 0) {
120 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
122 if (!lua_isboolean(L, -1)) {
123 luaL_error(L, "function must return a boolean");
125 bool result = lua_toboolean(L, -1);
126 lua_pop(L, 1);
127 return result;
133 class luaStemImplementation : public Xapian::StemImplementation {
134 int r;
135 lua_State* L;
137 public:
138 luaStemImplementation(lua_State* S) {
139 L = S;
140 if (!lua_isfunction(L, -1)) {
141 luaL_typerror(L, -1, "function");
143 r = luaL_ref(L, LUA_REGISTRYINDEX);
146 ~luaStemImplementation() {
147 luaL_unref(L, LUA_REGISTRYINDEX, r);
150 std::string operator()(const std::string& word) override {
151 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
152 if (!lua_isfunction(L, -1)) {
153 luaL_typerror(L, -1, "function");
156 lua_pushlstring(L, word.data(), word.length());
157 if (lua_pcall(L, 1, 1, 0) != 0) {
158 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
160 if (!lua_isstring(L, -1)) {
161 luaL_error(L, "function must return a string");
163 size_t len;
164 const char * p = lua_tolstring(L, -1, &len);
165 std::string result(p, len);
166 lua_pop(L, 1);
167 return result;
170 std::string get_description() const {
171 return "luaStemImplementation()";
177 class luaKeyMaker : public Xapian::KeyMaker {
178 int r;
179 lua_State* L;
181 public:
182 luaKeyMaker(lua_State* S) {
183 L = S;
184 if (!lua_isfunction(L, -1)) {
185 luaL_typerror(L, -1, "function");
187 r = luaL_ref(L, LUA_REGISTRYINDEX);
190 ~luaKeyMaker() {
191 luaL_unref(L, LUA_REGISTRYINDEX, r);
194 std::string operator()(const Xapian::Document& doc) const override {
195 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
196 if (!lua_isfunction(L, -1)) {
197 luaL_typerror(L, -1, "function");
200 SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
201 if (lua_pcall(L, 1, 1, 0) != 0) {
202 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
204 if (!lua_isstring(L, -1)) {
205 luaL_error(L, "function must return a string");
207 size_t len;
208 const char * p = lua_tolstring(L, -1, &len);
209 std::string result(p, len);
210 lua_pop(L, 1);
211 return result;
217 class luaRangeProcessor : public Xapian::RangeProcessor {
218 int r;
219 lua_State* L;
221 public:
222 luaRangeProcessor(lua_State* S) {
223 L = S;
224 if (!lua_isfunction(L, -1)) {
225 luaL_typerror(L, -1, "function");
227 r = luaL_ref(L, LUA_REGISTRYINDEX);
230 ~luaRangeProcessor() {
231 luaL_unref(L, LUA_REGISTRYINDEX, r);
234 Xapian::Query operator()(const std::string& begin,
235 const std::string& end) override {
236 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
237 if (!lua_isfunction(L, -1)) {
238 luaL_typerror(L, -1, "function");
241 lua_pushlstring(L, begin.data(), begin.length());
242 lua_pushlstring(L, end.data(), end.length());
244 if (lua_pcall(L, 2, 1, 0) != 0) {
245 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
248 // Allow the function to return a string or Query object.
249 if (lua_isstring(L, -1)) {
250 size_t len;
251 const char * p = lua_tolstring(L, -1, &len);
252 std::string result(p, len);
253 lua_pop(L, 1);
254 return Xapian::Query(result);
257 Xapian::Query *subq = 0;
258 if (!lua_isuserdata(L, -1) ||
259 SWIG_ConvertPtr(L, -1, (void **)&subq,
260 SWIGTYPE_p_Xapian__Query, 0) == -1) {
261 lua_pop(L, 1);
262 luaL_error(L, "function must return a string or Query object");
265 lua_pop(L, 1);
266 return *subq;
272 class luaFieldProcessor : public Xapian::FieldProcessor {
273 int r;
274 lua_State* L;
276 public:
277 luaFieldProcessor(lua_State* S) {
278 L = S;
279 if (!lua_isfunction(L, -1)) {
280 luaL_typerror(L, -1, "function");
282 r = luaL_ref(L, LUA_REGISTRYINDEX);
285 ~luaFieldProcessor() {
286 luaL_unref(L, LUA_REGISTRYINDEX, r);
289 Xapian::Query operator()(const std::string& str) override {
290 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
291 if (!lua_isfunction(L, -1)) {
292 luaL_typerror(L, -1, "function");
295 lua_pushlstring(L, str.data(), str.length());
297 if (lua_pcall(L, 1, 1, 0) != 0) {
298 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
301 // Allow the function to return a string or Query object.
302 if (lua_isstring(L, -1)) {
303 size_t len;
304 const char * p = lua_tolstring(L, -1, &len);
305 std::string result(p, len);
306 lua_pop(L, 1);
307 return Xapian::Query(result);
310 Xapian::Query *subq = 0;
311 if (!lua_isuserdata(L, -1) ||
312 SWIG_ConvertPtr(L, -1, (void **)&subq,
313 SWIGTYPE_p_Xapian__Query, 0) == -1) {
314 lua_pop(L, 1);
315 luaL_error(L, "function must return a string or Query object");
318 lua_pop(L, 1);
319 return *subq;
325 class luaMatchSpy : public Xapian::MatchSpy {
326 int r;
327 lua_State* L;
329 public:
330 luaMatchSpy(lua_State* S) {
331 L = S;
332 if (!lua_isfunction(L, -1)) {
333 luaL_typerror(L, -1, "function");
335 r = luaL_ref(L, LUA_REGISTRYINDEX);
338 ~luaMatchSpy() {
339 luaL_unref(L, LUA_REGISTRYINDEX, r);
342 void operator()(const Xapian::Document& doc, double wt) override {
343 lua_rawgeti(L, LUA_REGISTRYINDEX, r);
344 if (!lua_isfunction(L, -1)) {
345 luaL_typerror(L, -1, "function");
348 SWIG_NewPointerObj(L, &doc, SWIGTYPE_p_Xapian__Document, 0);
349 SWIG_NewPointerObj(L, &wt, SWIGTYPE_p_Xapian__Weight, 0);
350 if (lua_pcall(L, 2, 1, 0) != 0) {
351 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
357 // Template.
358 %define SUB_CLASS_TYPEMAPS_(NS, CLASS, PARAM, CODE...)
360 %typemap(typecheck, precedence=100) NS::CLASS * {
361 void *ptr;
362 if (lua_isfunction(L, $input) || (SWIG_isptrtype(L, $input) && !SWIG_ConvertPtr(L, $input, (void **) &ptr, $descriptor(NS::CLASS *), 0))) {
363 $1 = 1;
364 } else {
365 $1 = 0;
368 %typemap(in, noblock=1) NS::CLASS * PARAM {
369 if (lua_isfunction(L, $input)) {
370 auto functor = new lua##CLASS(L);
371 CODE
372 $1 = functor;
373 } else {
374 if (!SWIG_IsOK(SWIG_ConvertPtr(L, $input, (void**)&$1, $descriptor(NS::CLASS *), 0))) {
375 SWIG_fail;
380 %enddef
382 // Functor classes where Xapian takes ownership of the passed object.
383 #define SUB_CLASS_TYPEMAPS_DISOWNED(NS, CLASS) SUB_CLASS_TYPEMAPS_(NS, CLASS, , )
384 SUB_CLASS_TYPEMAPS_DISOWNED(Xapian, StemImplementation)
386 // Functor classes which don't need to live on after the wrapped C++ method returns.
387 #define SUB_CLASS_TYPEMAPS_EMPHEMERAL(NS, CLASS) SUB_CLASS_TYPEMAPS_(NS, CLASS, (std::unique_ptr<lua##CLASS> cleanup), cleanup.reset(functor);)
388 SUB_CLASS_TYPEMAPS_EMPHEMERAL(Xapian, MatchDecider)
389 SUB_CLASS_TYPEMAPS_EMPHEMERAL(Xapian, ExpandDecider)
391 // Functor classes which use Xapian's optional reference counting.
392 #define SUB_CLASS_TYPEMAPS_PERSISTENT(NS, CLASS) SUB_CLASS_TYPEMAPS_(NS, CLASS, , functor->release();)
393 SUB_CLASS_TYPEMAPS_PERSISTENT(Xapian, Stopper)
394 SUB_CLASS_TYPEMAPS_PERSISTENT(Xapian, KeyMaker)
395 SUB_CLASS_TYPEMAPS_PERSISTENT(Xapian, RangeProcessor)
396 SUB_CLASS_TYPEMAPS_PERSISTENT(Xapian, FieldProcessor)
397 SUB_CLASS_TYPEMAPS_PERSISTENT(Xapian, MatchSpy)
399 %luacode {
400 function xapian.Iterator(begin, _end)
401 local iter = begin;
402 local isFirst = 1
403 return function()
404 if iter:equals(_end) then
405 return nil
406 else
407 if isFirst == 1 then
408 isFirst = 0;
409 return iter
410 else
411 iter:next()
412 if iter:equals(_end) then
413 return nil
415 return iter
422 #define XAPIAN_MIXED_SUBQUERIES_BY_ITERATOR_TYPEMAP
424 %typemap(typecheck, precedence=500) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
425 $1 = lua_istable(L, $input);
426 /* FIXME: if we add more array typemaps, we'll need to check the elements
427 * of the array here to disambiguate. */
431 class XapianSWIGQueryItor {
432 lua_State* L;
433 int index;
434 int i;
436 public:
437 typedef std::random_access_iterator_tag iterator_category;
438 typedef Xapian::Query value_type;
439 typedef Xapian::termcount_diff difference_type;
440 typedef Xapian::Query * pointer;
441 typedef Xapian::Query & reference;
443 XapianSWIGQueryItor() { }
445 void begin(lua_State * S, int index_) {
446 L = S;
447 index = index_;
448 i = 0;
451 void end(lua_State * S, int index_, int n) {
452 L = S;
453 index = index_;
454 i = n;
457 void end() {
458 i = 0;
461 XapianSWIGQueryItor & operator++() {
462 ++i;
463 return *this;
466 Xapian::Query operator*() const {
467 lua_rawgeti(L, index, i+1);
468 if (lua_isstring(L, -1)) {
469 size_t len = 0;
470 const char *p = lua_tolstring(L, -1, &len);
471 lua_pop(L,1);
472 return Xapian::Query(string(p, len));
475 Xapian::Query *subq = 0;
476 if (!lua_isuserdata(L, -1) ||
477 SWIG_ConvertPtr(L, -1, (void **)&subq,
478 SWIGTYPE_p_Xapian__Query, 0) == -1) {
479 lua_pop(L, 1);
480 luaL_argerror(L, index,
481 "elements must be Query objects or strings");
484 lua_pop(L, 1);
485 return *subq;
488 bool operator==(const XapianSWIGQueryItor & o) {
489 return i == o.i;
492 bool operator!=(const XapianSWIGQueryItor & o) {
493 return !(*this == o);
496 difference_type operator-(const XapianSWIGQueryItor &o) const {
497 return i - o.i;
503 %typemap(in) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
504 if (lua_istable(L, $input)) {
505 $1.begin(L, $input);
506 $2.end(L, $input, lua_rawlen(L, $input));
507 } else {
508 $1.end();
509 $2.end();
513 %define OUTPUT_ITERATOR_METHODS(NS, CLASS, ITERATOR_CLASS, ITERATOR_BEGIN, ITERATOR_END, DEREF_METHOD, PARAMETER_NAME, PARAMETER_VALUE)
515 %extend NS::CLASS {
516 std::pair<NS::ITERATOR_CLASS , NS::ITERATOR_CLASS> DEREF_METHOD(PARAMETER_NAME) {
517 return std::make_pair($self->ITERATOR_BEGIN(PARAMETER_VALUE), $self->ITERATOR_END(PARAMETER_VALUE));
521 %typemap(out) std::pair<NS::ITERATOR_CLASS, NS::ITERATOR_CLASS> {
522 lua_getglobal(L, "xapian");
523 lua_pushstring(L, "Iterator");
524 lua_gettable(L, -2);
525 lua_remove(L, -2);
527 if (!lua_isfunction(L, -1)) {
528 luaL_typerror(L, -1, "function");
531 NS::ITERATOR_CLASS * begin = new NS::ITERATOR_CLASS((const NS::ITERATOR_CLASS &)$1.first);
532 SWIG_NewPointerObj(L, (void *) begin, $descriptor(NS::ITERATOR_CLASS *), 1);
534 NS::ITERATOR_CLASS * end = new NS::ITERATOR_CLASS((const NS::ITERATOR_CLASS &)$1.second);
535 SWIG_NewPointerObj(L, (void *) end, $descriptor(NS::ITERATOR_CLASS *), 1);
537 if (lua_pcall(L, 2, 1, 0) != 0) {
538 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
541 SWIG_arg++;
544 %enddef
546 OUTPUT_ITERATOR_METHODS(Xapian, Query, TermIterator, get_terms_begin, get_terms_end, get_terms, void, )
548 OUTPUT_ITERATOR_METHODS(Xapian, QueryParser, TermIterator, stoplist_begin, stoplist_end, stoplist, void, )
550 OUTPUT_ITERATOR_METHODS(Xapian, ESet, ESetIterator, begin, end, terms, void, )
552 OUTPUT_ITERATOR_METHODS(Xapian, MSet, MSetIterator, begin, end, items, void, )
554 OUTPUT_ITERATOR_METHODS(Xapian, Document, TermIterator, termlist_begin, termlist_end, termlist, void, )
555 OUTPUT_ITERATOR_METHODS(Xapian, Document, ValueIterator, values_begin, values_end, values, void, )
557 OUTPUT_ITERATOR_METHODS(Xapian, Enquire, TermIterator, get_matching_terms_begin, get_matching_terms_end, get_matching_terms, Xapian::docid did, did)
558 OUTPUT_ITERATOR_METHODS(Xapian, Enquire, TermIterator, get_matching_terms_begin, get_matching_terms_end, get_matching_terms, const MSetIterator &it, it)
560 OUTPUT_ITERATOR_METHODS(Xapian, ValueCountMatchSpy, TermIterator, values_begin, values_end, values, void, )
561 OUTPUT_ITERATOR_METHODS(Xapian, ValueCountMatchSpy, TermIterator, top_values_begin, top_values_end, top_values, size_t maxvalues, maxvalues)
563 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, allterms_begin, allterms_end, allterms, void, )
564 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, spellings_begin, spellings_end, spellings, void, )
565 OUTPUT_ITERATOR_METHODS(Xapian, Database, PostingIterator, postlist_begin, postlist_end, postlist, const std::string &tname, tname)
566 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, termlist_begin, termlist_end, termlist, Xapian::docid did, did)
567 OUTPUT_ITERATOR_METHODS(Xapian, Database, ValueIterator, valuestream_begin, valuestream_end, valuestream, Xapian::valueno slot, slot)
568 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, allterms_begin, allterms_end, allterms, const std::string &prefix, prefix)
569 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, synonyms_begin, synonyms_end, synonyms, const std::string &term, term)
570 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, synonym_keys_begin, synonym_keys_end, synonym_keys, const std::string &prefix, prefix)
571 OUTPUT_ITERATOR_METHODS(Xapian, Database, TermIterator, metadata_keys_begin, metadata_keys_end, metadata_keys, const std::string &prefix, prefix)
573 %extend Xapian::Database {
574 std::pair<Xapian::PositionIterator , Xapian::PositionIterator> positionlist(Xapian::docid did, const std::string &tname) {
575 return std::make_pair($self->positionlist_begin(did, tname), $self->positionlist_end(did, tname));
579 %typemap(out) std::pair<Xapian::PositionIterator, Xapian::PositionIterator> {
580 lua_getglobal(L, "xapian");
581 lua_pushstring(L, "Iterator");
582 lua_gettable(L, -2);
583 lua_remove(L, -2);
585 if (!lua_isfunction(L, -1)) {
586 luaL_typerror(L, -1, "function");
589 Xapian::PositionIterator * begin = new Xapian::PositionIterator((const Xapian::PositionIterator &)$1.first);
590 SWIG_NewPointerObj(L, (void *) begin, SWIGTYPE_p_Xapian__PositionIterator, 1);
592 Xapian::PositionIterator * end = new Xapian::PositionIterator((const Xapian::PositionIterator &)$1.second);
593 SWIG_NewPointerObj(L, (void *) end, SWIGTYPE_p_Xapian__PositionIterator, 1);
595 if (lua_pcall(L, 2, 1, 0) != 0) {
596 luaL_error(L, "error running function: %s", lua_tostring(L, -1));
599 SWIG_arg++;