internal void PushObject(object obj, IntPtr?stateOverride = null) { var state = stateOverride ?? MainState; Debug.Assert(LuaApi.GetMainState(state) == MainState, "State override did not match main state."); if (obj == null) { LuaApi.PushNil(state); return; } if (obj is IConvertible conv) { switch (conv.GetTypeCode()) { case TypeCode.Boolean: LuaApi.PushBoolean(state, (bool)obj); return; case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: LuaApi.PushInteger(state, conv.ToInt64(null)); return; case TypeCode.UInt64: LuaApi.PushInteger(state, (long)((ulong)conv)); return; case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: LuaApi.PushNumber(state, conv.ToDouble(null)); return; case TypeCode.Char: case TypeCode.String: LuaApi.PushString(state, conv.ToString()); return; default: ObjectBinder.PushNetObject(state, conv); return; } } else if (obj is LuaReference luaReference) { luaReference.PushOnto(state); } else { ObjectBinder.PushNetObject(state, obj); } }
internal void PushOnto(IntPtr state) { if (state != Lua.MainState && LuaApi.GetMainState(state) != Lua.MainState) { throw new ArgumentException("Reference cannot be pushed onto the given Lua environment.", nameof(state)); } LuaApi.RawGetI(state, LuaApi.RegistryIndex, _referenceId); }
internal object[] Call(object[] args, IntPtr?stateOverride = null, bool isResuming = false) { var state = stateOverride ?? MainState; Debug.Assert(LuaApi.GetMainState(state) == MainState, "State override did not match main state."); Debug.Assert(isResuming || LuaApi.Type(state, -1) == LuaType.Function, "Stack doesn't have function on top."); var oldTop = isResuming ? 0 : LuaApi.GetTop(state) - 1; var numArgs = args.Length; if (oldTop + numArgs > LuaApi.MinStackSize && !LuaApi.CheckStack(state, numArgs)) { throw new LuaException("Not enough stack space for arguments."); } foreach (var arg in args) { PushObject(arg, state); } var status = isResuming ? LuaApi.Resume(state, MainState, numArgs) : LuaApi.PCallK(state, numArgs); if (status != LuaStatus.Ok && status != LuaStatus.Yield) { var errorMessage = LuaApi.ToString(state, -1); LuaApi.Pop(state, 1); throw new LuaException(errorMessage); } // This is a fast path for functions returning nothing since we avoid a SetTop call. var top = LuaApi.GetTop(state); if (top == oldTop) { return(EmptyObjectArray); } if (top + 1 > LuaApi.MinStackSize && !LuaApi.CheckStack(state, 1)) { throw new LuaException("Not enough scratch stack space."); } var results = ToObjects(oldTop + 1, top, state); LuaApi.SetTop(state, oldTop); return(results); }
internal object ToObject(int index, LuaType?typeHint = null, IntPtr?stateOverride = null) { var state = stateOverride ?? MainState; Debug.Assert(LuaApi.GetMainState(state) == MainState, "State override did not match main state."); var type = typeHint ?? LuaApi.Type(state, index); Debug.Assert(type == LuaApi.Type(state, index), "Type hint did not match type."); switch (type) { case LuaType.None: case LuaType.Nil: return(null); case LuaType.Boolean: return(LuaApi.ToBoolean(state, index)); case LuaType.Number: var isInteger = LuaApi.IsInteger(state, index); return(isInteger ? LuaApi.ToInteger(state, index) : (object)LuaApi.ToNumber(state, index)); case LuaType.String: return(LuaApi.ToString(state, index)); case LuaType.Userdata: var handle = LuaApi.ToHandle(state, index); return(handle.Target); } LuaReference luaReference = null; var pointer = LuaApi.ToPointer(state, index); if (_cachedLuaReferences.TryGetValue(pointer, out var weakReference)) { luaReference = (LuaReference)weakReference.Target; if (luaReference != null) { return(luaReference); } } LuaApi.PushValue(state, index); var referenceId = LuaApi.Ref(state, LuaApi.RegistryIndex); switch (type) { case LuaType.Table: luaReference = new LuaTable(this, referenceId); break; case LuaType.Function: luaReference = new LuaFunction(this, referenceId); break; case LuaType.Thread: luaReference = new LuaThread(this, referenceId, pointer); break; } if (weakReference != null) { weakReference.Target = luaReference; } else { _cachedLuaReferences[pointer] = new WeakReference(luaReference); } _pointerToReferenceId[pointer] = referenceId; return(luaReference); }