1/*
2 * Copyright 2008-2018 Aerospike, Inc.
3 *
4 * Portions may be licensed to Aerospike, Inc. under one or more contributor
5 * license agreements.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8 * use this file except in compliance with the License. You may obtain a copy of
9 * the License at http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17#include <aerospike/mod_lua_val.h>
18#include <aerospike/as_nil.h>
19#include <aerospike/as_val.h>
20#include <aerospike/mod_lua_list.h>
21#include <aerospike/mod_lua_map.h>
22#include <aerospike/mod_lua_record.h>
23#include <aerospike/mod_lua_bytes.h>
24#include <aerospike/mod_lua_geojson.h>
25#include <citrusleaf/alloc.h>
26#include <lua.h>
27#include <lauxlib.h>
28#include <lualib.h>
29#include <stdio.h>
30#include <string.h>
31
32#include "internal.h"
33
34as_val * mod_lua_takeval(lua_State * l, int i) {
35 return mod_lua_toval(l, i);
36}
37
38as_val * mod_lua_retval(lua_State * l) {
39 return mod_lua_toval(l, -1);
40}
41
42/**
43 * Reads a val from the Lua stack
44 * the val returned includes a refcount that must be freed later
45 *
46 * @param l the lua_State to read the val from
47 * @param i the position of the val on the stack
48 * @returns the val if exists, otherwise NULL.
49 */
50as_val * mod_lua_toval(lua_State * l, int i) {
51 switch( lua_type(l, i) ) {
52 case LUA_TNUMBER : {
53 double d = lua_tonumber(l, i);
54 int64_t i64 = (int64_t)d;
55
56 if (d == i64) {
57 return (as_val*) as_integer_new(i64);
58 }
59 else {
60 return (as_val*) as_double_new(d);
61 }
62 }
63 case LUA_TBOOLEAN : {
64 return (as_val *) as_boolean_new(lua_toboolean(l, i));
65 }
66 case LUA_TSTRING : {
67 return (as_val *) as_string_new(cf_strdup(lua_tostring(l, i)), true);
68 }
69 case LUA_TUSERDATA : {
70 mod_lua_box * box = (mod_lua_box *) lua_touserdata(l, i);
71 if ( box && box->value ) {
72 switch( as_val_type(box->value) ) {
73 case AS_BOOLEAN:
74 case AS_INTEGER:
75 case AS_DOUBLE:
76 case AS_STRING:
77 case AS_BYTES:
78 case AS_LIST:
79 case AS_MAP:
80 case AS_REC:
81 case AS_GEOJSON:
82 switch (box->scope) {
83 case MOD_LUA_SCOPE_LUA:
84 as_val_reserve(box->value);
85 return box->value;
86 case MOD_LUA_SCOPE_HOST:
87 return box->value;
88 }
89 default:
90 return NULL;
91 }
92 }
93 else {
94 return (as_val *) NULL;
95 }
96 }
97 case LUA_TNIL :
98 return (as_val *)&as_nil;
99 case LUA_TTABLE :
100 case LUA_TFUNCTION :
101 case LUA_TLIGHTUSERDATA :
102 default:
103 return (as_val *) NULL;
104 }
105}
106
107
108/**
109 * Pushes a val onto the Lua stack
110 *
111 * @param l the lua_State to push the val onto
112 * @param v the val to push on to the stack
113 * @returns number of values pushed
114 */
115int mod_lua_pushval(lua_State * l, const as_val * v) {
116 if ( v == NULL ) {
117 lua_pushnil(l);
118 return 1;
119 }
120
121 switch( as_val_type(v) ) {
122 case AS_BOOLEAN: {
123 lua_pushboolean(l, as_boolean_tobool((as_boolean *) v) );
124 return 1;
125 }
126 case AS_INTEGER: {
127 lua_pushinteger(l, as_integer_toint((as_integer *) v) );
128 return 1;
129 }
130 case AS_DOUBLE: {
131 lua_pushnumber(l, as_double_get((as_double*)v));
132 return 1;
133 }
134 case AS_STRING: {
135 lua_pushstring(l, as_string_tostring((as_string *) v) );
136 return 1;
137 }
138 case AS_BYTES: {
139 as_val_reserve(v);
140 mod_lua_pushbytes(l, (as_bytes *) v);
141 return 1;
142 }
143 case AS_LIST: {
144 as_val_reserve(v);
145 mod_lua_pushlist(l, (as_list *) v);
146 return 1;
147 }
148 case AS_MAP: {
149 as_val_reserve(v);
150 mod_lua_pushmap(l, (as_map *) v);
151 return 1;
152 }
153 case AS_REC: {
154 as_val_reserve(v);
155 mod_lua_pushrecord(l, (as_rec *) v);
156 return 1;
157 }
158 case AS_PAIR: {
159 as_pair * p = (as_pair *) lua_newuserdata(l, sizeof(as_pair));
160 *p = *((as_pair *)v);
161 return 1;
162 }
163 case AS_GEOJSON: {
164 as_val_reserve(v);
165 mod_lua_pushgeojson(l, (as_geojson *) v);
166 return 1;
167 }
168 default: {
169 lua_pushnil(l);
170 return 1;
171 }
172 }
173 return 0;
174}
175
176
177
178mod_lua_box * mod_lua_newbox(lua_State * l, mod_lua_scope scope, void * value, const char * type) {
179 mod_lua_box * box = (mod_lua_box *) lua_newuserdata(l, sizeof(mod_lua_box));
180 box->scope = scope;
181 box->value = value;
182 return box;
183}
184
185mod_lua_box * mod_lua_pushbox(lua_State * l, mod_lua_scope scope, void * value, const char * type) {
186 mod_lua_box * box = (mod_lua_box *) mod_lua_newbox(l, scope, value, type);
187 luaL_getmetatable(l, type);
188 lua_setmetatable(l, -2);
189 return box;
190}
191
192mod_lua_box * mod_lua_tobox(lua_State * l, int index, const char * type) {
193 mod_lua_box * box = (mod_lua_box *) lua_touserdata(l, index);
194 if (box == NULL && type != NULL ) luaL_typerror(l, index, type);
195 return box;
196}
197
198mod_lua_box * mod_lua_checkbox(lua_State * l, int index, const char * type) {
199 luaL_checktype(l, index, LUA_TUSERDATA);
200 mod_lua_box * box = (mod_lua_box *) luaL_checkudata(l, index, type);
201 if (box == NULL) luaL_typerror(l, index, type);
202 return box;
203}
204
205int mod_lua_freebox(lua_State * l, int index, const char * type) {
206 mod_lua_box * box = mod_lua_checkbox(l, index, type);
207 if ( box != NULL && box->scope == MOD_LUA_SCOPE_LUA && box->value != NULL ) {
208 as_val_destroy(box->value);
209 box->value = NULL;
210 }
211 return 0;
212}
213
214void * mod_lua_box_value(mod_lua_box * box) {
215 return box ? box->value : NULL;
216}
217