Browse Source

Add: file:setvbuf

AnnulusGames 1 year ago
parent
commit
f5cace8ee9

+ 18 - 3
src/Lua/Standard/IO/FileHandle.cs

@@ -2,6 +2,8 @@ using Lua.Runtime;
 
 namespace Lua.Standard.IO;
 
+// TODO: optimize (remove StreamReader/Writer)
+
 public class FileHandle : LuaUserData
 {
     class IndexMetamethod : LuaFunction
@@ -19,6 +21,7 @@ public class FileHandle : LuaUserData
                     "read" => FileReadFunction.Instance,
                     "lines" => FileLinesFunction.Instance,
                     "flush" => FileFlushFunction.Instance,
+                    "setvbuf" => FileSetVBufFunction.Instance,
                     "close" => CloseFunction.Instance,
                     _ => LuaValue.Nil,
                 };
@@ -33,6 +36,7 @@ public class FileHandle : LuaUserData
     }
 
     Stream stream;
+    StreamWriter? writer;
     StreamReader? reader;
     bool isClosed;
 
@@ -50,6 +54,7 @@ public class FileHandle : LuaUserData
     {
         this.stream = stream;
         if (stream.CanRead) reader = new StreamReader(stream);
+        if (stream.CanWrite) writer = new StreamWriter(stream);
         Metatable = fileHandleMetatable;
     }
 
@@ -68,14 +73,24 @@ public class FileHandle : LuaUserData
         return stream.ReadByte();
     }
 
-    public void Write(ReadOnlySpan<byte> buffer)
+    public void Write(ReadOnlySpan<char> buffer)
     {
-        stream.Write(buffer);
+        writer!.Write(buffer);
     }
 
     public void Flush()
     {
-        stream.Flush();
+        writer!.Flush();
+    }
+
+    public void SetVBuf(string mode, int size)
+    {
+        // Ignore size parameter
+        
+        if (writer != null)
+        {
+            writer.AutoFlush = mode is "no" or "line";
+        }
     }
 
     public void Close()

+ 26 - 0
src/Lua/Standard/IO/FileSetVBufFunction.cs

@@ -0,0 +1,26 @@
+namespace Lua.Standard.IO;
+
+public sealed class FileSetVBufFunction : LuaFunction
+{
+    public override string Name => "setvbuf";
+    public static readonly FileSetVBufFunction Instance = new();
+
+    protected override ValueTask<int> InvokeAsyncCore(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    {
+        var file = context.ReadArgument<FileHandle>(0);
+        var mode = context.ReadArgument<string>(1);
+        var size = context.ArgumentCount >= 3
+            ? context.ReadArgument<double>(2)
+            : -1;
+
+        if (!MathEx.IsInteger(size))
+        {
+            throw new LuaRuntimeException(context.State.GetTraceback(), $"bad argument #3 to 'setvbuf' (number has no integer representation)");
+        }
+
+        file.SetVBuf(mode, (int)size);
+
+        buffer.Span[0] = true;
+        return new(1);
+    }
+}

+ 5 - 9
src/Lua/Standard/IO/IOHelper.cs

@@ -54,18 +54,14 @@ internal static class IOHelper
                 var arg = context.Arguments[i];
                 if (arg.TryRead<string>(out var str))
                 {
-                    using var fileBuffer = new PooledArray<byte>(str.Length * 3);
-                    var bytesWritten = Encoding.UTF8.GetBytes(str, fileBuffer.AsSpan());
-                    file.Write(fileBuffer.AsSpan()[..bytesWritten]);
+                    file.Write(str);
                 }
                 else if (arg.TryRead<double>(out var d))
                 {
-                    using var fileBuffer = new PooledArray<byte>(64);
-                    if (!Utf8Formatter.TryFormat(d, fileBuffer.AsSpan(), out var bytesWritten))
-                    {
-                        throw new ArgumentException("Destination is too short.");
-                    }
-                    file.Write(fileBuffer.AsSpan()[..bytesWritten]);
+                    using var fileBuffer = new PooledArray<char>(64);
+                    var span = fileBuffer.AsSpan();
+                    d.TryFormat(span, out var charsWritten);
+                    file.Write(span[..charsWritten]);
                 }
                 else
                 {