1 /*
2  * Copyright (c) 2015-2021 Hanspeter Portner (dev@open-music-kontrollers.ch)
3  *
4  * This is free software: you can redistribute it and/or modify
5  * it under the terms of the Artistic License 2.0 as published by
6  * The Perl Foundation.
7  *
8  * This source is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * Artistic License 2.0 for more details.
12  *
13  * You should have received a copy of the Artistic License 2.0
14  * along the source as a COPYING file. If not, obtain it from
15  * http://www.perlfoundation.org/artistic_license_2_0.
16  */
17 
18 #include <api_atom.h>
19 #include <api_stash.h>
20 
21 #include <inttypes.h>
22 #include <math.h>
23 
24 #define LV2_ATOM_VECTOR_BODY_ITEM_CONST(body, i) \
25 	(LV2_ATOM_CONTENTS_CONST(LV2_Atom_Vector_Body, (body)) + (i)*(body)->child_size)
26 
27 const lua_CFunction upclosures [MOONY_UPCLOSURE_COUNT] = {
28 	[MOONY_UPCLOSURE_TUPLE_FOREACH] = _latom_tuple_foreach_itr,
29 	[MOONY_UPCLOSURE_VECTOR_FOREACH] = _latom_vec_foreach_itr,
30 	[MOONY_UPCLOSURE_OBJECT_FOREACH] = _latom_obj_foreach_itr,
31 	[MOONY_UPCLOSURE_SEQUENCE_FOREACH] = _latom_seq_foreach_itr,
32 	[MOONY_UPCLOSURE_SEQUENCE_MULTIPLEX] = _latom_seq_multiplex_itr
33 };
34 
35 __realtime static inline void
_pushupclosure(lua_State * L,moony_t * moony,moony_upclosure_t type,bool cache)36 _pushupclosure(lua_State *L, moony_t *moony, moony_upclosure_t type, bool cache)
37 {
38 	int *upc = &moony->upc[type];
39 
40 	lua_rawgetp(L, LUA_REGISTRYINDEX, &upclosures[type]); // ref
41 	if(lua_rawgeti(L, -1, *upc) == LUA_TNIL) // no cached udata, create one!
42 	{
43 #if 0
44 		if(moony->log)
45 			lv2_log_trace(&moony->logger, "_pushupclosure:\n");
46 #endif
47 		lua_pop(L, 1); // nil
48 
49 		lua_pushlightuserdata(L, moony);
50 		_latom_new(L, NULL, false); // place-holder
51 		lua_pushcclosure(L, upclosures[type], 2);
52 
53 		lua_pushvalue(L, -1);
54 		lua_rawseti(L, -3, *upc); // store in cache
55 	}
56 	lua_remove(L, -2); // ref
57 	*upc += 1;
58 }
59 
60 __realtime int
_latom_clone(lua_State * L)61 _latom_clone(lua_State *L)
62 {
63 	latom_t *latom = lua_touserdata(L, 1);
64 
65 	latom_t *litem = lua_newuserdata(L, sizeof(latom_t) + lv2_atom_total_size(latom->atom));
66 	litem->lheader.type = MOONY_UDATA_ATOM;
67 	litem->lheader.cache = false;
68 	litem->atom = (const LV2_Atom *)litem->payload;
69 	litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
70 
71 	litem->payload->size = latom->atom->size;
72 	litem->payload->type = latom->atom->type;
73 	memcpy(LV2_ATOM_BODY(litem->payload), latom->body.raw, latom->atom->size);
74 
75 	luaL_getmetatable(L, "latom");
76 	lua_setmetatable(L, -2);
77 
78 	return 1;
79 }
80 
81 __realtime static int
_latom__gc(lua_State * L)82 _latom__gc(lua_State *L)
83 {
84 	latom_t *latom = lua_touserdata(L, 1);
85 
86 	if(latom->lheader.type == MOONY_UDATA_STASH)
87 		return _lstash__gc(L);
88 
89 	return 0;
90 }
91 
92 // Nil driver
93 __realtime static int
_latom_nil__len(lua_State * L,latom_t * latom)94 _latom_nil__len(lua_State *L, latom_t *latom)
95 {
96 	lua_pushinteger(L, latom->atom->size);
97 	return 1;
98 }
99 
100 __realtime static int
_latom_nil__tostring(lua_State * L,latom_t * latom)101 _latom_nil__tostring(lua_State *L, latom_t *latom)
102 {
103 	lua_pushfstring(L, "(nil: %p)", latom);
104 	return 1;
105 }
106 
107 __realtime static inline int
_latom_nil_value(lua_State * L,latom_t * latom)108 _latom_nil_value(lua_State *L, latom_t *latom)
109 {
110 	lua_pushnil(L);
111 	return 1;
112 }
113 
114 const latom_driver_t latom_nil_driver = {
115 	.__len = _latom_nil__len,
116 	.__tostring = _latom_nil__tostring,
117 	.value = _latom_nil_value
118 };
119 
120 // Int driver
121 __realtime static int
_latom_int__len(lua_State * L,latom_t * latom)122 _latom_int__len(lua_State *L, latom_t *latom)
123 {
124 	lua_pushinteger(L, latom->atom->size);
125 	return 1;
126 }
127 
128 __realtime static int
_latom_int__tostring(lua_State * L,latom_t * latom)129 _latom_int__tostring(lua_State *L, latom_t *latom)
130 {
131 	lua_pushfstring(L, "(int: %p, %d)", latom, *latom->body.i32);
132 	return 1;
133 }
134 
135 __realtime static inline int
_latom_int_value(lua_State * L,latom_t * latom)136 _latom_int_value(lua_State *L, latom_t *latom)
137 {
138 	lua_pushinteger(L, *latom->body.i32);
139 	return 1;
140 }
141 
142 const latom_driver_t latom_int_driver = {
143 	.__len = _latom_int__len,
144 	.__tostring = _latom_int__tostring,
145 	.value = _latom_int_value
146 };
147 
148 // Long driver
149 __realtime static int
_latom_long__len(lua_State * L,latom_t * latom)150 _latom_long__len(lua_State *L, latom_t *latom)
151 {
152 	lua_pushinteger(L, latom->atom->size);
153 	return 1;
154 }
155 
156 static int
_latom_long__tostring(lua_State * L,latom_t * latom)157 __realtime _latom_long__tostring(lua_State *L, latom_t *latom)
158 {
159 	lua_pushfstring(L, "(long: %p, %d)", latom, *latom->body.i64);
160 	return 1;
161 }
162 
163 __realtime static inline int
_latom_long_value(lua_State * L,latom_t * latom)164 _latom_long_value(lua_State *L, latom_t *latom)
165 {
166 	lua_pushinteger(L, *latom->body.i64);
167 	return 1;
168 }
169 
170 const latom_driver_t latom_long_driver = {
171 	.__len = _latom_long__len,
172 	.__tostring = _latom_long__tostring,
173 	.value = _latom_long_value
174 };
175 
176 // Float driver
177 __realtime static int
_latom_float__len(lua_State * L,latom_t * latom)178 _latom_float__len(lua_State *L, latom_t *latom)
179 {
180 	lua_pushinteger(L, latom->atom->size);
181 	return 1;
182 }
183 
184 __realtime static int
_latom_float__tostring(lua_State * L,latom_t * latom)185 _latom_float__tostring(lua_State *L, latom_t *latom)
186 {
187 	lua_pushfstring(L, "(float: %p, %f)", latom, *latom->body.f32);
188 	return 1;
189 }
190 
191 __realtime static inline int
_latom_float_value(lua_State * L,latom_t * latom)192 _latom_float_value(lua_State *L, latom_t *latom)
193 {
194 	lua_pushnumber(L, *latom->body.f32);
195 	return 1;
196 }
197 
198 const latom_driver_t latom_float_driver = {
199 	.__len = _latom_float__len,
200 	.__tostring = _latom_float__tostring,
201 	.value = _latom_float_value
202 };
203 
204 // Double driver
205 __realtime static int
_latom_double__len(lua_State * L,latom_t * latom)206 _latom_double__len(lua_State *L, latom_t *latom)
207 {
208 	lua_pushinteger(L, latom->atom->size);
209 	return 1;
210 }
211 
212 __realtime static int
_latom_double__tostring(lua_State * L,latom_t * latom)213 _latom_double__tostring(lua_State *L, latom_t *latom)
214 {
215 	lua_pushfstring(L, "(double: %p, %f)", latom, *latom->body.f64);
216 	return 1;
217 }
218 
219 __realtime static inline int
_latom_double_value(lua_State * L,latom_t * latom)220 _latom_double_value(lua_State *L, latom_t *latom)
221 {
222 	lua_pushnumber(L, *latom->body.f64);
223 	return 1;
224 }
225 
226 const latom_driver_t latom_double_driver = {
227 	.__len = _latom_double__len,
228 	.__tostring = _latom_double__tostring,
229 	.value = _latom_double_value
230 };
231 
232 // Bool driver
233 __realtime static int
_latom_bool__len(lua_State * L,latom_t * latom)234 _latom_bool__len(lua_State *L, latom_t *latom)
235 {
236 	lua_pushinteger(L, latom->atom->size);
237 	return 1;
238 }
239 
240 __realtime static int
_latom_bool__tostring(lua_State * L,latom_t * latom)241 _latom_bool__tostring(lua_State *L, latom_t *latom)
242 {
243 	if(*latom->body.i32 == 0)
244 		lua_pushfstring(L, "(bool: %p, false)", latom);
245 	else
246 		lua_pushfstring(L, "(bool: %p, true)", latom);
247 	return 1;
248 }
249 
250 __realtime static inline int
_latom_bool_value(lua_State * L,latom_t * latom)251 _latom_bool_value(lua_State *L, latom_t *latom)
252 {
253 	lua_pushboolean(L, *latom->body.i32);
254 	return 1;
255 }
256 
257 const latom_driver_t latom_bool_driver = {
258 	.__len = _latom_bool__len,
259 	.__tostring = _latom_bool__tostring,
260 	.value = _latom_bool_value
261 };
262 
263 // URID driver
264 __realtime static int
_latom_urid__len(lua_State * L,latom_t * latom)265 _latom_urid__len(lua_State *L, latom_t *latom)
266 {
267 	lua_pushinteger(L, latom->atom->size);
268 	return 1;
269 }
270 
271 __realtime static int
_latom_urid__tostring(lua_State * L,latom_t * latom)272 _latom_urid__tostring(lua_State *L, latom_t *latom)
273 {
274 	lua_pushfstring(L, "(URID: %p, %d)", latom, *latom->body.u32);
275 	return 1;
276 }
277 
278 __realtime static inline int
_latom_urid_value(lua_State * L,latom_t * latom)279 _latom_urid_value(lua_State *L, latom_t *latom)
280 {
281 	lua_pushinteger(L, *latom->body.u32);
282 	return 1;
283 }
284 
285 const latom_driver_t latom_urid_driver = {
286 	.__len = _latom_urid__len,
287 	.__tostring = _latom_urid__tostring,
288 	.value = _latom_urid_value
289 };
290 
291 // String driver
292 __realtime static int
_latom_string__len(lua_State * L,latom_t * latom)293 _latom_string__len(lua_State *L, latom_t *latom)
294 {
295 	lua_pushinteger(L, latom->atom->size);
296 	return 1;
297 }
298 
299 __realtime static inline int
_latom_string_value(lua_State * L,latom_t * latom)300 _latom_string_value(lua_State *L, latom_t *latom)
301 {
302 	lua_pushlstring(L, latom->body.str, latom->atom->size - 1);
303 	return 1;
304 }
305 
306 __realtime static int
_latom_string__tostring(lua_State * L,latom_t * latom)307 _latom_string__tostring(lua_State *L, latom_t *latom)
308 {
309 	//FIXME URI, Path
310 	lua_pushfstring(L, "(string: %p, %s)", latom, latom->body.str);
311 	return 1;
312 }
313 
314 const latom_driver_t latom_string_driver = {
315 	.__len = _latom_string__len,
316 	.__tostring = _latom_string__tostring,
317 	.value = _latom_string_value
318 };
319 
320 // Literal driver
321 __realtime static int
_latom_literal__indexk(lua_State * L,latom_t * latom,const char * key)322 _latom_literal__indexk(lua_State *L, latom_t *latom, const char *key)
323 {
324 	if(!strcmp(key, "datatype"))
325 		lua_pushinteger(L, latom->body.lit->datatype);
326 	else if(!strcmp(key, "lang"))
327 		lua_pushinteger(L, latom->body.lit->lang);
328 	else
329 		lua_pushnil(L);
330 	return 1;
331 }
332 
333 __realtime static int
_latom_literal_value(lua_State * L,latom_t * latom)334 _latom_literal_value(lua_State *L, latom_t *latom)
335 {
336 	lua_pushlstring(L,
337 		LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal_Body, latom->body.lit),
338 		latom->atom->size - 1 - sizeof(LV2_Atom_Literal_Body));
339 	return 1;
340 }
341 
342 __realtime static int
_latom_literal__tostring(lua_State * L,latom_t * latom)343 _latom_literal__tostring(lua_State *L, latom_t *latom)
344 {
345 	lua_pushfstring(L, "(literal: %p, %s)", latom,
346 		LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal_Body, latom->body.lit));
347 	return 1;
348 }
349 
350 __realtime int
_latom_literal_unpack(lua_State * L)351 _latom_literal_unpack(lua_State *L)
352 {
353 	latom_t *latom = lua_touserdata(L, 1);
354 	lua_pushlstring(L,
355 		LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal_Body, latom->body.lit),
356 		latom->atom->size - 1 - sizeof(LV2_Atom_Literal_Body));
357 	lua_pushinteger(L, latom->body.lit->datatype);
358 	lua_pushinteger(L, latom->body.lit->lang);
359 	return 3;
360 }
361 
362 const latom_driver_t latom_literal_driver = {
363 	.__indexk = _latom_literal__indexk,
364 	.__len = _latom_string__len,
365 	.__tostring = _latom_literal__tostring,
366 	.value = _latom_literal_value,
367 	.unpack = _latom_literal_unpack
368 };
369 
370 __realtime static int
_latom_tuple__indexi(lua_State * L,latom_t * latom)371 _latom_tuple__indexi(lua_State *L, latom_t *latom)
372 {
373 	const int idx = lua_tointeger(L, 2);
374 
375 	int count = 0;
376 	LV2_ATOM_TUPLE_BODY_FOREACH(latom->body.tuple, latom->atom->size, atom)
377 	{
378 		if(++count == idx)
379 		{
380 			_latom_new(L, atom, latom->lheader.cache);
381 			return 1;
382 		}
383 	}
384 
385 	lua_pushnil(L);
386 	return 1;
387 }
388 
389 __realtime static int
_latom_tuple__len(lua_State * L,latom_t * latom)390 _latom_tuple__len(lua_State *L, latom_t *latom)
391 {
392 	int count = 0;
393 	LV2_ATOM_TUPLE_BODY_FOREACH(latom->body.tuple, latom->atom->size, atom)
394 		++count;
395 
396 	lua_pushinteger(L, count);
397 	return 1;
398 }
399 
400 __realtime static int
_latom_tuple__tostring(lua_State * L,latom_t * latom)401 _latom_tuple__tostring(lua_State *L, latom_t *latom)
402 {
403 	lua_pushfstring(L, "(tuple: %p)", latom);
404 	return 1;
405 }
406 
407 __realtime int
_latom_tuple_unpack(lua_State * L)408 _latom_tuple_unpack(lua_State *L)
409 {
410 	latom_t *latom = lua_touserdata(L, 1);
411 
412 	int n = lua_gettop(L);
413 	int min = n > 1
414 		? luaL_checkinteger(L, 2)
415 		: 1;
416 	int max = n > 2
417 		? luaL_checkinteger(L, 3)
418 		: INT_MAX;
419 
420 	int pos = 1;
421 	int count = 0;
422 	LV2_ATOM_TUPLE_BODY_FOREACH(latom->body.tuple, latom->atom->size, atom)
423 	{
424 		if(pos >= min)
425 		{
426 			if(pos <= max)
427 			{
428 				_latom_new(L, atom, latom->lheader.cache);
429 				count += 1;
430 			}
431 			else
432 				break;
433 		}
434 
435 		pos += 1;
436 	}
437 
438 	return count;
439 }
440 
441 static const LV2_Atom nil_atom = {
442 	.size = 0,
443 	.type = 0
444 };
445 
446 __realtime static void
_latom_clear(latom_t * litem)447 _latom_clear(latom_t *litem)
448 {
449 	litem->atom = &nil_atom;
450 	litem->body.raw = NULL;
451 }
452 
453 __realtime int
_latom_tuple_foreach_itr(lua_State * L)454 _latom_tuple_foreach_itr(lua_State *L)
455 {
456 	latom_t *latom = lua_touserdata(L, 1);
457 	latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
458 
459 	if(!lv2_atom_tuple_is_end(latom->body.tuple, latom->atom->size, latom->iter.tuple.item))
460 	{
461 		// push index
462 		lua_pushinteger(L, latom->iter.tuple.pos);
463 		// push atom
464 		lua_pushvalue(L, lua_upvalueindex(2));
465 		litem->atom = latom->iter.tuple.item;
466 		litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
467 
468 		// advance iterator
469 		latom->iter.tuple.pos += 1;
470 		latom->iter.tuple.item = lv2_atom_tuple_next(latom->iter.tuple.item);
471 
472 		return 2;
473 	}
474 
475 	// end of tuple reached
476 	_latom_clear(litem);
477 	lua_pushnil(L);
478 	return 1;
479 }
480 
481 __realtime int
_latom_tuple_foreach(lua_State * L)482 _latom_tuple_foreach(lua_State *L)
483 {
484 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
485 	latom_t *latom = lua_touserdata(L, 1);
486 
487 	// reset iterator to beginning of tuple
488 	latom->iter.tuple.pos = 1;
489 	latom->iter.tuple.item = latom->body.tuple;
490 
491 	_pushupclosure(L, moony, MOONY_UPCLOSURE_TUPLE_FOREACH, latom->lheader.cache);
492 	lua_pushvalue(L, 1);
493 
494 	return 2;
495 }
496 
497 const latom_driver_t latom_tuple_driver = {
498 	.__indexi = _latom_tuple__indexi,
499 	.__len = _latom_tuple__len,
500 	.__tostring = _latom_tuple__tostring,
501 	.unpack = _latom_tuple_unpack,
502 	.foreach = _latom_tuple_foreach
503 };
504 
505 __realtime static int
_latom_obj__indexi(lua_State * L,latom_t * latom)506 _latom_obj__indexi(lua_State *L, latom_t *latom)
507 {
508 	const LV2_URID urid = lua_tointeger(L, 2);
509 
510 	const LV2_Atom *atom = NULL;
511 	lv2_atom_object_body_get(latom->atom->size, latom->body.obj, urid, &atom, 0);
512 
513 	if(atom) // query returned a matching atom
514 		_latom_new(L, atom, latom->lheader.cache);
515 	else // query returned no matching atom
516 		lua_pushnil(L);
517 
518 	return 1;
519 }
520 
521 __realtime static int
_latom_obj__indexk(lua_State * L,latom_t * latom,const char * key)522 _latom_obj__indexk(lua_State *L, latom_t *latom, const char *key)
523 {
524 	if(!strcmp(key, "id"))
525 		lua_pushinteger(L, latom->body.obj->id);
526 	else if(!strcmp(key, "otype"))
527 		lua_pushinteger(L, latom->body.obj->otype);
528 	else
529 		lua_pushnil(L);
530 	return 1;
531 }
532 
533 __realtime static int
_latom_obj__len(lua_State * L,latom_t * latom)534 _latom_obj__len(lua_State *L, latom_t *latom)
535 {
536 	int count = 0;
537 	LV2_ATOM_OBJECT_BODY_FOREACH(latom->body.obj, latom->atom->size, prop)
538 		++count;
539 
540 	lua_pushinteger(L, count);
541 	return 1;
542 }
543 
544 __realtime static int
_latom_obj__tostring(lua_State * L,latom_t * latom)545 _latom_obj__tostring(lua_State *L, latom_t *latom)
546 {
547 	lua_pushfstring(L, "(object: %p)", latom);
548 	return 1;
549 }
550 
551 __realtime int
_latom_obj_foreach_itr(lua_State * L)552 _latom_obj_foreach_itr(lua_State *L)
553 {
554 	latom_t *latom = lua_touserdata(L, 1);
555 	latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
556 
557 	if(!lv2_atom_object_is_end(latom->body.obj, latom->atom->size, latom->iter.obj.prop))
558 	{
559 		// push key
560 		lua_pushinteger(L, latom->iter.obj.prop->key);
561 		// push atom
562 
563 		lua_pushvalue(L, lua_upvalueindex(2));
564 		litem->atom = &latom->iter.obj.prop->value;
565 		litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
566 
567 		// push context
568 		lua_pushinteger(L, latom->iter.obj.prop->context);
569 
570 		// advance iterator
571 		latom->iter.obj.prop = lv2_atom_object_next(latom->iter.obj.prop);
572 
573 		return 3;
574 	}
575 
576 	// end of object reached
577 	_latom_clear(litem);
578 	lua_pushnil(L);
579 	return 1;
580 }
581 
582 __realtime int
_latom_obj_foreach(lua_State * L)583 _latom_obj_foreach(lua_State *L)
584 {
585 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
586 	latom_t *latom = lua_touserdata(L, 1);
587 
588 	// reset iterator to beginning of object
589 	latom->iter.obj.prop = lv2_atom_object_begin(latom->body.obj);
590 
591 	_pushupclosure(L, moony, MOONY_UPCLOSURE_OBJECT_FOREACH, latom->lheader.cache);
592 	lua_pushvalue(L, 1);
593 
594 	return 2;
595 }
596 
597 const latom_driver_t latom_object_driver = {
598 	.__indexi = _latom_obj__indexi,
599 	.__indexk = _latom_obj__indexk,
600 	.__len = _latom_obj__len,
601 	.__tostring = _latom_obj__tostring,
602 	.foreach = _latom_obj_foreach
603 };
604 
605 __realtime static int
_latom_seq__indexk(lua_State * L,latom_t * latom,const char * key)606 _latom_seq__indexk(lua_State *L, latom_t *latom, const char *key)
607 {
608 	if(!strcmp(key, "unit"))
609 		lua_pushinteger(L, latom->body.seq->unit);
610 	else
611 		lua_pushnil(L);
612 	return 1;
613 }
614 
615 __realtime static int
_latom_seq__indexi(lua_State * L,latom_t * latom)616 _latom_seq__indexi(lua_State *L, latom_t *latom)
617 {
618 	int index = lua_tointeger(L, 2); // indexing start from 1
619 
620 	int count = 0;
621 	LV2_ATOM_SEQUENCE_BODY_FOREACH(latom->body.seq, latom->atom->size, ev)
622 	{
623 		if(++count == index)
624 		{
625 			_latom_new(L, &ev->body, latom->lheader.cache);
626 			return 1;
627 		}
628 	}
629 
630 	lua_pushnil(L);
631 	return 1;
632 }
633 
634 __realtime static int
_latom_seq__len(lua_State * L,latom_t * latom)635 _latom_seq__len(lua_State *L, latom_t *latom)
636 {
637 	int count = 0;
638 	LV2_ATOM_SEQUENCE_BODY_FOREACH(latom->body.seq, latom->atom->size, ev)
639 		++count;
640 
641 	lua_pushinteger(L, count);
642 	return 1;
643 }
644 
645 __realtime static int
_latom_seq__tostring(lua_State * L,latom_t * latom)646 _latom_seq__tostring(lua_State *L, latom_t *latom)
647 {
648 	lua_pushfstring(L, "(sequence: %p)", latom);
649 	return 1;
650 }
651 
652 __realtime int
_latom_seq_multiplex_itr(lua_State * L)653 _latom_seq_multiplex_itr(lua_State *L)
654 {
655 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
656 	const unsigned n = lua_rawlen(L, 1);
657 	latom_t *latom [n];
658 	latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
659 
660 	// fill latom* array
661 	for(unsigned i=0; i<n; i++)
662 	{
663 		lua_rawgeti(L, 1, 1+i);
664 		latom[i] = lua_touserdata(L, -1);
665 	}
666 	lua_pop(L, n);
667 
668 	double huge = HUGE_VAL;
669 	int nxt = -1;
670 	for(unsigned i=0; i<n; i++)
671 	{
672 		if(lv2_atom_sequence_is_end(latom[i]->body.seq, latom[i]->atom->size, latom[i]->iter.seq.ev))
673 			continue;
674 
675 		if(latom[i]->body.seq->unit == moony->uris.atom_beat_time)
676 		{
677 			if(latom[i]->iter.seq.ev->time.beats < huge)
678 			{
679 				huge = latom[i]->iter.seq.ev->time.beats;
680 				nxt = i;
681 			}
682 		}
683 		else
684 		{
685 			if(latom[i]->iter.seq.ev->time.frames < huge)
686 			{
687 				huge = latom[i]->iter.seq.ev->time.frames;
688 				nxt = i;
689 			}
690 		}
691 	}
692 
693 	if(nxt >= 0) // is there a valid next event?
694 	{
695 		if(latom[nxt]->body.seq->unit == moony->uris.atom_beat_time)
696 			lua_pushnumber(L, latom[nxt]->iter.seq.ev->time.beats);
697 		else
698 			lua_pushinteger(L, latom[nxt]->iter.seq.ev->time.frames);
699 
700 		// push atom
701 		lua_pushvalue(L, lua_upvalueindex(2));
702 		litem->atom = &latom[nxt]->iter.seq.ev->body;
703 		litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
704 		lua_rawgeti(L, 1, 1+nxt);
705 
706 		// advance iterator
707 		latom[nxt]->iter.seq.ev = lv2_atom_sequence_next(latom[nxt]->iter.seq.ev);
708 
709 		return 3;
710 	}
711 
712 	// end of sequence reached
713 	_latom_clear(litem);
714 	lua_pushnil(L);
715 	return 1;
716 }
717 
718 __realtime static int
_latom_seq_multiplex(lua_State * L,unsigned n)719 _latom_seq_multiplex(lua_State *L, unsigned n)
720 {
721 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
722 	latom_t *latom = lua_touserdata(L, 1);
723 
724 	for(unsigned i=1; i<=n; i++)
725 	{
726 		latom_t *lmux = lua_touserdata(L, i);
727 
728 		// reset iterator to beginning of sequence
729 		lmux->iter.seq.ev = lv2_atom_sequence_begin(lmux->body.seq);
730 	}
731 
732 	_pushupclosure(L, moony, MOONY_UPCLOSURE_SEQUENCE_MULTIPLEX, latom->lheader.cache);
733 
734 	lua_createtable(L, n, 0); //FIXME cache this?
735 	for(unsigned i=1; i<=n; i++)
736 	{
737 		lua_pushvalue(L, i);
738 		lua_rawseti(L, -2, i);
739 	}
740 
741 	return 2;
742 }
743 
744 __realtime int
_latom_seq_foreach_itr(lua_State * L)745 _latom_seq_foreach_itr(lua_State *L)
746 {
747 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
748 	latom_t *latom = lua_touserdata(L, 1);
749 	latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
750 
751 	if(!lv2_atom_sequence_is_end(latom->body.seq, latom->atom->size, latom->iter.seq.ev))
752 	{
753 		if(latom->body.seq->unit == moony->uris.atom_beat_time)
754 			lua_pushnumber(L, latom->iter.seq.ev->time.beats);
755 		else
756 			lua_pushinteger(L, latom->iter.seq.ev->time.frames);
757 
758 		// push atom
759 		lua_pushvalue(L, lua_upvalueindex(2));
760 		litem->atom = &latom->iter.seq.ev->body;
761 		litem->body.raw = LV2_ATOM_BODY_CONST(litem->atom);
762 
763 		// advance iterator
764 		latom->iter.seq.ev = lv2_atom_sequence_next(latom->iter.seq.ev);
765 
766 		return 2;
767 	}
768 
769 	// end of sequence reached
770 	_latom_clear(litem);
771 	lua_pushnil(L);
772 	return 1;
773 }
774 
775 __realtime int
_latom_seq_foreach(lua_State * L)776 _latom_seq_foreach(lua_State *L)
777 {
778 	const unsigned n = lua_gettop(L);
779 	if(n > 1) // multiplex if given any function arguments
780 		return _latom_seq_multiplex(L, n);
781 
782 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
783 	latom_t *latom = lua_touserdata(L, 1);
784 
785 	// reset iterator to beginning of sequence
786 	latom->iter.seq.ev = lv2_atom_sequence_begin(latom->body.seq);
787 
788 	_pushupclosure(L, moony, MOONY_UPCLOSURE_SEQUENCE_FOREACH, latom->lheader.cache);
789 	lua_pushvalue(L, 1);
790 
791 	return 2;
792 }
793 
794 const latom_driver_t latom_sequence_driver = {
795 	.__indexk = _latom_seq__indexk,
796 	.__indexi = _latom_seq__indexi,
797 	.__len = _latom_seq__len,
798 	.__tostring = _latom_seq__tostring,
799 	.foreach = _latom_seq_foreach
800 };
801 
802 __realtime static int
_latom_vec__indexi(lua_State * L,latom_t * latom)803 _latom_vec__indexi(lua_State *L, latom_t *latom)
804 {
805 	int index = lua_tointeger(L, 2); // indexing start from 1
806 
807 	const int count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
808 		/ latom->body.vec->child_size;
809 
810 	if( (index > 0) && (index <= count) )
811 	{
812 		latom_t *litem = _latom_new(L, NULL, latom->lheader.cache);
813 		litem->atom = (const LV2_Atom *)latom->body.vec;
814 		litem->body.raw = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, index - 1);
815 	}
816 	else // index is out of bounds
817 		lua_pushnil(L);
818 
819 	return 1;
820 }
821 
822 __realtime static int
_latom_vec__indexk(lua_State * L,latom_t * latom,const char * key)823 _latom_vec__indexk(lua_State *L, latom_t *latom, const char *key)
824 {
825 	if(!strcmp(key, "childType"))
826 		lua_pushinteger(L, latom->body.vec->child_type);
827 	else if(!strcmp(key, "childSize"))
828 		lua_pushinteger(L, latom->body.vec->child_size);
829 	else
830 		lua_pushnil(L);
831 	return 1;
832 }
833 
834 __realtime static int
_latom_vec__len(lua_State * L,latom_t * latom)835 _latom_vec__len(lua_State *L, latom_t *latom)
836 {
837 	const int count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
838 		/ latom->body.vec->child_size;
839 
840 	lua_pushinteger(L, count);
841 	return 1;
842 }
843 
844 __realtime static int
_latom_vec__tostring(lua_State * L,latom_t * latom)845 _latom_vec__tostring(lua_State *L, latom_t *latom)
846 {
847 	lua_pushfstring(L, "(vector: %p)", latom);
848 	return 1;
849 }
850 
851 __realtime static int
_latom_vec_value(lua_State * L,latom_t * latom)852 _latom_vec_value(lua_State *L, latom_t *latom)
853 {
854 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
855 
856 	const int n = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
857 		/ latom->body.vec->child_size;
858 	const void *ptr = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, 0);
859 
860 	lua_createtable(L, n, 0);
861 
862 	if(latom->body.vec->child_type == moony->forge.Bool)
863 	{
864 		const int32_t *i32 = ptr;
865 		for(int i=0; i<n; i++)
866 		{
867 			lua_pushboolean(L, i32[i]);
868 			lua_rawseti(L, -2, i+1);
869 		}
870 	}
871 	else if(latom->body.vec->child_type == moony->forge.Int)
872 	{
873 		const int32_t *i32 = ptr;
874 		for(int i=0; i<n; i++)
875 		{
876 			lua_pushinteger(L, i32[i]);
877 			lua_rawseti(L, -2, i+1);
878 		}
879 	}
880 	else if(latom->body.vec->child_type == moony->forge.URID)
881 	{
882 		const uint32_t *u32 = ptr;
883 		for(int i=0; i<n; i++)
884 		{
885 			lua_pushinteger(L, u32[i]);
886 			lua_rawseti(L, -2, i+1);
887 		}
888 	}
889 	else if(latom->body.vec->child_type == moony->forge.Long)
890 	{
891 		const int64_t *i64 = ptr;
892 		for(int i=0; i<n; i++)
893 		{
894 			lua_pushinteger(L, i64[i]);
895 			lua_rawseti(L, -2, i+1);
896 		}
897 	}
898 	else if(latom->body.vec->child_type == moony->forge.Float)
899 	{
900 		const float *f32 = ptr;
901 		for(int i=0; i<n; i++)
902 		{
903 			lua_pushnumber(L, f32[i]);
904 			lua_rawseti(L, -2, i+1);
905 		}
906 	}
907 	else if(latom->body.vec->child_type == moony->forge.Double)
908 	{
909 		const double *f64 = ptr;
910 		for(int i=0; i<n; i++)
911 		{
912 			lua_pushnumber(L, f64[i]);
913 			lua_rawseti(L, -2, i+1);
914 		}
915 	}
916 
917 	return 1;
918 }
919 
920 __realtime int
_latom_vec_unpack(lua_State * L)921 _latom_vec_unpack(lua_State *L)
922 {
923 	latom_t *latom = lua_touserdata(L, 1);
924 
925 	const int count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
926 		/ latom->body.vec->child_size;
927 
928 	const int n = lua_gettop(L);
929 	int min = 1;
930 	int max = count;
931 
932 	if(n > 1) // check provided index ranges
933 	{
934 		min = luaL_checkinteger(L, 2);
935 		min = min < 1
936 			? 1
937 			: (min > count
938 				? count
939 				: min);
940 
941 		if(n > 2)
942 		{
943 			max = luaL_checkinteger(L, 3);
944 			max = max < 1
945 				? 1
946 				: (max > count
947 					? count
948 					: max);
949 		}
950 	}
951 
952 	for(int i=min; i<=max; i++)
953 	{
954 		latom_t *litem = _latom_new(L, NULL, latom->lheader.cache);
955 		litem->atom = (const LV2_Atom *)latom->body.vec;
956 		litem->body.raw = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, i - 1);
957 	}
958 
959 	return max - min + 1;
960 }
961 
962 __realtime int
_latom_vec_foreach_itr(lua_State * L)963 _latom_vec_foreach_itr(lua_State *L)
964 {
965 	latom_t *latom = lua_touserdata(L, 1);
966 	latom_t *litem = lua_touserdata(L, lua_upvalueindex(2));
967 
968 	if(latom->iter.vec.pos < latom->iter.vec.count)
969 	{
970 		// push index
971 		lua_pushinteger(L, latom->iter.vec.pos + 1);
972 		// push atom
973 		lua_pushvalue(L, lua_upvalueindex(2));
974 		litem->atom = (const LV2_Atom *)latom->body.vec;
975 		litem->body.raw = LV2_ATOM_VECTOR_BODY_ITEM_CONST(latom->body.vec, latom->iter.vec.pos);
976 
977 		// advance iterator
978 		latom->iter.vec.pos += 1;
979 
980 		return 2;
981 	}
982 
983 	// end of vector reached
984 	_latom_clear(litem);
985 	lua_pushnil(L);
986 	return 1;
987 }
988 
989 __realtime int
_latom_vec_foreach(lua_State * L)990 _latom_vec_foreach(lua_State *L)
991 {
992 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
993 	latom_t *latom = lua_touserdata(L, 1);
994 
995 	// reset iterator to beginning of vector
996 	latom->iter.vec.count = (latom->atom->size - sizeof(LV2_Atom_Vector_Body))
997 		/ latom->body.vec->child_size;
998 	latom->iter.vec.pos = 0;
999 
1000 	_pushupclosure(L, moony, MOONY_UPCLOSURE_VECTOR_FOREACH, latom->lheader.cache);
1001 	lua_pushvalue(L, 1);
1002 
1003 	return 2;
1004 }
1005 
1006 const latom_driver_t latom_vector_driver = {
1007 	.__indexi = _latom_vec__indexi,
1008 	.__indexk = _latom_vec__indexk,
1009 	.__len = _latom_vec__len,
1010 	.__tostring = _latom_vec__tostring,
1011 	.value = _latom_vec_value,
1012 	.unpack = _latom_vec_unpack,
1013 	.foreach = _latom_vec_foreach
1014 };
1015 
1016 __realtime static int
_latom_chunk__indexi(lua_State * L,latom_t * latom)1017 _latom_chunk__indexi(lua_State *L, latom_t *latom)
1018 {
1019 	const uint8_t *payload = latom->body.raw;
1020 	int index = lua_tointeger(L, 2); // indexing start from 1
1021 
1022 	if( (index > 0) && (index <= (int)latom->atom->size) )
1023 		lua_pushinteger(L, payload[index-1]);
1024 	else // index is out of bounds
1025 		lua_pushnil(L);
1026 
1027 	return 1;
1028 }
1029 
1030 __realtime static int
_latom_chunk__len(lua_State * L,latom_t * latom)1031 _latom_chunk__len(lua_State *L, latom_t *latom)
1032 {
1033 	lua_pushinteger(L, latom->atom->size);
1034 	return 1;
1035 }
1036 
1037 __realtime static int
_latom_chunk__tostring(lua_State * L,latom_t * latom)1038 _latom_chunk__tostring(lua_State *L, latom_t *latom)
1039 {
1040 	lua_pushfstring(L, "(chunk: %p)", latom);
1041 	return 1;
1042 }
1043 
1044 __realtime static int
_latom_chunk_value(lua_State * L,latom_t * latom)1045 _latom_chunk_value(lua_State *L, latom_t *latom)
1046 {
1047 	lua_pushlstring(L, latom->body.raw, latom->atom->size);
1048 
1049 	return 1;
1050 }
1051 
1052 __realtime int
_latom_chunk_unpack(lua_State * L)1053 _latom_chunk_unpack(lua_State *L)
1054 {
1055 	latom_t *latom = lua_touserdata(L, 1);
1056 	const uint8_t *payload = latom->body.raw;
1057 
1058 	int n = lua_gettop(L);
1059 	int min = 1;
1060 	int max = latom->atom->size;
1061 
1062 	if(n > 1) // check provided index ranges
1063 	{
1064 		min = luaL_checkinteger(L, 2);
1065 		min = min < 1
1066 			? 1
1067 			: (min > (int)latom->atom->size
1068 				? (int)latom->atom->size
1069 				: min);
1070 
1071 		if(n > 2)
1072 		{
1073 			max = luaL_checkinteger(L, 3);
1074 			max = max < 1
1075 				? 1
1076 				: (max > (int)latom->atom->size
1077 					? (int)latom->atom->size
1078 					: max);
1079 		}
1080 	}
1081 
1082 	for(int i=min; i<=max; i++)
1083 		lua_pushinteger(L, payload[i-1]);
1084 
1085 	return max - min + 1;
1086 }
1087 
1088 const latom_driver_t latom_chunk_driver = {
1089 	.__indexi = _latom_chunk__indexi,
1090 	.__len = _latom_chunk__len,
1091 	.__tostring = _latom_chunk__tostring,
1092 	.value = _latom_chunk_value,
1093 	.unpack = _latom_chunk_unpack
1094 };
1095 
1096 __realtime static int
_latom__index(lua_State * L)1097 _latom__index(lua_State *L)
1098 {
1099 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1100 	latom_t *latom = lua_touserdata(L, 1);
1101 	const latom_driver_t *driver = _latom_driver(moony, latom->atom->type);
1102 
1103 	if(driver)
1104 	{
1105 		const int type = lua_type(L, 2);
1106 		if(type == LUA_TSTRING)
1107 		{
1108 			const char *key = lua_tostring(L, 2);
1109 			if(!strcmp(key, "type"))
1110 			{
1111 				lua_pushinteger(L, latom->atom->type);
1112 				return 1;
1113 			}
1114 			else if(driver->value && !strcmp(key, "body"))
1115 			{
1116 				return driver->value(L, latom);
1117 			}
1118 			else if(driver->foreach && !strcmp(key, "foreach"))
1119 			{
1120 				lua_rawgetp(L, LUA_REGISTRYINDEX, driver->foreach);
1121 				return 1;
1122 			}
1123 			else if(driver->unpack && !strcmp(key, "unpack"))
1124 			{
1125 				lua_rawgetp(L, LUA_REGISTRYINDEX, driver->unpack);
1126 				return 1;
1127 			}
1128 			else if(!strcmp(key, "clone"))
1129 			{
1130 				lua_rawgetp(L, LUA_REGISTRYINDEX, _latom_clone);
1131 				return 1;
1132 			}
1133 			else if(!strcmp(key, "raw"))
1134 			{
1135 				lua_pushlstring(L, latom->body.raw, latom->atom->size);
1136 				return 1;
1137 			}
1138 			else if( (latom->lheader.type == MOONY_UDATA_STASH) && !strcmp(key, "write") )
1139 			{
1140 				lua_rawgetp(L, LUA_REGISTRYINDEX, _lstash_write);
1141 				return 1;
1142 			}
1143 			else if( (latom->lheader.type == MOONY_UDATA_STASH) && !strcmp(key, "read") )
1144 			{
1145 				lua_rawgetp(L, LUA_REGISTRYINDEX, _lstash_read);
1146 				return 1;
1147 			}
1148 			else if(driver->__indexk)
1149 			{
1150 				return driver->__indexk(L, latom, key);
1151 			}
1152 		}
1153 		else if(driver->__indexi && (type == LUA_TNUMBER) )
1154 		{
1155 			return driver->__indexi(L, latom);
1156 		}
1157 	}
1158 
1159 	lua_pushnil(L);
1160 	return 1;
1161 }
1162 
1163 __realtime static int
_latom__len(lua_State * L)1164 _latom__len(lua_State *L)
1165 {
1166 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1167 	latom_t *latom = lua_touserdata(L, 1);
1168 	const latom_driver_t *driver = _latom_driver(moony, latom->atom->type);
1169 
1170 	if(driver && driver->__len)
1171 		return driver->__len(L, latom);
1172 
1173 	lua_pushinteger(L, latom->atom->size);
1174 	return 1;
1175 }
1176 
1177 __realtime static int
_latom__tostring(lua_State * L)1178 _latom__tostring(lua_State *L)
1179 {
1180 	moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1181 	latom_t *latom = lua_touserdata(L, 1);
1182 	const latom_driver_t *driver = _latom_driver(moony, latom->atom->type);
1183 
1184 	if(driver && driver->__tostring)
1185 		return driver->__tostring(L, latom);
1186 
1187 	lua_pushnil(L);
1188 	return 1;
1189 }
1190 
1191 __realtime static int
_latom__eq(lua_State * L)1192 _latom__eq(lua_State *L)
1193 {
1194 	//moony_t *moony = lua_touserdata(L, lua_upvalueindex(1));
1195 	latom_t *latom1 = lua_touserdata(L, 1);
1196 	latom_t *latom2 = luaL_checkudata(L, 2, "latom");
1197 
1198 	lua_pushboolean(L,
1199 		(latom1->atom->type == latom2->atom->type)
1200 		&& (latom1->atom->size == latom2->atom->size)
1201 		&& (memcmp(latom1->body.raw, latom2->body.raw, latom1->atom->size) == 0) );
1202 
1203 	return 1;
1204 }
1205 
1206 const luaL_Reg latom_mt [] = {
1207 	{"__index", _latom__index},
1208 	{"__len", _latom__len},
1209 	{"__tostring", _latom__tostring},
1210 	{"__eq", _latom__eq},
1211 	{"__gc", _latom__gc},
1212 
1213 	{NULL, NULL}
1214 };
1215