parent
f34b640588
commit
d70ec9bf44
@ -0,0 +1,15 @@ |
||||
/*
|
||||
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include "lua.hpp" |
||||
|
||||
namespace lua { |
||||
|
||||
auto RegisterDatabaseModule(lua_State*) -> void; |
||||
|
||||
} // namespace lua
|
@ -0,0 +1,15 @@ |
||||
/*
|
||||
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include "lua.hpp" |
||||
|
||||
namespace lua { |
||||
|
||||
auto RegisterQueueModule(lua_State*) -> void; |
||||
|
||||
} // namespace lua
|
@ -0,0 +1,199 @@ |
||||
/*
|
||||
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#include "lua_database.hpp" |
||||
|
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include "lua.hpp" |
||||
|
||||
#include "esp_log.h" |
||||
#include "lauxlib.h" |
||||
#include "lua.h" |
||||
#include "lvgl.h" |
||||
|
||||
#include "database.hpp" |
||||
#include "event_queue.hpp" |
||||
#include "index.hpp" |
||||
#include "property.hpp" |
||||
#include "service_locator.hpp" |
||||
#include "ui_events.hpp" |
||||
|
||||
namespace lua { |
||||
|
||||
[[maybe_unused]] static constexpr char kTag[] = "lua_db"; |
||||
|
||||
static constexpr char kDbIndexMetatable[] = "db_index"; |
||||
static constexpr char kDbRecordMetatable[] = "db_record"; |
||||
static constexpr char kDbIteratorMetatable[] = "db_record"; |
||||
|
||||
static auto indexes(lua_State* state) -> int { |
||||
Bridge* instance = Bridge::Get(state); |
||||
|
||||
lua_newtable(state); |
||||
|
||||
auto db = instance->services().database().lock(); |
||||
if (!db) { |
||||
return 1; |
||||
} |
||||
|
||||
for (const auto& i : db->GetIndexes()) { |
||||
database::IndexInfo** data = reinterpret_cast<database::IndexInfo**>( |
||||
lua_newuserdata(state, sizeof(uintptr_t))); |
||||
luaL_setmetatable(state, kDbIndexMetatable); |
||||
*data = new database::IndexInfo{i}; |
||||
lua_rawseti(state, -2, i.id); |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
static const struct luaL_Reg kDatabaseFuncs[] = {{"indexes", indexes}, |
||||
{NULL, NULL}}; |
||||
|
||||
static auto db_iterate(lua_State* state) -> int { |
||||
database::Iterator* it = *reinterpret_cast<database::Iterator**>( |
||||
lua_touserdata(state, lua_upvalueindex(1))); |
||||
|
||||
auto res = it->Next(); |
||||
if (res) { |
||||
database::IndexRecord** record = reinterpret_cast<database::IndexRecord**>( |
||||
lua_newuserdata(state, sizeof(uintptr_t))); |
||||
*record = new database::IndexRecord(*res); |
||||
luaL_setmetatable(state, kDbRecordMetatable); |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static auto db_iterator_gc(lua_State* state) -> int { |
||||
database::Iterator** it = reinterpret_cast<database::Iterator**>( |
||||
luaL_checkudata(state, 1, kDbIteratorMetatable)); |
||||
if (it != NULL) { |
||||
delete *it; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static auto push_iterator( |
||||
lua_State* state, |
||||
std::variant<database::Continuation, database::IndexInfo> val) -> void { |
||||
Bridge* instance = Bridge::Get(state); |
||||
database::Iterator** data = reinterpret_cast<database::Iterator**>( |
||||
lua_newuserdata(state, sizeof(uintptr_t))); |
||||
std::visit( |
||||
[&](auto&& arg) { |
||||
*data = new database::Iterator(instance->services().database(), arg); |
||||
}, |
||||
val); |
||||
luaL_setmetatable(state, kDbIteratorMetatable); |
||||
lua_pushcclosure(state, db_iterate, 1); |
||||
} |
||||
|
||||
static auto record_text(lua_State* state) -> int { |
||||
database::IndexRecord* data = *reinterpret_cast<database::IndexRecord**>( |
||||
luaL_checkudata(state, 1, kDbRecordMetatable)); |
||||
lua_pushstring(state, |
||||
data->text().value_or("[tell jacqueline u saw this]").c_str()); |
||||
return 1; |
||||
} |
||||
|
||||
static auto record_contents(lua_State* state) -> int { |
||||
database::IndexRecord* data = *reinterpret_cast<database::IndexRecord**>( |
||||
luaL_checkudata(state, 1, kDbRecordMetatable)); |
||||
|
||||
if (data->track()) { |
||||
lua_pushinteger(state, *data->track()); |
||||
} else { |
||||
push_iterator(state, data->Expand(1).value()); |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
static auto record_gc(lua_State* state) -> int { |
||||
database::IndexRecord** data = reinterpret_cast<database::IndexRecord**>( |
||||
luaL_checkudata(state, 1, kDbRecordMetatable)); |
||||
if (data != NULL) { |
||||
delete *data; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static const struct luaL_Reg kDbRecordFuncs[] = {{"title", record_text}, |
||||
{"contents", record_contents}, |
||||
{"__tostring", record_text}, |
||||
{"__gc", record_gc}, |
||||
{NULL, NULL}}; |
||||
|
||||
static auto index_name(lua_State* state) -> int { |
||||
database::IndexInfo** data = reinterpret_cast<database::IndexInfo**>( |
||||
luaL_checkudata(state, 1, kDbIndexMetatable)); |
||||
if (data == NULL) { |
||||
return 0; |
||||
} |
||||
lua_pushstring(state, (*data)->name.c_str()); |
||||
return 1; |
||||
} |
||||
|
||||
static auto index_iter(lua_State* state) -> int { |
||||
database::IndexInfo** data = reinterpret_cast<database::IndexInfo**>( |
||||
luaL_checkudata(state, 1, kDbIndexMetatable)); |
||||
if (data == NULL) { |
||||
return 0; |
||||
} |
||||
push_iterator(state, **data); |
||||
return 1; |
||||
} |
||||
|
||||
static auto index_gc(lua_State* state) -> int { |
||||
database::IndexInfo** data = reinterpret_cast<database::IndexInfo**>( |
||||
luaL_checkudata(state, 1, kDbIndexMetatable)); |
||||
if (data != NULL) { |
||||
delete *data; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static const struct luaL_Reg kDbIndexFuncs[] = {{"name", index_name}, |
||||
{"iter", index_iter}, |
||||
{"__tostring", index_name}, |
||||
{"__gc", index_gc}, |
||||
{NULL, NULL}}; |
||||
|
||||
static auto lua_database(lua_State* state) -> int { |
||||
// Metatable for indexes
|
||||
luaL_newmetatable(state, kDbIndexMetatable); |
||||
|
||||
lua_pushliteral(state, "__index"); |
||||
lua_pushvalue(state, -2); |
||||
lua_settable(state, -3); // metatable.__index = metatable
|
||||
|
||||
// Add member funcs to the metatable.
|
||||
luaL_setfuncs(state, kDbIndexFuncs, 0); |
||||
|
||||
luaL_newmetatable(state, kDbIteratorMetatable); |
||||
lua_pushliteral(state, "__gc"); |
||||
lua_pushcfunction(state, db_iterator_gc); |
||||
lua_settable(state, -3); |
||||
|
||||
luaL_newmetatable(state, kDbRecordMetatable); |
||||
lua_pushliteral(state, "__index"); |
||||
lua_pushvalue(state, -2); |
||||
lua_settable(state, -3); // metatable.__index = metatable
|
||||
luaL_setfuncs(state, kDbRecordFuncs, 0); |
||||
|
||||
luaL_newlib(state, kDatabaseFuncs); |
||||
return 1; |
||||
} |
||||
|
||||
auto RegisterDatabaseModule(lua_State* s) -> void { |
||||
luaL_requiref(s, "database", lua_database, true); |
||||
lua_pop(s, 1); |
||||
} |
||||
|
||||
} // namespace lua
|
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#include "lua_database.hpp" |
||||
|
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include "lua.hpp" |
||||
|
||||
#include "esp_log.h" |
||||
#include "lauxlib.h" |
||||
#include "lua.h" |
||||
#include "lvgl.h" |
||||
|
||||
#include "database.hpp" |
||||
#include "event_queue.hpp" |
||||
#include "index.hpp" |
||||
#include "property.hpp" |
||||
#include "service_locator.hpp" |
||||
#include "ui_events.hpp" |
||||
|
||||
namespace lua { |
||||
|
||||
[[maybe_unused]] static constexpr char kTag[] = "lua_queue"; |
||||
|
||||
static auto queue_add(lua_State* state) -> int { |
||||
return 0; |
||||
} |
||||
|
||||
static const struct luaL_Reg kQueueFuncs[] = {{"add", queue_add}, {NULL, NULL}}; |
||||
|
||||
static auto lua_queue(lua_State* state) -> int { |
||||
luaL_newlib(state, kQueueFuncs); |
||||
return 1; |
||||
} |
||||
|
||||
auto RegisterQueueModule(lua_State* s) -> void { |
||||
luaL_requiref(s, "queue", lua_queue, true); |
||||
lua_pop(s, 1); |
||||
} |
||||
|
||||
} // namespace lua
|
@ -0,0 +1,59 @@ |
||||
--- Module for accessing and updating data about the user's library of tracks. |
||||
-- @module database |
||||
|
||||
local database = {} |
||||
|
||||
--- Returns a list of all indexes in the database. |
||||
-- @treturn Array(Index) |
||||
function database.indexes() end |
||||
|
||||
--- An iterator is a userdata type that behaves like an ordinary Lua iterator. |
||||
-- @type Iterator |
||||
local Iterator = {} |
||||
|
||||
--- A TrackId is a unique identifier, representing a playable track in the |
||||
--- user's library. |
||||
-- @type TrackId |
||||
local TrackId = {} |
||||
|
||||
--- A record is an item within an Index, representing some value at a specific |
||||
--- depth. |
||||
-- @type Record |
||||
local Record = {} |
||||
|
||||
--- Gets the human-readable text representing this record. The `__tostring` |
||||
--- metatable function is an alias of this function. |
||||
-- @treturn string |
||||
function Record:title() end |
||||
|
||||
--- Returns the value that this record represents. This may be either a track |
||||
--- id, for records which uniquely identify a track, or it may be a new |
||||
--- Iterator representing the next level of depth for the current index. |
||||
--- |
||||
--- For example, each Record in the "All Albums" index corresponds to an entire |
||||
--- album of tracks; the 'contents' of such a Record is an iterator returning |
||||
--- each track in the album represented by the Record. The contents of each of |
||||
--- the returned 'track' Records would be a full Track, as there is no further |
||||
--- disambiguation needed. |
||||
-- @treturn TrackId|Iterator(Record) |
||||
function Record:contents() end |
||||
|
||||
--- An index is heirarchical, sorted, view of the tracks within the database. |
||||
--- For example, the 'All Albums' index contains, first, a sorted list of every |
||||
--- album name in the library. Then, at the second level of the index, a sorted |
||||
--- list of every track within each album. |
||||
-- @type Index |
||||
local Index = {} |
||||
|
||||
--- Gets the human-readable name of this index. This is typically something |
||||
--- like "All Albums", or "Albums by Artist". The `__tostring` metatable |
||||
--- function is an alias of this function. |
||||
-- @treturn string |
||||
function Index:name() end |
||||
|
||||
--- Returns a new iterator that can be used to access every record within the |
||||
--- first level of this index. |
||||
-- @treturn Iterator(Record) |
||||
function Index:iter() end |
||||
|
||||
return database |
Loading…
Reference in new issue