Skip to content

Instantly share code, notes, and snippets.

@zeux
Last active November 24, 2021 20:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeux/6779d59c9e3edf640ad7d0b586710ea0 to your computer and use it in GitHub Desktop.
Save zeux/6779d59c9e3edf640ad7d0b586710ea0 to your computer and use it in GitHub Desktop.
A simple proof of concept for Luau function binding.
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
// Use this with luaL_Reg + luaL_register:
//
// static const luaL_Reg funcs[] = {
// {"test123", LUAU_BIND(test123)},
// {NULL, NULL},
// };
#include "lua.h"
#include "lualib.h"
#include <utility>
#include <type_traits>
namespace Luau
{
template <typename T> struct UnsupportedType;
template <typename T>
auto bindRead(lua_State* L, int idx)
{
using DT = std::decay_t<T>;
if constexpr (std::is_same_v<DT, bool>)
{
return bool(luaL_checkboolean(L, idx));
}
else if constexpr (std::is_same_v<DT, const char*>)
{
return luaL_checkstring(L, idx);
}
else if constexpr (std::is_arithmetic_v<DT>)
{
return DT(luaL_checknumber(L, idx));
}
else
{
static_assert(UnsupportedType<T>::value);
}
}
template <typename T>
void bindWrite(lua_State* L, const T& v)
{
if constexpr (std::is_same_v<T, bool>)
{
lua_pushboolean(L, v);
}
else if constexpr (std::is_same_v<T, const char*>)
{
lua_pushstring(L, v);
}
else if constexpr (std::is_arithmetic_v<T>)
{
lua_pushnumber(L, double(v));
}
else
{
static_assert(UnsupportedType<T>::value);
}
}
template <typename T>
struct Binder;
template <typename R, typename... Args>
struct Binder<R(Args...)>
{
template <R (*fn)(Args...), int... Idx>
static lua_CFunction impl(std::integer_sequence<int, Idx...>)
{
return [](lua_State* L) -> int
{
if constexpr (std::is_same_v<R, void>)
{
fn(bindRead<Args>(L, 1 + Idx)...);
return 0;
}
else
{
R r = fn(bindRead<Args>(L, 1 + Idx)...);
bindWrite(L, r);
return 1;
}
};
}
template <R (*fn)(Args...)>
static lua_CFunction get()
{
using IS = std::make_integer_sequence<int, sizeof...(Args)>;
return impl<fn>(IS{});
}
};
}
#define LUAU_BIND(fun) Luau::Binder<decltype(fun)>::get<fun>()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment