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 | |
34 | as_val * mod_lua_takeval(lua_State * l, int i) { |
35 | return mod_lua_toval(l, i); |
36 | } |
37 | |
38 | as_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 | */ |
50 | as_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 | */ |
115 | int 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 | |
178 | mod_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 | |
185 | mod_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 | |
192 | mod_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 | |
198 | mod_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 | |
205 | int 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 | |
214 | void * mod_lua_box_value(mod_lua_box * box) { |
215 | return box ? box->value : NULL; |
216 | } |
217 | |