| 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/as_std.h> |
| 18 | |
| 19 | // This system lua code in the lua-core repo have been converted to these strings. |
| 20 | |
| 21 | const char as_lua_as[] = |
| 22 | "Map = Map or getmetatable(map())\n" |
| 23 | "List = List or getmetatable(list())\n" |
| 24 | "Bytes = Bytes or getmetatable(bytes())\n" |
| 25 | "function list.clone(l)\n" |
| 26 | " local ll = {}\n" |
| 27 | " for v in list.iterator(l) do\n" |
| 28 | " table.insert(ll, v)\n" |
| 29 | " end\n" |
| 30 | " return list(ll)\n" |
| 31 | "end\n" |
| 32 | "function list.merge(l1, l2)\n" |
| 33 | " local ll = {}\n" |
| 34 | " for v in list.iterator(l1) do\n" |
| 35 | " table.insert(ll,v)\n" |
| 36 | " end\n" |
| 37 | " for v in list.iterator(l2) do\n" |
| 38 | " table.insert(ll, v)\n" |
| 39 | " end\n" |
| 40 | " return list(ll)\n" |
| 41 | "end\n" |
| 42 | "function map.merge(m1,m2,f)\n" |
| 43 | " local mm = {}\n" |
| 44 | " for k,v in map.pairs(m1) do\n" |
| 45 | " mm[k] = v\n" |
| 46 | " end\n" |
| 47 | " for k,v in map.pairs(m2) do\n" |
| 48 | " mm[k] = (mm[k] and f and type(f) == 'function' and f(m1[k],m2[k])) or v\n" |
| 49 | " end\n" |
| 50 | " return map(mm, map.size(m1) + map.size(m2))\n" |
| 51 | "end\n" |
| 52 | "function map.diff(m1,m2)\n" |
| 53 | " local mm = {}\n" |
| 54 | " for k,v in map.pairs(m1) do\n" |
| 55 | " if not m2[k] then\n" |
| 56 | " mm[k] = v\n" |
| 57 | " end\n" |
| 58 | " end\n" |
| 59 | " for k,v in map.pairs(m2) do\n" |
| 60 | " if not m1[k] then\n" |
| 61 | " mm[k] = v\n" |
| 62 | " end\n" |
| 63 | " end\n" |
| 64 | " return map(mm, map.size(m1) + map.size(m2))\n" |
| 65 | "end\n" |
| 66 | "function map.clone(m)\n" |
| 67 | " local mm = {}\n" |
| 68 | " for k,v in map.pairs(m) do\n" |
| 69 | " mm[k] = v\n" |
| 70 | " end\n" |
| 71 | " return map(mm, map.size(m))\n" |
| 72 | "end\n" |
| 73 | "function math.sum(a,b) \n" |
| 74 | " return a + b\n" |
| 75 | "end\n" |
| 76 | "function math.product(a, b)\n" |
| 77 | " return a * b\n" |
| 78 | "end\n" |
| 79 | ; |
| 80 | |
| 81 | size_t as_lua_as_size = sizeof(as_lua_as); |
| 82 | |
| 83 | const char as_lua_stream_ops[] = |
| 84 | "local function check_limit(v)\n" |
| 85 | " return type(v) == 'number' and v >= 1000\n" |
| 86 | "end\n" |
| 87 | "local function clone_table(t)\n" |
| 88 | " local out = {}\n" |
| 89 | " for k,v in pairs(t) do\n" |
| 90 | " out[k] = v\n" |
| 91 | " end\n" |
| 92 | " return out\n" |
| 93 | "end\n" |
| 94 | "local function clone(v)\n" |
| 95 | " local t = type(v)\n" |
| 96 | " if t == 'number' then\n" |
| 97 | " return v\n" |
| 98 | " elseif t == 'string' then\n" |
| 99 | " return v\n" |
| 100 | " elseif t == 'boolean' then\n" |
| 101 | " return v\n" |
| 102 | " elseif t == 'table' then\n" |
| 103 | " return clone_table(v)\n" |
| 104 | " elseif t == 'userdata' then\n" |
| 105 | " if getmetatable(v) == Map then\n" |
| 106 | " return map.clone(v)\n" |
| 107 | " elseif getmetatable(v) == List then\n" |
| 108 | " return list.clone(v)\n" |
| 109 | " end\n" |
| 110 | " return nil\n" |
| 111 | " end\n" |
| 112 | " return v\n" |
| 113 | "end\n" |
| 114 | "function filter( next, p )\n" |
| 115 | " local done = false\n" |
| 116 | " return function()\n" |
| 117 | " if done then return nil end\n" |
| 118 | " for a in next do\n" |
| 119 | " if p(a) then\n" |
| 120 | " return a\n" |
| 121 | " end\n" |
| 122 | " end\n" |
| 123 | " done = true\n" |
| 124 | " return nil\n" |
| 125 | " end\n" |
| 126 | "end\n" |
| 127 | "function transform( next, f )\n" |
| 128 | " local done = false\n" |
| 129 | " return function()\n" |
| 130 | " if done then return nil end\n" |
| 131 | " local a = next()\n" |
| 132 | " if a ~= nil then\n" |
| 133 | " return f(a)\n" |
| 134 | " end\n" |
| 135 | " done = true;\n" |
| 136 | " return nil\n" |
| 137 | " end\n" |
| 138 | "end\n" |
| 139 | "function reduce( next, f )\n" |
| 140 | " local done = false\n" |
| 141 | " return function()\n" |
| 142 | " if done then return nil end\n" |
| 143 | " local a = next()\n" |
| 144 | " if a ~= nil then\n" |
| 145 | " for b in next do\n" |
| 146 | " a = f(a,b)\n" |
| 147 | " end\n" |
| 148 | " end\n" |
| 149 | " done = true\n" |
| 150 | " return a\n" |
| 151 | " end\n" |
| 152 | "end\n" |
| 153 | "function aggregate( next, init, f )\n" |
| 154 | " local done = false\n" |
| 155 | " return function()\n" |
| 156 | " if done then return nil end\n" |
| 157 | " local a = clone(init)\n" |
| 158 | " for b in next do\n" |
| 159 | " a = f(a,b)\n" |
| 160 | " if check_limit(a) then\n" |
| 161 | " return a\n" |
| 162 | " end\n" |
| 163 | " end\n" |
| 164 | " done = true\n" |
| 165 | " return a\n" |
| 166 | " end\n" |
| 167 | "end\n" |
| 168 | "function stream_iterator(s)\n" |
| 169 | " local done = false\n" |
| 170 | " return function()\n" |
| 171 | " if done then return nil end\n" |
| 172 | " local v = stream.read(s)\n" |
| 173 | " if v == nil then\n" |
| 174 | " done = true\n" |
| 175 | " end\n" |
| 176 | " return v;\n" |
| 177 | " end\n" |
| 178 | "end\n" |
| 179 | "StreamOps = {}\n" |
| 180 | "StreamOps_mt = { __index = StreamOps }\n" |
| 181 | "local SCOPE_SERVER = 1\n" |
| 182 | "local SCOPE_CLIENT = 2\n" |
| 183 | "local SCOPE_EITHER = 3\n" |
| 184 | "local SCOPE_BOTH = 4\n" |
| 185 | "function StreamOps_create()\n" |
| 186 | " local self = {}\n" |
| 187 | " setmetatable(self, StreamOps_mt)\n" |
| 188 | " self.ops = {}\n" |
| 189 | " return self\n" |
| 190 | "end\n" |
| 191 | "function StreamOps_apply(stream, ops, i, n)\n" |
| 192 | " i = i or 1\n" |
| 193 | " n = n or #ops\n" |
| 194 | " if i > n then return stream end\n" |
| 195 | " local op = ops[i]\n" |
| 196 | " local s = op.func(stream, unpack(op.args)) or stream\n" |
| 197 | " return StreamOps_apply(s, ops, i + 1, n)\n" |
| 198 | "end\n" |
| 199 | "function StreamOps_select(stream_ops, scope)\n" |
| 200 | " local server_ops = {}\n" |
| 201 | " local client_ops = {}\n" |
| 202 | " local phase = SCOPE_SERVER\n" |
| 203 | " for i,op in ipairs(stream_ops) do\n" |
| 204 | " if phase == SCOPE_SERVER then\n" |
| 205 | " if op.scope == SCOPE_SERVER then\n" |
| 206 | " table.insert(server_ops, op)\n" |
| 207 | " elseif op.scope == SCOPE_EITHER then\n" |
| 208 | " table.insert(server_ops, op)\n" |
| 209 | " elseif op.scope == SCOPE_BOTH then\n" |
| 210 | " table.insert(server_ops, op)\n" |
| 211 | " table.insert(client_ops, op)\n" |
| 212 | " phase = SCOPE_CLIENT\n" |
| 213 | " end\n" |
| 214 | " elseif phase == SCOPE_CLIENT then\n" |
| 215 | " table.insert(client_ops, op)\n" |
| 216 | " end \n" |
| 217 | " end\n" |
| 218 | " if scope == SCOPE_CLIENT then\n" |
| 219 | " return client_ops\n" |
| 220 | " else\n" |
| 221 | " return server_ops\n" |
| 222 | " end\n" |
| 223 | "end\n" |
| 224 | "function StreamOps:aggregate(...)\n" |
| 225 | " table.insert(self.ops, { scope = SCOPE_SERVER, name = \"aggregate\", func = aggregate, args = {...}})\n" |
| 226 | " return self\n" |
| 227 | "end\n" |
| 228 | "function StreamOps:reduce(...)\n" |
| 229 | " table.insert(self.ops, { scope = SCOPE_BOTH, name = \"reduce\", func = reduce, args = {...}})\n" |
| 230 | " return self\n" |
| 231 | "end\n" |
| 232 | "function StreamOps:map(...)\n" |
| 233 | " table.insert(self.ops, { scope = SCOPE_EITHER, name = \"map\", func = transform, args = {...}})\n" |
| 234 | " return self\n" |
| 235 | "end\n" |
| 236 | "function StreamOps:filter(...)\n" |
| 237 | " table.insert(self.ops, { scope = SCOPE_EITHER, name = \"filter\", func = filter, args = {...}})\n" |
| 238 | " return self\n" |
| 239 | "end\n" |
| 240 | "function StreamOps:groupby(f)\n" |
| 241 | " local function _aggregate(m, v)\n" |
| 242 | " local k = f and f(v) or nil;\n" |
| 243 | " local l = m[k] or list()\n" |
| 244 | " list.append(l, v)\n" |
| 245 | " m[k] = l;\n" |
| 246 | " return m;\n" |
| 247 | " end\n" |
| 248 | " local function _merge(l1, l2)\n" |
| 249 | " local l = list.clone(l1)\n" |
| 250 | " for v in list.iterator(l2) do\n" |
| 251 | " list.append(l, v)\n" |
| 252 | " end\n" |
| 253 | " return l\n" |
| 254 | " end\n" |
| 255 | " function _reduce(m1, m2)\n" |
| 256 | " return map.merge(m1, m2, _merge)\n" |
| 257 | " end\n" |
| 258 | " return self : aggregate(map(), _aggregate) : reduce(_reduce)\n" |
| 259 | "end\n" |
| 260 | ; |
| 261 | |
| 262 | size_t as_lua_stream_ops_size = sizeof(as_lua_stream_ops); |
| 263 | |
| 264 | const char as_lua_aerospike[] = |
| 265 | "sandboxed = {}\n" |
| 266 | "ldebug = debug;\n" |
| 267 | "function trace(m, ...)\n" |
| 268 | " return aerospike:log(4, string.format(m, ...))\n" |
| 269 | "end\n" |
| 270 | "function debug(m, ...)\n" |
| 271 | " return aerospike:log(3, string.format(m, ...))\n" |
| 272 | "end\n" |
| 273 | "function info(m, ...)\n" |
| 274 | " return aerospike:log(2, string.format(m, ...))\n" |
| 275 | "end\n" |
| 276 | "function warn(m, ...)\n" |
| 277 | " return aerospike:log(1, string.format(m, ...))\n" |
| 278 | "end\n" |
| 279 | "function env_record()\n" |
| 280 | " return {\n" |
| 281 | " [\"record\"] = record,\n" |
| 282 | " [\"iterator\"] = iterator,\n" |
| 283 | " [\"list\"] = list,\n" |
| 284 | " [\"map\"] = map,\n" |
| 285 | " [\"bytes\"] = bytes,\n" |
| 286 | " [\"geojson\"] = geojson,\n" |
| 287 | " [\"aerospike\"] = aerospike,\n" |
| 288 | " [\"Map\"] = Map, \n" |
| 289 | " [\"List\"] = List,\n" |
| 290 | " [\"Bytes\"] = Bytes,\n" |
| 291 | " [\"GeoJSON\"] = GeoJSON,\n" |
| 292 | " [\"putX\"] = putX,\n" |
| 293 | " [\"trace\"] = trace,\n" |
| 294 | " [\"debug\"] = debug,\n" |
| 295 | " [\"info\"] = info,\n" |
| 296 | " [\"warn\"] = warn,\n" |
| 297 | " [\"collectgarbage\"] = collectgarbage,\n" |
| 298 | " [\"error\"] = error,\n" |
| 299 | " [\"getmetatable\"] = getmetatable,\n" |
| 300 | " [\"ipairs\"] = ipairs,\n" |
| 301 | " [\"load\"] = load,\n" |
| 302 | " [\"module\"] = module,\n" |
| 303 | " [\"next\"] = next,\n" |
| 304 | " [\"pairs\"] = pairs,\n" |
| 305 | " [\"print\"] = print,\n" |
| 306 | " [\"pcall\"] = pcall,\n" |
| 307 | " [\"rawequal\"] = rawequal,\n" |
| 308 | " [\"rawget\"] = rawget,\n" |
| 309 | " [\"rawset\"] = rawset,\n" |
| 310 | " [\"require\"] = require,\n" |
| 311 | " [\"require\"] = require,\n" |
| 312 | " [\"select\"] = select,\n" |
| 313 | " [\"setmetatable\"] = setmetatable,\n" |
| 314 | " [\"setfenv\"] = setfenv,\n" |
| 315 | " [\"tonumber\"] = tonumber,\n" |
| 316 | " [\"tostring\"] = tostring,\n" |
| 317 | " [\"type\"] = type,\n" |
| 318 | " [\"unpack\"] = unpack,\n" |
| 319 | " [\"xpcall\"] = xpcall,\n" |
| 320 | " [\"math\"] = math,\n" |
| 321 | " [\"io\"] = io,\n" |
| 322 | " [\"os\"] = {\n" |
| 323 | " ['clock'] = os.clock,\n" |
| 324 | " ['date'] = os.date,\n" |
| 325 | " ['difftime'] = os.difftime,\n" |
| 326 | " ['getenv'] = os.getenv,\n" |
| 327 | " ['setlocale'] = os.setlocale,\n" |
| 328 | " ['time'] = os.time,\n" |
| 329 | " ['tmpname'] = os.tmpname\n" |
| 330 | " },\n" |
| 331 | " [\"package\"] = package,\n" |
| 332 | " [\"string\"] = string,\n" |
| 333 | " [\"table\"] = table,\n" |
| 334 | " [\"_G\"] = {}\n" |
| 335 | " }\n" |
| 336 | "end\n" |
| 337 | "function apply_record(f, r, ...)\n" |
| 338 | " if f == nil then\n" |
| 339 | " error(\"function not found\", 2)\n" |
| 340 | " end\n" |
| 341 | " if not sandboxed[f] then\n" |
| 342 | " setfenv(f,env_record())\n" |
| 343 | " sandboxed[f] = true\n" |
| 344 | " end\n" |
| 345 | " success, result = pcall(f, r, ...)\n" |
| 346 | " if success then\n" |
| 347 | " return result\n" |
| 348 | " else\n" |
| 349 | " error(result, 2)\n" |
| 350 | " return nil\n" |
| 351 | " end\n" |
| 352 | "end\n" |
| 353 | "function apply_stream(f, scope, istream, ostream, ...)\n" |
| 354 | " if f == nil then\n" |
| 355 | " error(\"function not found\", 2)\n" |
| 356 | " return 2\n" |
| 357 | " end\n" |
| 358 | " if not sandboxed[f] then\n" |
| 359 | " setfenv(f,env_record())\n" |
| 360 | " sandboxed[f] = true\n" |
| 361 | " end\n" |
| 362 | " local stream_ops = StreamOps_create();\n" |
| 363 | " success, result = pcall(f, stream_ops, ...)\n" |
| 364 | " if success then\n" |
| 365 | " local ops = StreamOps_select(result.ops, scope);\n" |
| 366 | " local values = StreamOps_apply(stream_iterator(istream), ops);\n" |
| 367 | " for value in values do\n" |
| 368 | " if stream.write(ostream, value) ~= 0 then\n" |
| 369 | " break\n" |
| 370 | " end\n" |
| 371 | " end\n" |
| 372 | " stream.write(ostream, nil)\n" |
| 373 | " return 0\n" |
| 374 | " else\n" |
| 375 | " error(result, 2)\n" |
| 376 | " return 2\n" |
| 377 | " end\n" |
| 378 | "end\n" |
| 379 | ; |
| 380 | |
| 381 | size_t as_lua_aerospike_size = sizeof(as_lua_aerospike); |
| 382 | |