Skip to content

Commit

Permalink
Added support for pointers.
Browse files Browse the repository at this point in the history
Pointers are opaque.
Pointers support 'nil' assignment.
'deref' property on pointers to access the actual object.
  • Loading branch information
TurkeyMan committed Mar 7, 2016
1 parent 3a33813 commit 7294e42
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 2 deletions.
145 changes: 145 additions & 0 deletions luad/conversions/pointers.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/**
Internal module for pushing and getting pointers.
Pointers are stored in metadata with metatables to enfirce type-safety.
A 'deref' property is created to access the pointer's value.
*/
module luad.conversions.pointers;

import luad.conversions.helpers;
import luad.conversions.functions;

import luad.c.all;
import luad.stack;

import core.memory;

import std.traits;
import std.conv;

void pushGetter(T)(lua_State* L)
{
static if(isUserStruct!(PointerTarget!T))
{
static ref PointerTarget!T deref(T ptr)
{
return *ptr;
}
}
else
{
static PointerTarget!T deref(T ptr)
{
return *ptr;
}
}

lua_pushlightuserdata(L, &deref);
lua_pushcclosure(L, &functionWrapper!(typeof(&deref)), 1);
}

private void pushGetters(T)(lua_State* L)
{
lua_newtable(L); // -2 is getters
lua_newtable(L); // -1 is methods

pushGetter!T(L);
lua_setfield(L, -3, "deref");

lua_pushcclosure(L, &index, 2);
}

void pushSetter(T)(lua_State* L)
{
static if(isUserStruct!(PointerTarget!T))
{
static void deref(T ptr, ref PointerTarget!T val)
{
*ptr = val;
}
}
else
{
static void deref(T ptr, PointerTarget!T val)
{
*ptr = val;
}
}

lua_pushlightuserdata(L, &deref);
lua_pushcclosure(L, &functionWrapper!(typeof(&deref)), 1);
}

private void pushSetters(T)(lua_State* L)
{
lua_newtable(L);

pushSetter!T(L);
lua_setfield(L, -2, "deref");

lua_pushcclosure(L, &newIndex, 1);
}

private void pushMeta(T)(lua_State* L)
{
if(luaL_newmetatable(L, T.mangleof.ptr) == 0)
return;

pushValue(L, T.stringof);
lua_setfield(L, -2, "__dtype");

// TODO: mangled names can get REALLY long in D, it might be nicer to store a hash instead?
pushValue(L, T.mangleof);
lua_setfield(L, -2, "__dmangle");

lua_pushcfunction(L, &userdataCleaner);
lua_setfield(L, -2, "__gc");

static if(!is(Unqual!(PointerTarget!T) == void))
{
pushGetters!T(L);
lua_setfield(L, -2, "__index");
static if(isMutable!(PointerTarget!T))
{
pushSetters!T(L);
lua_setfield(L, -2, "__newindex");
}
}

lua_pushvalue(L, -1);
lua_setfield(L, -2, "__metatable");
}

void pushPointer(T)(lua_State* L, T value) if (isPointer!T)
{
T* udata = cast(T*)lua_newuserdata(L, T.sizeof);
*udata = value;

GC.addRoot(udata);

pushMeta!T(L);
lua_setmetatable(L, -2);
}


T getPointer(T)(lua_State* L, int idx) if(isPointer!T)
{
verifyType!T(L, idx);

T* udata = cast(T*)lua_touserdata(L, idx);
return *udata;
}

version(unittest)
{
import luad.base;
}

unittest
{
import luad.testing;

lua_State* L = luaL_newstate();
scope(success) lua_close(L);
luaL_openlibs(L);

}
14 changes: 12 additions & 2 deletions luad/stack.d
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import luad.conversions.arrays;
import luad.conversions.structs;
import luad.conversions.assocarrays;
import luad.conversions.classes;
import luad.conversions.pointers;
import luad.conversions.variant;
import luad.conversions.helpers;

Expand Down Expand Up @@ -132,6 +133,12 @@ void pushValue(T)(lua_State* L, T value) if(!isUserStruct!T)
else static if(isSomeFunction!T)
pushFunction(L, value);

else static if(isPointer!T)
{
// TODO: if value == null -> lua_pushnil(L);
pushPointer(L, value);
}

else static if(is(T == class))
{
if(value is null)
Expand Down Expand Up @@ -188,7 +195,7 @@ template luaTypeOf(T)
else static if(isArray!T || isAssociativeArray!T || is(T == LuaTable))
enum luaTypeOf = LUA_TTABLE;

else static if(is(T : const(Object)) || is(T == struct))
else static if(is(T : const(Object)) || is(T == struct) || isPointer!T)
enum luaTypeOf = LUA_TUSERDATA;

else
Expand Down Expand Up @@ -236,7 +243,7 @@ T getValue(T, alias typeMismatchHandler = defaultTypeMismatch)(lua_State* L, int
enum expectedType = luaTypeOf!T;

//if a class reference, return null for nil values
static if(is(T : const(Object)))
static if(is(T : const(Object)) || isPointer!T)
{
if(type == LuaType.Nil)
return null;
Expand Down Expand Up @@ -305,6 +312,9 @@ T getValue(T, alias typeMismatchHandler = defaultTypeMismatch)(lua_State* L, int
else static if(isSomeFunction!T)
return getFunction!T(L, idx);

else static if(isPointer!T)
return getPointer!T(L, idx);

else static if(is(T : const(Object)))
return getClassInstance!T(L, idx);

Expand Down
1 change: 1 addition & 0 deletions visuald/LuaD.visualdproj
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@
<File path="..\luad\conversions\classes.d" />
<File path="..\luad\conversions\functions.d" />
<File path="..\luad\conversions\helpers.d" />
<File path="..\luad\conversions\pointers.d" />
<File path="..\luad\conversions\structs.d" />
<File path="..\luad\conversions\variant.d" />
</Folder>
Expand Down

0 comments on commit 7294e42

Please sign in to comment.