225 lines
4.4 KiB
D
225 lines
4.4 KiB
D
module luad.base;
|
|
|
|
import luad.c.all;
|
|
import luad.stack;
|
|
|
|
import core.stdc.string : strlen;
|
|
|
|
/**
|
|
* Enumerates all Lua types.
|
|
*/
|
|
enum LuaType
|
|
{
|
|
///string
|
|
String = LUA_TSTRING,
|
|
///number
|
|
Number = LUA_TNUMBER,
|
|
//table
|
|
Table = LUA_TTABLE,
|
|
///nil
|
|
Nil = LUA_TNIL,
|
|
///boolean
|
|
Boolean = LUA_TBOOLEAN,
|
|
///function
|
|
Function = LUA_TFUNCTION,
|
|
///userdata
|
|
Userdata = LUA_TUSERDATA,
|
|
///ditto
|
|
LightUserdata = LUA_TLIGHTUSERDATA,
|
|
///thread
|
|
Thread = LUA_TTHREAD
|
|
}
|
|
|
|
package struct Nil{}
|
|
|
|
/**
|
|
* Special value representing the Lua type and value nil.
|
|
* Examples:
|
|
* Useful for clearing keys in a table:
|
|
* --------------------------
|
|
lua["n"] = 1.23;
|
|
assert(lua.get!double("n") == 1.23);
|
|
|
|
lua["n"] = nil;
|
|
assert(lua["n"].type == LuaType.Nil);
|
|
* --------------------------
|
|
*/
|
|
public Nil nil;
|
|
|
|
/**
|
|
* Represents a reference to a Lua value of any type.
|
|
* It contains only the bare minimum of functionality which all Lua values support.
|
|
* For a generic reference type with more functionality, see $(DPREF dynamic,LuaDynamic).
|
|
*/
|
|
struct LuaObject
|
|
{
|
|
private:
|
|
int r = LUA_REFNIL;
|
|
lua_State* L = null;
|
|
|
|
package:
|
|
this(lua_State* L, int idx)
|
|
{
|
|
this.L = L;
|
|
|
|
lua_pushvalue(L, idx);
|
|
r = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
}
|
|
|
|
void push() nothrow
|
|
{
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, r);
|
|
}
|
|
|
|
static void checkType(lua_State* L, int idx, int expectedType, const(char)* expectedName)
|
|
{
|
|
int t = lua_type(L, idx);
|
|
if(t != expectedType)
|
|
{
|
|
luaL_error(L, "attempt to create %s with %s", expectedName, lua_typename(L, t));
|
|
}
|
|
}
|
|
|
|
public:
|
|
@trusted this(this)
|
|
{
|
|
push();
|
|
r = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
}
|
|
|
|
@trusted nothrow ~this()
|
|
{
|
|
luaL_unref(L, LUA_REGISTRYINDEX, r);
|
|
}
|
|
|
|
/// The underlying $(D lua_State) pointer for interfacing with C.
|
|
lua_State* state() pure nothrow @safe @property
|
|
{
|
|
return L;
|
|
}
|
|
|
|
/**
|
|
* Release this reference.
|
|
*
|
|
* This reference becomes a nil reference.
|
|
* This is only required when you want to _release the reference before the lifetime
|
|
* of this $(D LuaObject) has ended.
|
|
*/
|
|
void release() pure nothrow @safe
|
|
{
|
|
r = LUA_REFNIL;
|
|
L = null;
|
|
}
|
|
|
|
/**
|
|
* Type of referenced object.
|
|
* See_Also:
|
|
* $(MREF LuaType)
|
|
*/
|
|
@property LuaType type() @trusted nothrow
|
|
{
|
|
push();
|
|
auto result = cast(LuaType)lua_type(state, -1);
|
|
lua_pop(state, 1);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Type name of referenced object.
|
|
*/
|
|
@property string typeName() @trusted /+ nothrow +/
|
|
{
|
|
push();
|
|
const(char)* cname = luaL_typename(state, -1); // TODO: Doesn't have to use luaL_typename, i.e. no copy
|
|
auto name = cname[0.. strlen(cname)].idup;
|
|
lua_pop(state, 1);
|
|
return name;
|
|
}
|
|
|
|
/// Boolean whether or not the referenced object is nil.
|
|
@property bool isNil() pure nothrow @safe
|
|
{
|
|
return r == LUA_REFNIL;
|
|
}
|
|
|
|
/**
|
|
* Convert the referenced object into a textual representation.
|
|
*
|
|
* The returned string is formatted in the same way the Lua $(D tostring) function formats.
|
|
*
|
|
* Returns:
|
|
* String representation of referenced object
|
|
*/
|
|
string toString() @trusted
|
|
{
|
|
push();
|
|
|
|
size_t len;
|
|
const(char)* cstr = luaL_tolstring(state, -1, &len);
|
|
auto str = cstr[0 .. len].idup;
|
|
|
|
lua_pop(state, 2);
|
|
return str;
|
|
}
|
|
|
|
/**
|
|
* Attempt _to convert the referenced object _to the specified D type.
|
|
* Examples:
|
|
-----------------------
|
|
auto results = lua.doString(`return "hello!"`);
|
|
assert(results[0].to!string() == "hello!");
|
|
-----------------------
|
|
*/
|
|
T to(T)()
|
|
{
|
|
static void typeMismatch(lua_State* L, int t, int e)
|
|
{
|
|
luaL_error(L, "attempt to convert LuaObject with type %s to a %s", lua_typename(L, t), lua_typename(L, e));
|
|
}
|
|
|
|
push();
|
|
return popValue!(T, typeMismatch)(state);
|
|
}
|
|
|
|
/**
|
|
* Compare this object to another with Lua's equality semantics.
|
|
* Also returns false if the two objects are in different Lua states.
|
|
*/
|
|
bool opEquals(T : LuaObject)(ref T o) @trusted
|
|
{
|
|
if(o.state != this.state)
|
|
return false;
|
|
|
|
push();
|
|
o.push();
|
|
scope(success) lua_pop(state, 2);
|
|
|
|
return lua_equal(state, -1, -2);
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
lua_State* L = luaL_newstate();
|
|
scope(success) lua_close(L);
|
|
|
|
lua_pushstring(L, "foobar");
|
|
auto o = popValue!LuaObject(L);
|
|
|
|
assert(!o.isNil);
|
|
assert(o.type == LuaType.String);
|
|
assert(o.typeName == "string");
|
|
assert(o.to!string() == "foobar");
|
|
|
|
lua_pushnil(L);
|
|
auto nilref = popValue!LuaObject(L);
|
|
|
|
assert(nilref.isNil);
|
|
assert(nilref.typeName == "nil");
|
|
|
|
assert(o != nilref);
|
|
|
|
auto o2 = o;
|
|
assert(o2 == o);
|
|
}
|