/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using LuaInterface.Extensions;
namespace LuaInterface
{
/*
* Type checking and conversion functions.
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class CheckType
{
private Dictionary extractValues = new Dictionary();
private ExtractValue extractNetObject;
private ObjectTranslator translator;
public CheckType(ObjectTranslator translator)
{
this.translator = translator;
extractValues.Add(typeof(object).TypeHandle.Value.ToInt64(), new ExtractValue(getAsObject));
extractValues.Add(typeof(sbyte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsSbyte));
extractValues.Add(typeof(byte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsByte));
extractValues.Add(typeof(short).TypeHandle.Value.ToInt64(), new ExtractValue(getAsShort));
extractValues.Add(typeof(ushort).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUshort));
extractValues.Add(typeof(int).TypeHandle.Value.ToInt64(), new ExtractValue(getAsInt));
extractValues.Add(typeof(uint).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUint));
extractValues.Add(typeof(long).TypeHandle.Value.ToInt64(), new ExtractValue(getAsLong));
extractValues.Add(typeof(ulong).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUlong));
extractValues.Add(typeof(double).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDouble));
extractValues.Add(typeof(char).TypeHandle.Value.ToInt64(), new ExtractValue(getAsChar));
extractValues.Add(typeof(float).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFloat));
extractValues.Add(typeof(decimal).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDecimal));
extractValues.Add(typeof(bool).TypeHandle.Value.ToInt64(), new ExtractValue(getAsBoolean));
extractValues.Add(typeof(string).TypeHandle.Value.ToInt64(), new ExtractValue(getAsString));
extractValues.Add(typeof(LuaFunction).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFunction));
extractValues.Add(typeof(LuaTable).TypeHandle.Value.ToInt64(), new ExtractValue(getAsTable));
extractValues.Add(typeof(LuaUserData).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUserdata));
extractNetObject = new ExtractValue(getAsNetObject);
}
/*
* Checks if the value at Lua stack index stackPos matches paramType,
* returning a conversion function if it does and null otherwise.
*/
internal ExtractValue getExtractor(IReflect paramType)
{
return getExtractor(paramType.UnderlyingSystemType);
}
internal ExtractValue getExtractor(Type paramType)
{
if(paramType.IsByRef)
paramType = paramType.GetElementType();
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
return extractValues.ContainsKey(runtimeHandleValue) ? extractValues[runtimeHandleValue] : extractNetObject;
}
internal ExtractValue checkType(KopiLua.Lua.lua_State luaState, int stackPos, Type paramType)
{
var luatype = KopiLua.Lua.lua_type(luaState, stackPos).ToLuaTypes();
if(paramType.IsByRef)
paramType = paramType.GetElementType();
var underlyingType = Nullable.GetUnderlyingType(paramType);
if(!underlyingType.IsNull())
paramType = underlyingType; // Silently convert nullable types to their non null requics
long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
if(paramType.Equals(typeof(object)))
return extractValues[runtimeHandleValue];
//CP: Added support for generic parameters
if(paramType.IsGenericParameter)
{
if(luatype == LuaTypes.Boolean)
return extractValues[typeof(bool).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.String)
return extractValues[typeof(string).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Table)
return extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.UserData)
return extractValues[typeof(object).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Function)
return extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()];
else if(luatype == LuaTypes.Number)
return extractValues[typeof(double).TypeHandle.Value.ToInt64()];
//else
//;//an unsupported type was encountered
}
if(KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
if(paramType == typeof(bool))
{
if(KopiLua.Lua.lua_isboolean(luaState, stackPos))
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(string))
{
if(KopiLua.Lua.lua_isstring(luaState, stackPos).ToBoolean())
return extractValues[runtimeHandleValue];
else if(luatype == LuaTypes.Nil)
return extractNetObject; // kevinh - silently convert nil to a null string pointer
}
else if(paramType == typeof(LuaTable))
{
if(luatype == LuaTypes.Table)
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(LuaUserData))
{
if(luatype == LuaTypes.UserData)
return extractValues[runtimeHandleValue];
}
else if(paramType == typeof(LuaFunction))
{
if(luatype == LuaTypes.Function)
return extractValues[runtimeHandleValue];
}
else if(typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.Function)
return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated);
else if(paramType.IsInterface && luatype == LuaTypes.Table)
return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated);
else if((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.Nil)
{
// kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
return extractNetObject;
}
else if(KopiLua.Lua.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(KopiLua.Lua.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
object obj = translator.getNetObject(luaState, -1);
KopiLua.Lua.lua_settop(luaState, -2);
if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
else
return null;
}
else
{
object obj = translator.getNetObject(luaState, stackPos);
if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType()))
return extractNetObject;
}
return null;
}
/*
* The following functions return the value in the Lua stack
* index stackPos as the desired type if it can, or null
* otherwise.
*/
private object getAsSbyte(KopiLua.Lua.lua_State luaState, int stackPos)
{
sbyte retVal = (sbyte)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsByte(KopiLua.Lua.lua_State luaState, int stackPos)
{
byte retVal = (byte)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsShort(KopiLua.Lua.lua_State luaState, int stackPos)
{
short retVal = (short)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUshort(KopiLua.Lua.lua_State luaState, int stackPos)
{
ushort retVal = (ushort)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsInt(KopiLua.Lua.lua_State luaState, int stackPos)
{
int retVal = (int)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUint(KopiLua.Lua.lua_State luaState, int stackPos)
{
uint retVal = (uint)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsLong(KopiLua.Lua.lua_State luaState, int stackPos)
{
long retVal = (long)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsUlong(KopiLua.Lua.lua_State luaState, int stackPos)
{
ulong retVal = (ulong)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsDouble(KopiLua.Lua.lua_State luaState, int stackPos)
{
double retVal = KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsChar(KopiLua.Lua.lua_State luaState, int stackPos)
{
char retVal = (char)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsFloat(KopiLua.Lua.lua_State luaState, int stackPos)
{
float retVal = (float)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsDecimal(KopiLua.Lua.lua_State luaState, int stackPos)
{
decimal retVal = (decimal)KopiLua.Lua.lua_tonumber(luaState, stackPos);
if(retVal == 0 && !KopiLua.Lua.lua_isnumber(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsBoolean(KopiLua.Lua.lua_State luaState, int stackPos)
{
return KopiLua.Lua.lua_toboolean(luaState, stackPos);
}
private object getAsString(KopiLua.Lua.lua_State luaState, int stackPos)
{
string retVal = KopiLua.Lua.lua_tostring(luaState, stackPos).ToString();
if(retVal == string.Empty && !KopiLua.Lua.lua_isstring(luaState, stackPos).ToBoolean())
return null;
return retVal;
}
private object getAsTable(KopiLua.Lua.lua_State luaState, int stackPos)
{
return translator.getTable(luaState, stackPos);
}
private object getAsFunction(KopiLua.Lua.lua_State luaState, int stackPos)
{
return translator.getFunction(luaState, stackPos);
}
private object getAsUserdata(KopiLua.Lua.lua_State luaState, int stackPos)
{
return translator.getUserData(luaState, stackPos);
}
public object getAsObject(KopiLua.Lua.lua_State luaState, int stackPos)
{
if(KopiLua.Lua.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(KopiLua.Lua.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState, -1))
{
KopiLua.Lua.lua_insert(luaState, stackPos);
KopiLua.Lua.lua_remove(luaState, stackPos+1);
}
else
KopiLua.Lua.lua_settop(luaState, -2);
}
}
object obj = translator.getObject(luaState, stackPos);
return obj;
}
public object getAsNetObject(KopiLua.Lua.lua_State luaState, int stackPos)
{
object obj = translator.getNetObject(luaState, stackPos);
if(obj.IsNull() && KopiLua.Lua.lua_type(luaState, stackPos).ToLuaTypes() == LuaTypes.Table)
{
if(KopiLua.Lua.luaL_getmetafield(luaState, stackPos, "__index").ToBoolean())
{
if(LuaLib.luaL_checkmetatable(luaState, -1))
{
KopiLua.Lua.lua_insert(luaState, stackPos);
KopiLua.Lua.lua_remove(luaState, stackPos+1);
obj = translator.getNetObject(luaState, stackPos);
}
else
KopiLua.Lua.lua_settop(luaState, -2);
}
}
return obj;
}
}
}