Skip to content

Commit

Permalink
Implement warning buffer pooling and control messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Quahu committed Sep 4, 2024
1 parent 2e9d6be commit 183fdbe
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 13 deletions.
27 changes: 25 additions & 2 deletions src/Laylua.Tests/Tests/Library/LuaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ public unsafe void GetThread_WorksWithMultipleThreads()
}

[Test]
public void Warn_TriggersWarningEvent()
public void Warn_OnePieceMessage_TriggersWarningEvent()
{
// Arrange
const string Message = "This is a warning message.";
Expand All @@ -315,7 +315,7 @@ public void Warn_TriggersWarningEvent()
}

[Test]
public void ContinuedWarn_TriggersSingleWarningEvent()
public void Warn_MultiPieceMessage_TriggersSingleWarningEvent()
{
// Arrange
const string Message = "Youshallnotpass.";
Expand All @@ -335,4 +335,27 @@ public void ContinuedWarn_TriggersSingleWarningEvent()
Assert.That(collectedMessages, Has.Count.EqualTo(1));
Assert.That(collectedMessages[0], Is.EqualTo(Message));
}

[Test]
public void Warn_OffOnControlMessages_TogglesEmitsWarningsAccordingly()
{
// Arrange
const string Message = "This is a warning message.";
var collectedMessages = new List<string>();

Lua.OpenLibrary(LuaLibraries.Standard.Base);
Lua.Warning += (_, e) =>
{
collectedMessages.Add(e.Message.ToString());
};

// Act
Lua.Execute("warn('@off')");
Lua.Execute($"warn('{Message}')");
Lua.Execute("warn('@on')");
Lua.Execute($"warn('{Message}')");

// Assert
Assert.That(collectedMessages, Is.EqualTo(new[] { Message }));
}
}
70 changes: 59 additions & 11 deletions src/Laylua/Library/Lua.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Laylua.Marshaling;
using Laylua.Moon;
using Qommon;
using Qommon.Pooling;

namespace Laylua;

Expand Down Expand Up @@ -64,6 +65,15 @@ public object? this[string name]
set => SetGlobal(name, value);
}

/// <summary>
/// Gets or sets whether <see cref="Warning"/> should fire for emitted warnings.
/// </summary>
/// <remarks>
/// This can be controlled by the content of warning messages;
/// can be disabled using "@off" and enabled using "@on".
/// </remarks>
public bool EmitsWarnings { get; set; } = true;

/// <summary>
/// Fired when Lua emits a warning. <br/>
/// See <a href="https://www.lua.org/manual/5.4/manual.html#2.3">Lua manual</a> for more information about warnings.
Expand Down Expand Up @@ -141,38 +151,76 @@ private Lua(
private static void WarningHandler(void* ud, byte* msg, int tocont)
{
var lua = FromExtraSpace((lua_State*) ud);
var handlers = lua._warningHandlers;
if (handlers.Count == 0)
var msgSpan = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(msg);
if (msgSpan.StartsWith("@"u8))
{
ProcessControlWarningMessage(lua, msgSpan[1..]);
return;
}

if (!lua.EmitsWarnings || lua._warningHandlers.Count == 0)
{
return;
}

var msgSpan = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(msg);
if (tocont != 0)
{
(lua._warningBuffer ??= new(capacity: 128)).Write(msgSpan);
return;
}

ReadOnlyMemory<char> message;
RentedArray<char> message;
var warningBuffer = lua._warningBuffer;
if (warningBuffer == null)
if (warningBuffer == null || warningBuffer.Length == 0)
{
message = Encoding.UTF8.GetString(msgSpan).AsMemory();
message = CreateWarningMessage(msgSpan);
}
else
{
warningBuffer.Write(msgSpan);
Debug.Assert(warningBuffer.TryGetBuffer(out var buffer));
message = Encoding.UTF8.GetString(buffer).AsMemory();

warningBuffer.Position = 0;
warningBuffer.SetLength(0);
message = CreateWarningMessage(buffer);

Check failure on line 183 in src/Laylua/Library/Lua.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'buffer'

Check failure on line 183 in src/Laylua/Library/Lua.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'buffer'

Check failure on line 183 in src/Laylua/Library/Lua.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'buffer'

Check failure on line 183 in src/Laylua/Library/Lua.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'buffer'

Check failure on line 183 in src/Laylua/Library/Lua.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'buffer'

Check failure on line 183 in src/Laylua/Library/Lua.cs

View workflow job for this annotation

GitHub Actions / build

Use of unassigned local variable 'buffer'

ClearWarningBuffer(warningBuffer);
}

using (message)
{
foreach (var handler in lua._warningHandlers)
{
handler.Invoke(lua, new LuaWarningEventArgs(message));
}
}

static void ProcessControlWarningMessage(Lua lua, ReadOnlySpan<byte> controlMsg)
{
if (controlMsg.SequenceEqual("on"u8))
{
lua.EmitsWarnings = true;
}
else if (controlMsg.SequenceEqual("off"u8))
{
lua.EmitsWarnings = false;

if (lua._warningBuffer != null)
{
ClearWarningBuffer(lua._warningBuffer);
}
}
}

static RentedArray<char> CreateWarningMessage(ReadOnlySpan<byte> msg)
{
var message = RentedArray<char>.Rent(Encoding.UTF8.GetCharCount(msg));
_ = Encoding.UTF8.GetChars(msg, message);
return message;
}

foreach (var handler in handlers)
static void ClearWarningBuffer(MemoryStream warningBuffer)
{
handler.Invoke(lua, new LuaWarningEventArgs(message));
warningBuffer.Position = 0;
warningBuffer.SetLength(0);
}
}

Expand Down

0 comments on commit 183fdbe

Please sign in to comment.