From 2626e45d7b83e5b4ce7124a458650e930aba9135 Mon Sep 17 00:00:00 2001 From: Akeit0 <90429982+Akeit0@users.noreply.github.com> Date: Thu, 12 Jun 2025 22:02:16 +0900 Subject: [PATCH] revert allows bytes --- src/Lua/IO/BinaryData.cs | 16 -- src/Lua/IO/BinaryLuaStream.cs | 88 -------- src/Lua/IO/CompositeLoaderFileSystem.cs | 2 +- src/Lua/IO/FileSystem.cs | 38 ++-- src/Lua/IO/ILuaFileSystem.cs | 2 +- src/Lua/IO/ILuaStream.cs | 43 ++-- src/Lua/IO/LuaChunkStream.cs | 107 ---------- src/Lua/IO/LuaFileMode.cs | 201 ------------------ src/Lua/IO/LuaFileOpenMode.cs | 127 ++++++++--- src/Lua/IO/MemoryStreams.cs | 101 +-------- src/Lua/IO/StandardIOStream.cs | 6 +- src/Lua/IO/TextLuaStream.cs | 13 +- src/Lua/Loaders/FileModuleLoader.cs | 19 -- src/Lua/LuaFileContent.cs | 73 ------- src/Lua/LuaModule.cs | 51 ++--- src/Lua/LuaState.cs | 3 +- src/Lua/LuaStateExtensions.cs | 27 +-- src/Lua/Standard/BasicLibrary.cs | 12 +- src/Lua/Standard/FileHandle.cs | 18 +- src/Lua/Standard/IOLibrary.cs | 28 +-- src/Lua/Standard/Internal/IOHelper.cs | 14 +- src/Lua/Standard/ModuleLibrary.cs | 15 +- tests/Lua.Tests/AbstractFileTests.cs | 4 +- tests/Lua.Tests/Helpers/CharMemoryStream.cs | 5 +- .../NotImplementedExceptionFileSystemBase.cs | 2 +- .../Helpers/NotSupportedStreamBase.cs | 7 +- tests/Lua.Tests/IOTests.cs | 187 +++------------- 27 files changed, 244 insertions(+), 965 deletions(-) delete mode 100644 src/Lua/IO/BinaryData.cs delete mode 100644 src/Lua/IO/BinaryLuaStream.cs delete mode 100644 src/Lua/IO/LuaChunkStream.cs delete mode 100644 src/Lua/IO/LuaFileMode.cs delete mode 100644 src/Lua/Loaders/FileModuleLoader.cs delete mode 100644 src/Lua/LuaFileContent.cs diff --git a/src/Lua/IO/BinaryData.cs b/src/Lua/IO/BinaryData.cs deleted file mode 100644 index 8c66829d..00000000 --- a/src/Lua/IO/BinaryData.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Buffers; - -namespace Lua.IO; - -public class BinaryData(ReadOnlyMemory bytes) : IBinaryData -{ - public ReadOnlyMemory Memory => bytes; -} - -public interface IBinaryData -{ - /// - /// Gets the bytes of the binary data. - /// - public ReadOnlyMemory Memory { get; } -} \ No newline at end of file diff --git a/src/Lua/IO/BinaryLuaStream.cs b/src/Lua/IO/BinaryLuaStream.cs deleted file mode 100644 index 8ed72ee7..00000000 --- a/src/Lua/IO/BinaryLuaStream.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Text; - -namespace Lua.IO; - -internal sealed class BinaryLuaStream(LuaFileMode mode, Stream innerStream) : ILuaStream -{ - ulong flushSize = ulong.MaxValue; - ulong nextFlushSize = ulong.MaxValue; - - public LuaFileMode Mode => mode; - - public ValueTask ReadAllAsync(CancellationToken cancellationToken) - { - mode.ThrowIfNotReadable(); - using var memoryStream = new MemoryStream(); - innerStream.CopyTo(memoryStream); - var bytes = memoryStream.ToArray(); - return new(new LuaFileContent(bytes)); - } - - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) - { - mode.ThrowIfNotReadable(); - if (content.Type != LuaFileContentType.Binary) - { - var encoding = Encoding.UTF8; - var span = content.ReadText().Span; - var byteCount = encoding.GetByteCount(span); - var bytes = new byte[byteCount]; - encoding.GetBytes(span, bytes); - return WriteBytesAsync(bytes, cancellationToken); - } - - return WriteBytesAsync(content.ReadBytes().Span, cancellationToken); - } - - - public ValueTask WriteBytesAsync(ReadOnlySpan buffer, CancellationToken cancellationToken) - { - if (mode.IsAppend()) - { - innerStream.Seek(0, SeekOrigin.End); - } - - innerStream.Write(buffer); - - if (nextFlushSize < (ulong)buffer.Length) - { - innerStream.Flush(); - nextFlushSize = flushSize; - } - - return new(); - } - - public ValueTask FlushAsync(CancellationToken cancellationToken) - { - innerStream.Flush(); - nextFlushSize = flushSize; - return new(); - } - - public void SetVBuf(LuaFileBufferingMode mode, int size) - { - // Ignore size parameter - if (mode is LuaFileBufferingMode.NoBuffering or LuaFileBufferingMode.LineBuffering) - { - nextFlushSize = 0; - flushSize = 0; - } - else - { - nextFlushSize = (ulong)size; - flushSize = (ulong)size; - } - } - - public long Seek(long offset, SeekOrigin origin) - { - return innerStream.Seek(offset, origin); - } - - public void Dispose() - { - if (innerStream.CanWrite) innerStream.Flush(); - innerStream.Dispose(); - } -} \ No newline at end of file diff --git a/src/Lua/IO/CompositeLoaderFileSystem.cs b/src/Lua/IO/CompositeLoaderFileSystem.cs index 40155838..6c51e9eb 100644 --- a/src/Lua/IO/CompositeLoaderFileSystem.cs +++ b/src/Lua/IO/CompositeLoaderFileSystem.cs @@ -40,7 +40,7 @@ public bool IsReadable(string path) return false; } - public async ValueTask Open(string path, LuaFileMode mode, CancellationToken cancellationToken) + public async ValueTask Open(string path, LuaFileOpenMode mode, CancellationToken cancellationToken) { if (cached != null) { diff --git a/src/Lua/IO/FileSystem.cs b/src/Lua/IO/FileSystem.cs index 87f51016..26e6d6c0 100644 --- a/src/Lua/IO/FileSystem.cs +++ b/src/Lua/IO/FileSystem.cs @@ -9,9 +9,9 @@ public static (FileMode, FileAccess access) GetFileMode(LuaFileOpenMode luaFileO LuaFileOpenMode.Read => (FileMode.Open, FileAccess.Read), LuaFileOpenMode.Write => (FileMode.Create, FileAccess.Write), LuaFileOpenMode.Append => (FileMode.Append, FileAccess.Write), - LuaFileOpenMode.ReadWriteOpen => (FileMode.Open, FileAccess.ReadWrite), - LuaFileOpenMode.ReadWriteCreate => (FileMode.Truncate, FileAccess.ReadWrite), - LuaFileOpenMode.ReadAppend => (FileMode.Append, FileAccess.ReadWrite), + LuaFileOpenMode.ReadUpdate => (FileMode.Open, FileAccess.ReadWrite), + LuaFileOpenMode.WriteUpdate => (FileMode.Truncate, FileAccess.ReadWrite), + LuaFileOpenMode.AppendUpdate => (FileMode.Append, FileAccess.ReadWrite), _ => throw new ArgumentOutOfRangeException(nameof(luaFileOpenMode), luaFileOpenMode, null) }; } @@ -22,12 +22,12 @@ public bool IsReadable(string path) } - ILuaStream Open(string path, LuaFileOpenMode openMode, LuaFileContentType contentType) + public ValueTask Open(string path, LuaFileOpenMode openMode, CancellationToken cancellationToken) { var (mode, access) = GetFileMode(openMode); Stream stream; - if (openMode == LuaFileOpenMode.ReadAppend) + if (openMode == LuaFileOpenMode.AppendUpdate) { stream = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete); } @@ -36,32 +36,18 @@ ILuaStream Open(string path, LuaFileOpenMode openMode, LuaFileContentType conten stream = File.Open(path, mode, access, FileShare.ReadWrite | FileShare.Delete); } - var fileMode = LuaFileModeExtensions.GetMode(openMode, contentType); - ILuaStream wrapper = contentType == LuaFileContentType.Binary - ? new BinaryLuaStream(fileMode, stream) - : new TextLuaStream(fileMode, stream); + ILuaStream wrapper = + new TextLuaStream(openMode, stream); - if (openMode == LuaFileOpenMode.ReadAppend) + if (openMode == LuaFileOpenMode.AppendUpdate) { wrapper.Seek(0, SeekOrigin.End); } - return wrapper; + return new(wrapper); } - public ValueTask Open(string path, LuaFileMode mode, CancellationToken cancellationToken) - { - if (mode is LuaFileMode.Load) - { - return new ( new LuaChunkStream(File.OpenRead(path))); - } - - var openMode = mode.GetOpenMode(); - var contentType = mode.GetContentType(); - return new(Open(path, openMode, contentType)); - } - - public ValueTask Rename(string oldName, string newName,CancellationToken cancellationToken) + public ValueTask Rename(string oldName, string newName, CancellationToken cancellationToken) { if (oldName == newName) return default; if (File.Exists(newName)) File.Delete(newName); @@ -70,7 +56,7 @@ public ValueTask Rename(string oldName, string newName,CancellationToken cancell return default; } - public ValueTask Remove(string path,CancellationToken cancellationToken) + public ValueTask Remove(string path, CancellationToken cancellationToken) { File.Delete(path); return default; @@ -86,7 +72,7 @@ public string GetTempFileName() public ValueTask OpenTempFileStream(CancellationToken cancellationToken) { - return new( new TextLuaStream(LuaFileMode.ReadUpdateText, File.Open(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite))); + return new(new TextLuaStream(LuaFileOpenMode.WriteUpdate, File.Open(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite))); } } } \ No newline at end of file diff --git a/src/Lua/IO/ILuaFileSystem.cs b/src/Lua/IO/ILuaFileSystem.cs index ccfb954e..3950f9f0 100644 --- a/src/Lua/IO/ILuaFileSystem.cs +++ b/src/Lua/IO/ILuaFileSystem.cs @@ -3,7 +3,7 @@ public interface ILuaFileSystem { public bool IsReadable(string path); - public ValueTask Open(string path, LuaFileMode mode, CancellationToken cancellationToken); + public ValueTask Open(string path, LuaFileOpenMode mode, CancellationToken cancellationToken); public ValueTask Rename(string oldName, string newName, CancellationToken cancellationToken); public ValueTask Remove(string path, CancellationToken cancellationToken); public string DirectorySeparator => "/"; diff --git a/src/Lua/IO/ILuaStream.cs b/src/Lua/IO/ILuaStream.cs index 20b49fc2..07186caf 100644 --- a/src/Lua/IO/ILuaStream.cs +++ b/src/Lua/IO/ILuaStream.cs @@ -2,9 +2,9 @@ { public interface ILuaStream : IDisposable { - public LuaFileMode Mode { get; } + public LuaFileOpenMode Mode { get; } - public ValueTask ReadAllAsync(CancellationToken cancellationToken) + public ValueTask ReadAllAsync(CancellationToken cancellationToken) { Mode.ThrowIfNotReadable(); @@ -16,7 +16,6 @@ public ValueTask ReadAllAsync(CancellationToken cancellationToke { Mode.ThrowIfNotReadable(); - Mode.ThrowIfNotText(); // Default implementation using ReadStringAsync throw new NotImplementedException($"ReadLineAsync must be implemented by {GetType().Name}"); @@ -26,26 +25,19 @@ public ValueTask ReadAllAsync(CancellationToken cancellationToke { Mode.ThrowIfNotReadable(); - Mode.ThrowIfNotText(); // Default implementation using ReadAllAsync throw new NotImplementedException($"ReadStringAsync must be implemented by {GetType().Name}"); } - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) + public ValueTask WriteAsync(ReadOnlyMemory content, CancellationToken cancellationToken) { Mode.ThrowIfNotWritable(); - if (content.Type == LuaFileContentType.Binary) - { - Mode.ThrowIfNotBinary(); - } - else - { - Mode.ThrowIfNotText(); - } throw new NotImplementedException($"WriteAsync must be implemented by {GetType().Name}"); } + public ValueTask WriteAsync(string content, CancellationToken cancellationToken) => WriteAsync(content.AsMemory(), cancellationToken); + public ValueTask FlushAsync(CancellationToken cancellationToken) { // Default implementation does nothing (no buffering) @@ -62,24 +54,19 @@ public long Seek(long offset, SeekOrigin origin) throw new NotSupportedException($"Seek is not supported by {GetType().Name}"); } - public static ILuaStream CreateStreamWrapper(Stream stream, LuaFileOpenMode openMode, LuaFileContentType contentType = LuaFileContentType.Text) + public static ILuaStream CreateStreamWrapper(Stream stream, LuaFileOpenMode openMode) { - var mode = LuaFileModeExtensions.GetMode(openMode, contentType); - return contentType == LuaFileContentType.Binary - ? new BinaryLuaStream(mode, stream) - : new TextLuaStream(mode, stream); + return new TextLuaStream(openMode, stream); } - - public static ILuaStream CreateFromFileContent(LuaFileContent content) + + public static ILuaStream CreateFromFileString(string content) + { + return new StringStream(content); + } + + public static ILuaStream CreateFromMemory(ReadOnlyMemory content) { - if (content.Type == LuaFileContentType.Binary) - { - return new ByteMemoryStream(content.ReadBytes() ); - } - else - { - return new StringStream(content.ReadString()); - } + return new CharMemoryStream(content); } diff --git a/src/Lua/IO/LuaChunkStream.cs b/src/Lua/IO/LuaChunkStream.cs deleted file mode 100644 index c3559279..00000000 --- a/src/Lua/IO/LuaChunkStream.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Lua.CodeAnalysis.Compilation; -using System.Buffers; -using System.Text; - -namespace Lua.IO; - -internal sealed class LuaChunkStream : ILuaStream -{ - public LuaChunkStream(Stream stream) - { - using (stream) - { - var length = stream.Length; - if (length > int.MaxValue) - throw new ArgumentOutOfRangeException(nameof(stream), "Stream length exceeds maximum size for Lua chunk."); - - bytesToReturnToPool = ArrayPool.Shared.Rent((int)length); - try - { - var count = stream.Read(bytesToReturnToPool.AsSpan()); - bytes = bytesToReturnToPool.AsMemory(0, count); - } - catch (Exception) - { - ArrayPool.Shared.Return(bytesToReturnToPool); - } - } - } - - public LuaChunkStream(ReadOnlyMemory bytes, IDisposable? disposable = null) - { - this.bytes = bytes; - this.disposable = disposable; - } - - byte[]? bytesToReturnToPool; - char[]? charsToReturnToPool; - private readonly ReadOnlyMemory bytes; - private IDisposable? disposable; - - public void Dispose() - { - if (bytesToReturnToPool is not null) - { - ArrayPool.Shared.Return(bytesToReturnToPool); - bytesToReturnToPool = null!; - } - - if (charsToReturnToPool is not null) - { - ArrayPool.Shared.Return(charsToReturnToPool); - charsToReturnToPool = null!; - } - - disposable?.Dispose(); - disposable = null; - } - - public LuaFileMode Mode => LuaFileMode.Read | (bytes.Span.StartsWith(LuaCompiler.LuaByteCodeSignature) ? LuaFileMode.Binary : LuaFileMode.Text); - - public ValueTask ReadAllAsync(CancellationToken cancellationToken) - { - var span = bytes.Span; - if ((Mode & LuaFileMode.Binary) != 0) - { - return new(new LuaFileContent(bytes)); - } - else - { - var encoding = Encoding.UTF8; - var array = ArrayPool.Shared.Rent(encoding.GetMaxCharCount(span.Length)); - var charCount = encoding.GetChars(span, array); - charsToReturnToPool = array; - return new(new LuaFileContent(array.AsMemory(0, charCount))); - } - } - - public ValueTask ReadLineAsync(CancellationToken cancellationToken) - { - throw new NotSupportedException(); - } - - public ValueTask ReadStringAsync(int count, CancellationToken cancellationToken) - { - throw new NotSupportedException(); - } - - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) - { - throw new NotSupportedException(); - } - - public ValueTask FlushAsync(CancellationToken cancellationToken) - { - throw new NotSupportedException(); - } - - public void SetVBuf(LuaFileBufferingMode mode, int size) - { - throw new NotSupportedException(); - } - - public long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } -} \ No newline at end of file diff --git a/src/Lua/IO/LuaFileMode.cs b/src/Lua/IO/LuaFileMode.cs deleted file mode 100644 index 7d3f03b5..00000000 --- a/src/Lua/IO/LuaFileMode.cs +++ /dev/null @@ -1,201 +0,0 @@ -namespace Lua.IO; -public enum LuaFileContentTypeFlags -{ - None = 0, - Binary = 1 << 0, // b - Text = 1 << 1, // t (default if neither specified) -} -[Flags] -public enum LuaFileMode -{ - None = 0, - - // Access modes (mutually exclusive) - Read = 1 << 0, // r - Write = 1 << 1, // w - Append = 1 << 2, // a - Update = 1 << 3, // + - - // Content type flags - Binary = 1 << 4, // b - Text = 1 << 5, // t (default if neither specified) - - // Common combinations - ReadBinary = Read | Binary, // rb - WriteBinary = Write | Binary, // wb - AppendBinary = Append | Binary, // ab - ReadText = Read | Text, // r - WriteText = Write | Text, // w - AppendText = Append | Text, // a - - ReadUpdate = Read | Update, // r+ - WriteUpdate = Write | Update, // w+ - AppendUpdate = Append | Update, // a+ - ReadUpdateText = Read | Update | Text, // r+ - WriteUpdateText = Write | Update | Text, // w+ - AppendUpdateText = Append | Update | Text, // a+ - - ReadUpdateBinary = Read | Update | Binary, // r+b or rb+ - WriteUpdateBinary = Write | Update | Binary, // w+b or wb+ - AppendUpdateBinary = Append | Update | Binary, // a+b or ab+ - - /// - /// This is used for load files. bt mode. - /// - ReadBinaryOrText = Read | Binary | Text, //(default is text, but can be binary) - Load = ReadBinaryOrText, // Mode for loading files to compile Lua scripts -} - -public static class LuaFileModeExtensions -{ - public static LuaFileMode GetMode(LuaFileOpenMode openMode, LuaFileContentType type) - { - var isBinary = type == LuaFileContentType.Binary; - return openMode switch - { - LuaFileOpenMode.Read => isBinary ? LuaFileMode.ReadBinary : LuaFileMode.ReadText, - LuaFileOpenMode.Write => isBinary ? LuaFileMode.WriteBinary : LuaFileMode.WriteText, - LuaFileOpenMode.Append => isBinary ? LuaFileMode.AppendBinary : LuaFileMode.AppendText, - LuaFileOpenMode.ReadWriteOpen => isBinary ? LuaFileMode.ReadUpdateBinary : LuaFileMode.ReadUpdateText, - LuaFileOpenMode.ReadWriteCreate => isBinary ? LuaFileMode.WriteUpdateBinary : LuaFileMode.WriteUpdateText, - LuaFileOpenMode.ReadAppend => isBinary ? LuaFileMode.AppendUpdateBinary : LuaFileMode.AppendUpdateText, - _ => throw new ArgumentOutOfRangeException(nameof(openMode), openMode, "Invalid file open mode") - }; - } - - public static LuaFileOpenMode GetOpenMode(this LuaFileMode mode) - { - var hasUpdate = (mode & LuaFileMode.Update) != 0; - - if ((mode & LuaFileMode.Read) != 0) - return hasUpdate ? LuaFileOpenMode.ReadWriteOpen : LuaFileOpenMode.Read; - if ((mode & LuaFileMode.Write) != 0) - return hasUpdate ? LuaFileOpenMode.ReadWriteCreate : LuaFileOpenMode.Write; - if ((mode & LuaFileMode.Append) != 0) - return hasUpdate ? LuaFileOpenMode.ReadAppend : LuaFileOpenMode.Append; - - throw new ArgumentException("Invalid file open flags: no access mode specified", nameof(mode)); - } - - public static LuaFileContentType GetContentType(this LuaFileMode mode) - { - // If binary flag is set, it's binary mode - if ((mode & LuaFileMode.Binary) != 0) - return LuaFileContentType.Binary; - - // Otherwise it's text mode (even if Text flag is not explicitly set) - return LuaFileContentType.Text; - } - - public static LuaFileMode ParseModeString(string mode) - { - var flags = LuaFileMode.None; - - // Parse base mode - if (mode.Contains("+")) - flags |= LuaFileMode.Update; - if (mode.Contains("r")) - flags |= LuaFileMode.Read; - if (mode.Contains("w")) - flags |= LuaFileMode.Write; - if (mode.Contains("a")) - flags |= LuaFileMode.Append; - - // Parse content type - if (mode.Contains('b')) - flags |= LuaFileMode.Binary; - else - flags |= LuaFileMode.Text; - // If neither 'b' nor 't' is specified, default is text (handled by GetContentType) - - return flags; - } - - public static bool IsValid(this LuaFileMode mode) - { - var modeCount = 0; - if ((mode & LuaFileMode.Read) != 0) modeCount++; - if ((mode & LuaFileMode.Write) != 0) modeCount++; - if ((mode & LuaFileMode.Append) != 0) modeCount++; - if (modeCount != 1) - { - return false; // Must have exactly one access mode - } - - var typeCount = 0; - if ((mode & LuaFileMode.Binary) != 0) typeCount++; - if ((mode & LuaFileMode.Text) != 0) typeCount++; - if (typeCount < 1) - { - return false; - } - - return true; - } - - public static bool IsAppend(this LuaFileMode mode) - { - return (mode & LuaFileMode.Append) != 0; - } - - public static bool CanRead(this LuaFileMode mode) - { - return (mode & LuaFileMode.Read) != 0; - } - - public static bool CanWrite(this LuaFileMode mode) - { - return (mode & LuaFileMode.Write) != 0 || (mode & LuaFileMode.Append) != 0; - } - - public static bool IsBinary(this LuaFileMode mode) - { - return (mode & LuaFileMode.Binary) != 0; - } - - public static bool IsText(this LuaFileMode mode) - { - return (mode & LuaFileMode.Text) != 0; - } - - - public static void ThrowIfNotValid(this LuaFileMode mode) - { - if (!mode.IsValid()) - { - throw new ArgumentException("Invalid file mode flags", nameof(mode)); - } - } - - public static void ThrowIfNotReadable(this LuaFileMode mode) - { - if (!mode.CanRead()) - { - throw new InvalidOperationException("This operation is only valid for readable streams."); - } - } - - public static void ThrowIfNotWritable(this LuaFileMode mode) - { - if (!mode.CanWrite()) - { - throw new InvalidOperationException("This operation is only valid for writable streams."); - } - } - - public static void ThrowIfNotText(this LuaFileMode mode) - { - if (!mode.IsText()) - { - throw new InvalidOperationException("This operation is only valid for text streams."); - } - } - - public static void ThrowIfNotBinary(this LuaFileMode mode) - { - if (!mode.IsBinary()) - { - throw new InvalidOperationException("This operation is only valid for binary streams."); - } - } -} \ No newline at end of file diff --git a/src/Lua/IO/LuaFileOpenMode.cs b/src/Lua/IO/LuaFileOpenMode.cs index 719c0c88..0001b1e2 100644 --- a/src/Lua/IO/LuaFileOpenMode.cs +++ b/src/Lua/IO/LuaFileOpenMode.cs @@ -1,35 +1,100 @@ -namespace Lua.IO +namespace Lua.IO; + +public enum LuaFileOpenMode +{ + /// + /// r + /// + Read, + + /// + /// w + /// + Write, + + /// + /// a + /// + Append, + + /// + /// r+ + /// + ReadUpdate, + + /// + /// w+ + /// + WriteUpdate, + + /// + /// a+ + /// + AppendUpdate, +} + +public static class LuaFileOpenModeExtensions { - public enum LuaFileOpenMode + public static bool CanRead(this LuaFileOpenMode mode) => mode is LuaFileOpenMode.Read + or LuaFileOpenMode.ReadUpdate + or LuaFileOpenMode.WriteUpdate + or LuaFileOpenMode.AppendUpdate; + + public static bool CanWrite(this LuaFileOpenMode mode) => mode is LuaFileOpenMode.Write + or LuaFileOpenMode.ReadUpdate + or LuaFileOpenMode.WriteUpdate + or LuaFileOpenMode.Append + or LuaFileOpenMode.AppendUpdate; + + public static LuaFileOpenMode ParseModeFromString(string mode) + { + return mode switch + { + "r" => LuaFileOpenMode.Read, + "rb" => LuaFileOpenMode.Read, + "w" => LuaFileOpenMode.Write, + "wb" => LuaFileOpenMode.Write, + "a" => LuaFileOpenMode.Append, + "ab" => LuaFileOpenMode.Append, + "r+" => LuaFileOpenMode.ReadUpdate, + "r+b" => LuaFileOpenMode.ReadUpdate, + "w+" => LuaFileOpenMode.WriteUpdate, + "w+b" => LuaFileOpenMode.WriteUpdate, + "a+" => LuaFileOpenMode.AppendUpdate, + "a+b" => LuaFileOpenMode.AppendUpdate, + _ => 0 + }; + } + + + public static bool IsValid(this LuaFileOpenMode mode) + { + return mode is LuaFileOpenMode.Read + or LuaFileOpenMode.Write + or LuaFileOpenMode.Append + or LuaFileOpenMode.ReadUpdate + or LuaFileOpenMode.WriteUpdate + or LuaFileOpenMode.AppendUpdate; + } + + public static bool IsAppend(this LuaFileOpenMode mode) + { + return mode is LuaFileOpenMode.Append or LuaFileOpenMode.AppendUpdate or LuaFileOpenMode.WriteUpdate; + } + + public static void ThrowIfNotReadable(this LuaFileOpenMode mode) + { + if (!mode.CanRead()) + { + throw new IOException($"Cannot read from a file opened with mode {mode}"); + } + } + + public static void ThrowIfNotWritable(this LuaFileOpenMode mode) { - /// - /// r - /// - Read, - - /// - /// w - /// - Write, - - /// - /// a - /// - Append, - - /// - /// r+ - /// - ReadWriteOpen, - - /// - /// w+ - /// - ReadWriteCreate, - - /// - /// a+ - /// - ReadAppend, + if (!mode.CanWrite()) + { + throw new IOException($"Cannot write to a file opened with mode {mode}"); + } } } \ No newline at end of file diff --git a/src/Lua/IO/MemoryStreams.cs b/src/Lua/IO/MemoryStreams.cs index 9961ce33..6503cfaa 100644 --- a/src/Lua/IO/MemoryStreams.cs +++ b/src/Lua/IO/MemoryStreams.cs @@ -1,113 +1,28 @@ namespace Lua.IO; -public sealed class ByteMemoryStream(ReadOnlyMemory bytes) : ILuaStream -{ - private int position; - private bool disposed; - - public ByteMemoryStream(byte[] bytes) : this(bytes.AsMemory()) - { - if (bytes is null) - throw new ArgumentNullException(nameof(bytes)); - } - - public LuaFileMode Mode => LuaFileMode.ReadBinary; - - public void Dispose() - { - disposed = true; - } - - public ValueTask ReadAllAsync(CancellationToken cancellationToken) - { - ThrowIfDisposed(); - cancellationToken.ThrowIfCancellationRequested(); - - var remaining = bytes.Slice(position); - position = bytes.Length; - return new(new LuaFileContent(remaining)); - } - - public ValueTask ReadLineAsync(CancellationToken cancellationToken) - { - ThrowIfDisposed(); - cancellationToken.ThrowIfCancellationRequested(); - - throw new InvalidOperationException("Cannot read lines string from a binary stream."); - } - - public ValueTask ReadStringAsync(int count, CancellationToken cancellationToken) - { - ThrowIfDisposed(); - cancellationToken.ThrowIfCancellationRequested(); - throw new InvalidOperationException("Cannot read lines string from a binary stream."); - } - - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) - { - throw new NotSupportedException("Stream is read-only"); - } - - public ValueTask FlushAsync(CancellationToken cancellationToken) - { - ThrowIfDisposed(); - return default; - } - - public void SetVBuf(LuaFileBufferingMode mode, int size) - { - // No-op for memory streams - } - - public long Seek(long offset, SeekOrigin origin) - { - ThrowIfDisposed(); - - long newPosition = origin switch - { - SeekOrigin.Begin => offset, - SeekOrigin.Current => position + offset, - SeekOrigin.End => bytes.Length + offset, - _ => throw new ArgumentException("Invalid seek origin", nameof(origin)) - }; - - if (newPosition < 0 || newPosition > bytes.Length) - throw new ArgumentOutOfRangeException(nameof(offset), "Seek position is out of range"); - - position = (int)newPosition; - return position; - } - - private void ThrowIfDisposed() - { - if (disposed) - throw new ObjectDisposedException(nameof(ByteMemoryStream)); - } -} - public class CharMemoryStream(ReadOnlyMemory contents) : ILuaStream { protected int Position; private bool disposed; - public LuaFileMode Mode => LuaFileMode.ReadText; + public LuaFileOpenMode Mode => LuaFileOpenMode.Read; public void Dispose() { disposed = true; } - public virtual ValueTask ReadAllAsync(CancellationToken cancellationToken) + public virtual ValueTask ReadAllAsync(CancellationToken cancellationToken) { ThrowIfDisposed(); cancellationToken.ThrowIfCancellationRequested(); if (Position >= contents.Length) - return new(new LuaFileContent("")); + return new(""); var remaining = contents[Position..]; Position = contents.Length; - return new(new LuaFileContent(remaining)); + return new(remaining.ToString()); } public ValueTask ReadLineAsync(CancellationToken cancellationToken) @@ -160,9 +75,9 @@ public virtual ValueTask ReadAllAsync(CancellationToken cancella return new(result); } - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) + public ValueTask WriteAsync(ReadOnlyMemory content, CancellationToken cancellationToken) { - throw new NotSupportedException("Stream is read-only"); + throw new IOException("Stream is read-only"); } public ValueTask FlushAsync(CancellationToken cancellationToken) @@ -204,12 +119,12 @@ protected void ThrowIfDisposed() public sealed class StringStream(string content) : CharMemoryStream(content.AsMemory()) { - public override ValueTask ReadAllAsync(CancellationToken cancellationToken) + public override ValueTask ReadAllAsync(CancellationToken cancellationToken) { ThrowIfDisposed(); cancellationToken.ThrowIfCancellationRequested(); if (Position == 0) - return new(new LuaFileContent(content)); + return new((content)); return base.ReadAllAsync(cancellationToken); } } \ No newline at end of file diff --git a/src/Lua/IO/StandardIOStream.cs b/src/Lua/IO/StandardIOStream.cs index 99ce60e8..5700a794 100644 --- a/src/Lua/IO/StandardIOStream.cs +++ b/src/Lua/IO/StandardIOStream.cs @@ -5,9 +5,9 @@ /// internal sealed class StandardIOStream(ILuaStream innerStream) : ILuaStream { - public LuaFileMode Mode => innerStream.Mode; + public LuaFileOpenMode Mode => innerStream.Mode; - public ValueTask ReadAllAsync(CancellationToken cancellationToken) + public ValueTask ReadAllAsync(CancellationToken cancellationToken) => innerStream.ReadAllAsync(cancellationToken); public ValueTask ReadLineAsync(CancellationToken cancellationToken) @@ -16,7 +16,7 @@ public ValueTask ReadAllAsync(CancellationToken cancellationToke public ValueTask ReadStringAsync(int count, CancellationToken cancellationToken) => innerStream.ReadStringAsync(count, cancellationToken); - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) + public ValueTask WriteAsync(ReadOnlyMemory content, CancellationToken cancellationToken) => innerStream.WriteAsync(content, cancellationToken); public ValueTask FlushAsync(CancellationToken cancellationToken) diff --git a/src/Lua/IO/TextLuaStream.cs b/src/Lua/IO/TextLuaStream.cs index b9a55caf..9b3d606b 100644 --- a/src/Lua/IO/TextLuaStream.cs +++ b/src/Lua/IO/TextLuaStream.cs @@ -3,13 +3,13 @@ namespace Lua.IO; -internal sealed class TextLuaStream(LuaFileMode mode, Stream innerStream) : ILuaStream +internal sealed class TextLuaStream(LuaFileOpenMode mode, Stream innerStream) : ILuaStream { Utf8Reader? reader; ulong flushSize = ulong.MaxValue; ulong nextFlushSize = ulong.MaxValue; - public LuaFileMode Mode => mode; + public LuaFileOpenMode Mode => mode; public ValueTask ReadLineAsync(CancellationToken cancellationToken) { @@ -18,12 +18,12 @@ internal sealed class TextLuaStream(LuaFileMode mode, Stream innerStream) : ILua return new(reader.ReadLine(innerStream)); } - public ValueTask ReadAllAsync(CancellationToken cancellationToken) + public ValueTask ReadAllAsync(CancellationToken cancellationToken) { mode.ThrowIfNotReadable(); reader ??= new(); var text = reader.ReadToEnd(innerStream); - return new(new LuaFileContent(text)); + return new(text); } public ValueTask ReadStringAsync(int count, CancellationToken cancellationToken) @@ -33,11 +33,6 @@ public ValueTask ReadAllAsync(CancellationToken cancellationToke return new(reader.Read(innerStream, count)); } - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) - { - mode.ThrowIfNotWritable(); - return WriteAsync(content.ReadText(), cancellationToken); - } public ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken) { diff --git a/src/Lua/Loaders/FileModuleLoader.cs b/src/Lua/Loaders/FileModuleLoader.cs deleted file mode 100644 index 5962a477..00000000 --- a/src/Lua/Loaders/FileModuleLoader.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Lua.Loaders; - -public sealed class FileModuleLoader : ILuaModuleLoader -{ - public static readonly FileModuleLoader Instance = new(); - - public bool Exists(string moduleName) - { - return File.Exists(moduleName); - } - - public async ValueTask LoadAsync(string moduleName, CancellationToken cancellationToken = default) - { - var path = moduleName; - if (!Path.HasExtension(path)) path += ".lua"; - var text = await File.ReadAllBytesAsync(path, cancellationToken); - return new LuaModule(moduleName, text); - } -} \ No newline at end of file diff --git a/src/Lua/LuaFileContent.cs b/src/Lua/LuaFileContent.cs deleted file mode 100644 index 1888a2c9..00000000 --- a/src/Lua/LuaFileContent.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Lua.IO; - -namespace Lua; - -public enum LuaFileContentType -{ - Text, - Binary -} - -public readonly struct LuaFileContent -{ - public LuaFileContentType Type => type; - - readonly LuaFileContentType type; - readonly object referenceValue; - - public LuaFileContent(ReadOnlyMemory memory) - { - type = LuaFileContentType.Text; - referenceValue = memory; - } - - public LuaFileContent(ReadOnlyMemory memory) - { - type = LuaFileContentType.Binary; - referenceValue = new BinaryData(memory); - } - - public LuaFileContent(IBinaryData data) - { - type = LuaFileContentType.Binary; - referenceValue = data ?? throw new ArgumentNullException(nameof(data), "Binary data cannot be null."); - } - - public LuaFileContent(string text) - { - type = LuaFileContentType.Text; - referenceValue = text ?? throw new ArgumentNullException(nameof(text), "Text cannot be null."); - } - - public ReadOnlyMemory ReadText() - { - if (type != LuaFileContentType.Text) throw new InvalidOperationException("Cannot read text from a LuaFileContent of type Bytes."); - if (referenceValue is string str) return str.AsMemory(); - return ((ReadOnlyMemory)referenceValue); - } - - public string ReadString() - { - if (type != LuaFileContentType.Text) throw new InvalidOperationException("Cannot read text from a LuaFileContent of type Bytes."); - if (referenceValue is string str) return str; - return ((ReadOnlyMemory)referenceValue).ToString(); - } - - public ReadOnlyMemory ReadBytes() - { - if (type != LuaFileContentType.Binary) throw new InvalidOperationException("Cannot read bytes from a LuaFileContent of type Text."); - return ((IBinaryData)referenceValue).Memory; - } - - public LuaValue ToLuaValue() - { - if (type == LuaFileContentType.Binary) - { - return LuaValue.FromObject(referenceValue); - } - else - { - return ReadString(); - } - } -} \ No newline at end of file diff --git a/src/Lua/LuaModule.cs b/src/Lua/LuaModule.cs index 579518eb..6ea5b7fa 100644 --- a/src/Lua/LuaModule.cs +++ b/src/Lua/LuaModule.cs @@ -1,77 +1,54 @@ using System.Buffers; +using System.Runtime.CompilerServices; namespace Lua; public enum LuaModuleType { Text, - Bytes + Bytes, } -public readonly struct LuaModule : IDisposable +public readonly struct LuaModule { public string Name => name; public LuaModuleType Type => type; readonly string name; readonly LuaModuleType type; - readonly object referenceValue; + readonly ReadOnlyMemory text; + readonly ReadOnlyMemory bytes; - public LuaModule(string name, string text) + public LuaModule(string name, ReadOnlyMemory text) { this.name = name; type = LuaModuleType.Text; - referenceValue = text; + this.text = text; } - public LuaModule(string name, byte[] bytes) + public LuaModule(string name, ReadOnlyMemory bytes) { this.name = name; type = LuaModuleType.Bytes; - referenceValue = bytes; + this.bytes = bytes; } - public LuaModule(string name, IMemoryOwner bytes) - { - this.name = name; - type = LuaModuleType.Text; - referenceValue = bytes; - } + public LuaModule(string name, string text) : this(name, text.AsMemory()) { } - public LuaModule(string name, IMemoryOwner bytes) + public LuaModule(string name, byte[] bytes) + : this(name, new ReadOnlyMemory(bytes)) { - this.name = name; - type = LuaModuleType.Bytes; - referenceValue = bytes; } public ReadOnlySpan ReadText() { if (type != LuaModuleType.Text) throw new Exception(); // TODO: add message - if (referenceValue is IMemoryOwner mem) - { - return mem.Memory.Span; - } - - return ((string)referenceValue); + return text.Span; } public ReadOnlySpan ReadBytes() { if (type != LuaModuleType.Bytes) throw new Exception(); // TODO: add message - if (referenceValue is IMemoryOwner mem) - { - return mem.Memory.Span; - } - - return (byte[])referenceValue; - } - - public void Dispose() - { - if (referenceValue is IDisposable memoryOwner) - { - memoryOwner.Dispose(); - } + return bytes.Span; } } \ No newline at end of file diff --git a/src/Lua/LuaState.cs b/src/Lua/LuaState.cs index 8826ebcd..b624bff8 100644 --- a/src/Lua/LuaState.cs +++ b/src/Lua/LuaState.cs @@ -40,8 +40,7 @@ public sealed class LuaState public LuaPlatform Platform { get; } - public ILuaModuleLoader ModuleLoader { get; set; } = FileModuleLoader.Instance; - + public ILuaModuleLoader? ModuleLoader { get; set; } public ILuaFileSystem FileSystem => Platform.FileSystem ?? throw new InvalidOperationException("FileSystem is not set. Please set it before access."); public ILuaOsEnvironment OsEnvironment => Platform.OsEnvironment ?? throw new InvalidOperationException("OperatingSystem is not set. Please set it before access."); diff --git a/src/Lua/LuaStateExtensions.cs b/src/Lua/LuaStateExtensions.cs index df19444d..4cdad9ee 100644 --- a/src/Lua/LuaStateExtensions.cs +++ b/src/Lua/LuaStateExtensions.cs @@ -38,30 +38,9 @@ public static ValueTask DoFileAsync(this LuaState state, string path public static async ValueTask LoadFileAsync(this LuaState state, string fileName, string mode, LuaTable? environment, CancellationToken cancellationToken) { var name = "@" + fileName; - LuaClosure closure; - - var openFlags = LuaFileMode.Read; - if (mode.Contains('b')) - { - openFlags |= LuaFileMode.Binary; - } - - if (mode.Contains('t')) - { - openFlags |= LuaFileMode.Text; - } - - using var stream = await state.FileSystem.Open(fileName, openFlags, cancellationToken); - var content = await stream.ReadAllAsync(cancellationToken); - - if (content.Type == LuaFileContentType.Binary) - { - closure = state.Load(content.ReadBytes().Span, name, mode, environment); - } - else - { - closure = state.Load(content.ReadText().Span, name, environment); - } + using var stream = await state.FileSystem.Open(fileName, LuaFileOpenMode.Read, cancellationToken); + var source = await stream.ReadAllAsync(cancellationToken); + LuaClosure closure = state.Load(source, name, environment); return closure; } diff --git a/src/Lua/Standard/BasicLibrary.cs b/src/Lua/Standard/BasicLibrary.cs index b1749fa7..1379ef48 100644 --- a/src/Lua/Standard/BasicLibrary.cs +++ b/src/Lua/Standard/BasicLibrary.cs @@ -200,10 +200,6 @@ public ValueTask Load(LuaFunctionExecutionContext context, CancellationToke // TODO: throw new NotImplementedException(); } - else if (arg0.TryRead(out var binaryData)) - { - return new(context.Return(context.State.Load(binaryData.Memory.Span, name, "bt", arg3))); - } else { LuaRuntimeException.BadArgument(context.Thread, 1, ["string", "function,binary data"], arg0.TypeToString()); @@ -291,18 +287,18 @@ public async ValueTask PCall(LuaFunctionExecutionContext context, Cancellat public async ValueTask Print(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { var stdout = context.State.StandardIO.Output; - + for (int i = 0; i < context.ArgumentCount; i++) { await context.Arguments[i].CallToStringAsync(context, cancellationToken); - await stdout.WriteAsync(new (context.Thread.Stack.Pop().Read()), cancellationToken); + await stdout.WriteAsync(context.Thread.Stack.Pop().Read(), cancellationToken); if (i < context.ArgumentCount - 1) { - await stdout.WriteAsync( new("\t"), cancellationToken); + await stdout.WriteAsync("\t", cancellationToken); } } - await stdout.WriteAsync(new("\n"), cancellationToken); + await stdout.WriteAsync("\n", cancellationToken); await stdout.FlushAsync(cancellationToken); return context.Return(); } diff --git a/src/Lua/Standard/FileHandle.cs b/src/Lua/Standard/FileHandle.cs index 84e8d363..71e403a6 100644 --- a/src/Lua/Standard/FileHandle.cs +++ b/src/Lua/Standard/FileHandle.cs @@ -46,7 +46,7 @@ static FileHandle() fileHandleMetatable[Metamethods.Index] = IndexMetamethod; } - public FileHandle(Stream stream, LuaFileOpenMode mode, LuaFileContentType type = LuaFileContentType.Text) : this(ILuaStream.CreateStreamWrapper(stream, mode, type)) { } + public FileHandle(Stream stream, LuaFileOpenMode mode) : this(ILuaStream.CreateStreamWrapper(stream, mode)) { } public FileHandle(ILuaStream stream) { @@ -58,7 +58,7 @@ public FileHandle(ILuaStream stream) return stream.ReadLineAsync(cancellationToken); } - public ValueTask ReadToEndAsync(CancellationToken cancellationToken) + public ValueTask ReadToEndAsync(CancellationToken cancellationToken) { return stream.ReadAllAsync(cancellationToken); } @@ -68,25 +68,17 @@ public ValueTask ReadToEndAsync(CancellationToken cancellationTo return stream.ReadStringAsync(count, cancellationToken); } - public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) - { - return stream.WriteAsync(content, cancellationToken); - } public ValueTask WriteAsync(string content, CancellationToken cancellationToken) { - return stream.WriteAsync(new(content), cancellationToken); + return stream.WriteAsync(content.AsMemory(), cancellationToken); } public ValueTask WriteAsync(ReadOnlyMemory content, CancellationToken cancellationToken) { - return stream.WriteAsync(new (content), cancellationToken); + return stream.WriteAsync(content, cancellationToken); } - public ValueTask WriteAsync(IBinaryData content, CancellationToken cancellationToken) - { - return stream.WriteAsync(new(content), cancellationToken); - } public long Seek(string whence, long offset) => whence switch @@ -148,7 +140,7 @@ public void Close() } catch (IOException ex) { - return (context.Return(LuaValue.Nil, ex.Message, ex.HResult)); + return context.Return(LuaValue.Nil, ex.Message, ex.HResult); } }); diff --git a/src/Lua/Standard/IOLibrary.cs b/src/Lua/Standard/IOLibrary.cs index e0abd42f..7e9ed9ea 100644 --- a/src/Lua/Standard/IOLibrary.cs +++ b/src/Lua/Standard/IOLibrary.cs @@ -13,16 +13,16 @@ public IOLibrary() var libraryName = "io"; Functions = [ - new(libraryName,"close", Close), - new(libraryName,"flush", Flush), - new(libraryName,"input", Input), - new(libraryName,"lines", Lines), - new(libraryName,"open", Open), - new(libraryName,"output", Output), - new(libraryName,"read", Read), - new(libraryName,"type", Type), - new(libraryName,"write", Write), - new(libraryName,"tmpfile", TmpFile), + new(libraryName, "close", Close), + new(libraryName, "flush", Flush), + new(libraryName, "input", Input), + new(libraryName, "lines", Lines), + new(libraryName, "open", Open), + new(libraryName, "output", Output), + new(libraryName, "read", Read), + new(libraryName, "type", Type), + new(libraryName, "write", Write), + new(libraryName, "tmpfile", TmpFile), ]; } @@ -77,7 +77,7 @@ public async ValueTask Input(LuaFunctionExecutionContext context, Cancellat } else { - var stream =await context.State.FileSystem.Open(arg.ToString(), LuaFileMode.ReadUpdateText, cancellationToken); + var stream = await context.State.FileSystem.Open(arg.ToString(), LuaFileOpenMode.AppendUpdate, cancellationToken); var handle = new FileHandle(stream); registry["_IO_input"] = new(handle); return context.Return(new LuaValue(handle)); @@ -108,7 +108,7 @@ public async ValueTask Lines(LuaFunctionExecutionContext context, Cancellat var stack = context.Thread.Stack; context.Return(); - await IOHelper.Open(context.Thread, fileName, "r", true,cancellationToken); + await IOHelper.Open(context.Thread, fileName, "r", true, cancellationToken); var file = stack.Get(context.ReturnFrameBase).Read(); var upValues = new LuaValue[context.Arguments.Length]; @@ -168,7 +168,7 @@ public async ValueTask Output(LuaFunctionExecutionContext context, Cancella } else { - var stream = await context.State.FileSystem.Open(arg.ToString(), LuaFileMode.WriteUpdateText, cancellationToken); + var stream = await context.State.FileSystem.Open(arg.ToString(), LuaFileOpenMode.WriteUpdate, cancellationToken); var handle = new FileHandle(stream); io["_IO_output"] = new(handle); return context.Return(new LuaValue(handle)); @@ -208,6 +208,6 @@ public async ValueTask Write(LuaFunctionExecutionContext context, Cancellat public async ValueTask TmpFile(LuaFunctionExecutionContext context, CancellationToken cancellationToken) { - return context.Return(LuaValue.FromUserData(new FileHandle(await context.State.FileSystem.OpenTempFileStream( cancellationToken)))); + return context.Return(LuaValue.FromUserData(new FileHandle(await context.State.FileSystem.OpenTempFileStream(cancellationToken)))); } } \ No newline at end of file diff --git a/src/Lua/Standard/Internal/IOHelper.cs b/src/Lua/Standard/Internal/IOHelper.cs index 50de9905..a6d79db7 100644 --- a/src/Lua/Standard/Internal/IOHelper.cs +++ b/src/Lua/Standard/Internal/IOHelper.cs @@ -6,13 +6,13 @@ namespace Lua.Standard.Internal; internal static class IOHelper { - public static async ValueTask Open(LuaThread thread, string fileName, string mode, bool throwError,CancellationToken cancellationToken) + public static async ValueTask Open(LuaThread thread, string fileName, string mode, bool throwError, CancellationToken cancellationToken) { - var fileMode = LuaFileModeExtensions.ParseModeString(mode); + var fileMode = LuaFileOpenModeExtensions.ParseModeFromString(mode); if (!fileMode.IsValid()) throw new LuaRuntimeException(thread, "bad argument #2 to 'open' (invalid mode)"); try { - var stream =await thread.State.FileSystem.Open(fileName, fileMode,cancellationToken); + var stream = await thread.State.FileSystem.Open(fileName, fileMode, cancellationToken); thread.Stack.Push(new LuaValue(new FileHandle(stream))); return 1; @@ -49,11 +49,7 @@ public static async ValueTask WriteAsync(FileHandle file, string name, LuaF using var fileBuffer = new PooledArray(64); var span = fileBuffer.AsSpan(); d.TryFormat(span, out var charsWritten); - await file.WriteAsync(fileBuffer.UnderlyingArray.AsMemory(0,charsWritten) , cancellationToken); - } - else if (arg.TryRead(out var binaryData)) - { - await file.WriteAsync( binaryData, cancellationToken); + await file.WriteAsync(fileBuffer.UnderlyingArray.AsMemory(0, charsWritten), cancellationToken); } else { @@ -103,7 +99,7 @@ public static async ValueTask ReadAsync(LuaThread thread, FileHandle file, throw new NotImplementedException(); case "*a": case "*all": - stack.Push((await file.ReadToEndAsync(cancellationToken)).ToLuaValue()); + stack.Push((await file.ReadToEndAsync(cancellationToken))); break; case "*l": case "*line": diff --git a/src/Lua/Standard/ModuleLibrary.cs b/src/Lua/Standard/ModuleLibrary.cs index 2a26ea64..215bc91c 100644 --- a/src/Lua/Standard/ModuleLibrary.cs +++ b/src/Lua/Standard/ModuleLibrary.cs @@ -24,7 +24,20 @@ public async ValueTask Require(LuaFunctionExecutionContext context, Cancell if (!loaded.TryGetValue(arg0, out var loadedTable)) { - var loader = await FindLoader(context.Access, arg0, cancellationToken); + LuaFunction loader; + var moduleLoader = context.State.ModuleLoader; + if (moduleLoader != null && moduleLoader.Exists(arg0)) + { + var module = await moduleLoader.LoadAsync(arg0, cancellationToken); + loader = module.Type == LuaModuleType.Bytes + ? context.State.Load(module.ReadBytes(), module.Name) + : context.State.Load(module.ReadText(), module.Name); + } + else + { + loader = await FindLoader(context.Access, arg0, cancellationToken); + } + await context.Access.RunAsync(loader, 0, context.ReturnFrameBase, cancellationToken); loadedTable = context.Thread.Stack.Get(context.ReturnFrameBase); loaded[arg0] = loadedTable; diff --git a/tests/Lua.Tests/AbstractFileTests.cs b/tests/Lua.Tests/AbstractFileTests.cs index f4757872..a357120c 100644 --- a/tests/Lua.Tests/AbstractFileTests.cs +++ b/tests/Lua.Tests/AbstractFileTests.cs @@ -9,14 +9,14 @@ public class AbstractFileTests { class ReadOnlyFileSystem(Dictionary dictionary) : NotImplementedExceptionFileSystemBase { - public override ValueTask Open(string path, LuaFileMode mode,CancellationToken cancellationToken) + public override ValueTask Open(string path, LuaFileOpenMode mode,CancellationToken cancellationToken) { if (!dictionary.TryGetValue(path, out var value)) { throw new FileNotFoundException($"File {path} not found"); } - if (mode != LuaFileMode.ReadText) + if (mode != LuaFileOpenMode.Read) throw new IOException($"File {path} not opened in read mode"); return new (new ReadOnlyCharMemoryLuaIOStream(value.AsMemory())); } diff --git a/tests/Lua.Tests/Helpers/CharMemoryStream.cs b/tests/Lua.Tests/Helpers/CharMemoryStream.cs index 79725f9e..acabac77 100644 --- a/tests/Lua.Tests/Helpers/CharMemoryStream.cs +++ b/tests/Lua.Tests/Helpers/CharMemoryStream.cs @@ -45,10 +45,11 @@ public static (string Result, int AdvanceCount) ReadLine(ReadOnlySpan rema return new(line); } - public override ValueTask ReadAllAsync(CancellationToken cancellationToken) + public override ValueTask ReadAllAsync(CancellationToken cancellationToken) { + var remaining = Buffer[position..]; position = Buffer.Length; - return new( new LuaFileContent(Buffer.ToArray())); + return new( remaining.ToString()); } public override ValueTask ReadStringAsync(int count, CancellationToken cancellationToken) diff --git a/tests/Lua.Tests/Helpers/NotImplementedExceptionFileSystemBase.cs b/tests/Lua.Tests/Helpers/NotImplementedExceptionFileSystemBase.cs index e6677fdd..0f00df7d 100644 --- a/tests/Lua.Tests/Helpers/NotImplementedExceptionFileSystemBase.cs +++ b/tests/Lua.Tests/Helpers/NotImplementedExceptionFileSystemBase.cs @@ -9,7 +9,7 @@ public virtual bool IsReadable(string path) throw new NotImplementedException(); } - public virtual ValueTask Open(string path, LuaFileMode mode, CancellationToken cancellationToken) + public virtual ValueTask Open(string path, LuaFileOpenMode mode, CancellationToken cancellationToken) { throw new NotImplementedException(); } diff --git a/tests/Lua.Tests/Helpers/NotSupportedStreamBase.cs b/tests/Lua.Tests/Helpers/NotSupportedStreamBase.cs index cd6c3ace..f1770bc8 100644 --- a/tests/Lua.Tests/Helpers/NotSupportedStreamBase.cs +++ b/tests/Lua.Tests/Helpers/NotSupportedStreamBase.cs @@ -8,15 +8,14 @@ public virtual void Dispose() { } - public virtual LuaFileMode Mode => throw IOThrowHelpers.GetNotSupportedException(); - public LuaFileContentType ContentType=> throw IOThrowHelpers.GetNotSupportedException(); + public virtual LuaFileOpenMode Mode => throw IOThrowHelpers.GetNotSupportedException(); public virtual ValueTask ReadLineAsync(CancellationToken cancellationToken) { throw IOThrowHelpers.GetNotSupportedException(); } - public virtual ValueTask ReadAllAsync(CancellationToken cancellationToken) + public virtual ValueTask ReadAllAsync(CancellationToken cancellationToken) { throw IOThrowHelpers.GetNotSupportedException(); } @@ -26,7 +25,7 @@ public virtual ValueTask ReadAllAsync(CancellationToken cancella throw IOThrowHelpers.GetNotSupportedException(); } - public virtual ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken) + public virtual ValueTask WriteAsync(ReadOnlyMemory content, CancellationToken cancellationToken) { throw IOThrowHelpers.GetNotSupportedException(); } diff --git a/tests/Lua.Tests/IOTests.cs b/tests/Lua.Tests/IOTests.cs index 9ba335e5..f06d71c9 100644 --- a/tests/Lua.Tests/IOTests.cs +++ b/tests/Lua.Tests/IOTests.cs @@ -28,58 +28,7 @@ private string GetTestFilePath(string filename) { return Path.Combine(testDirectory, filename); } - - [Test] - public void FileOpenFlags_ParseModeString_Parses_Correctly() - { - // Text modes - Assert.That(LuaFileModeExtensions.ParseModeString("r"), Is.EqualTo(LuaFileMode.ReadText)); - Assert.That(LuaFileModeExtensions.ParseModeString("w"), Is.EqualTo(LuaFileMode.WriteText)); - Assert.That(LuaFileModeExtensions.ParseModeString("a"), Is.EqualTo(LuaFileMode.AppendText)); - - // Binary modes - Assert.That(LuaFileModeExtensions.ParseModeString("rb"), Is.EqualTo(LuaFileMode.ReadBinary)); - Assert.That(LuaFileModeExtensions.ParseModeString("wb"), Is.EqualTo(LuaFileMode.WriteBinary)); - Assert.That(LuaFileModeExtensions.ParseModeString("ab"), Is.EqualTo(LuaFileMode.AppendBinary)); - - // Update modes - Assert.That(LuaFileModeExtensions.ParseModeString("r+"), Is.EqualTo(LuaFileMode.ReadUpdateText)); - Assert.That(LuaFileModeExtensions.ParseModeString("w+"), Is.EqualTo(LuaFileMode.WriteUpdateText)); - Assert.That(LuaFileModeExtensions.ParseModeString("a+"), Is.EqualTo(LuaFileMode.AppendUpdateText)); - - // Binary update modes - Assert.That(LuaFileModeExtensions.ParseModeString("r+b"), Is.EqualTo(LuaFileMode.ReadUpdateBinary)); - Assert.That(LuaFileModeExtensions.ParseModeString("rb+"), Is.EqualTo(LuaFileMode.ReadUpdateBinary)); - Assert.That(LuaFileModeExtensions.ParseModeString("w+b"), Is.EqualTo(LuaFileMode.WriteUpdateBinary)); - Assert.That(LuaFileModeExtensions.ParseModeString("wb+"), Is.EqualTo(LuaFileMode.WriteUpdateBinary)); - - // Mixed order modes - Assert.That(LuaFileModeExtensions.ParseModeString("br"), Is.EqualTo(LuaFileMode.ReadBinary)); - Assert.That(LuaFileModeExtensions.ParseModeString("rb"), Is.EqualTo(LuaFileMode.ReadBinary)); - Assert.That(LuaFileModeExtensions.ParseModeString("tr"), Is.EqualTo(LuaFileMode.ReadText)); - Assert.That(LuaFileModeExtensions.ParseModeString("rt"), Is.EqualTo(LuaFileMode.ReadText)); - } - - [Test] - public void FileOpenFlags_GetOpenMode_Returns_Correct_Mode() - { - Assert.That(LuaFileMode.Read.GetOpenMode(), Is.EqualTo(LuaFileOpenMode.Read)); - Assert.That(LuaFileMode.Write.GetOpenMode(), Is.EqualTo(LuaFileOpenMode.Write)); - Assert.That(LuaFileMode.Append.GetOpenMode(), Is.EqualTo(LuaFileOpenMode.Append)); - Assert.That(LuaFileMode.ReadUpdate.GetOpenMode(), Is.EqualTo(LuaFileOpenMode.ReadWriteOpen)); - Assert.That(LuaFileMode.WriteUpdate.GetOpenMode(), Is.EqualTo(LuaFileOpenMode.ReadWriteCreate)); - Assert.That(LuaFileMode.AppendUpdate.GetOpenMode(), Is.EqualTo(LuaFileOpenMode.ReadAppend)); - } - - [Test] - public void FileOpenFlags_GetContentType_Returns_Correct_Type() - { - Assert.That(LuaFileMode.Read.GetContentType(), Is.EqualTo(LuaFileContentType.Text)); - Assert.That(LuaFileMode.ReadText.GetContentType(), Is.EqualTo(LuaFileContentType.Text)); - Assert.That(LuaFileMode.ReadBinary.GetContentType(), Is.EqualTo(LuaFileContentType.Binary)); - Assert.That(LuaFileMode.WriteBinary.GetContentType(), Is.EqualTo(LuaFileContentType.Binary)); - } - + [Test] public async Task TextStream_Write_And_Read_Text() { @@ -87,66 +36,21 @@ public async Task TextStream_Write_And_Read_Text() var testContent = "Hello, World!\nThis is a test."; // Write text - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write,CancellationToken.None)) { - await stream.WriteAsync(new(testContent), CancellationToken.None); + await stream.WriteAsync(testContent, CancellationToken.None); } // Read text - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadText,CancellationToken.None)) - { - var content = await stream.ReadAllAsync(CancellationToken.None); - Assert.That(content.Type, Is.EqualTo(LuaFileContentType.Text)); - Assert.That(content.ReadString(), Is.EqualTo(testContent)); - } - } - - [Test] - public async Task BinaryStream_Write_And_Read_Bytes() - { - var testFile = GetTestFilePath("binary_test.bin"); - var testBytes = new byte[] { 0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD }; - - // Write bytes - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteBinary,CancellationToken.None)) - { - await stream.WriteAsync(new(testBytes), CancellationToken.None); - } - - // Read bytes - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadBinary,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Read,CancellationToken.None)) { var content = await stream.ReadAllAsync(CancellationToken.None); - Assert.That(content.Type, Is.EqualTo(LuaFileContentType.Binary)); - Assert.That(content.ReadBytes().ToArray(), Is.EqualTo(testBytes)); + Assert.That(content, Is.EqualTo(testContent)); } } - [Test] - public async Task TextStream_Cannot_Write_Binary_Content() - { - var testFile = GetTestFilePath("text_binary_mix.txt"); - - using var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None); - var binaryContent = new LuaFileContent(new byte[] { 0x00, 0x01 }); - Assert.ThrowsAsync( - async () => await stream.WriteAsync(binaryContent, CancellationToken.None) - ); - } - [Test] - public async Task BinaryStream_Cannot_Write_Text_Content() - { - var testFile = GetTestFilePath("binary_text_mix.bin"); - - using var stream = await fileSystem.Open(testFile, LuaFileMode.WriteBinary,CancellationToken.None); - var textContent = new LuaFileContent("Hello"); - - Assert.ThrowsAsync( - async () => await stream.WriteAsync(textContent, CancellationToken.None) - ); - } [Test] public async Task TextStream_ReadLine_Works() @@ -155,13 +59,13 @@ public async Task TextStream_ReadLine_Works() var lines = new[] { "Line 1", "Line 2", "Line 3" }; // Write multiple lines - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write,CancellationToken.None)) { - await stream.WriteAsync(new(string.Join("\n", lines)), CancellationToken.None); + await stream.WriteAsync((string.Join("\n", lines)), CancellationToken.None); } // Read lines one by one - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Read,CancellationToken.None)) { for (int i = 0; i < lines.Length; i++) { @@ -182,13 +86,13 @@ public async Task TextStream_ReadString_Works() var testContent = "Hello, World!"; // Write content - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write,CancellationToken.None)) { - await stream.WriteAsync(new(testContent), CancellationToken.None); + await stream.WriteAsync(testContent, CancellationToken.None); } // Read partial strings - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Read,CancellationToken.None)) { var part1 = await stream.ReadStringAsync(5, CancellationToken.None); Assert.That(part1, Is.EqualTo("Hello")); @@ -203,28 +107,7 @@ public async Task TextStream_ReadString_Works() Assert.That(eof, Is.Null); } } - - [Test] - public async Task BinaryStream_Cannot_Use_Text_Operations() - { - var testFile = GetTestFilePath("binary_no_text.bin"); - - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteBinary,CancellationToken.None)) - { - await stream.WriteAsync(new(new byte[] { 0x01, 0x02 }), CancellationToken.None); - } - - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadBinary,CancellationToken.None)) - { - Assert.ThrowsAsync( - async () => await stream.ReadLineAsync(CancellationToken.None) - ); - - Assert.ThrowsAsync( - async () => await stream.ReadStringAsync(10, CancellationToken.None) - ); - } - } + [Test] public async Task Append_Mode_Appends_Content() @@ -232,22 +115,22 @@ public async Task Append_Mode_Appends_Content() var testFile = GetTestFilePath("append_test.txt"); // Write initial content - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write,CancellationToken.None)) { - await stream.WriteAsync(new("Hello"), CancellationToken.None); + await stream.WriteAsync(("Hello"), CancellationToken.None); } // Append content - using (var stream = await fileSystem.Open(testFile, LuaFileMode.AppendText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Append,CancellationToken.None)) { - await stream.WriteAsync(new(" World"), CancellationToken.None); + await stream.WriteAsync((" World"), CancellationToken.None); } // Read and verify - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Read,CancellationToken.None)) { var content = await stream.ReadAllAsync(CancellationToken.None); - Assert.That(content.ReadString(), Is.EqualTo("Hello World")); + Assert.That(content, Is.EqualTo("Hello World")); } } @@ -258,13 +141,13 @@ public async Task Seek_Works_Correctly() var testContent = "0123456789"; // Write content - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write,CancellationToken.None)) { - await stream.WriteAsync(new(testContent), CancellationToken.None); + await stream.WriteAsync((testContent), CancellationToken.None); } // Test seeking - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Read,CancellationToken.None)) { // Seek from beginning stream.Seek(5, SeekOrigin.Begin); @@ -332,12 +215,12 @@ public async Task FileSystem_TempFile_Works() { using (var tempStream = await fileSystem.OpenTempFileStream(CancellationToken.None)) { - await tempStream.WriteAsync(new("temp content"), CancellationToken.None); + await tempStream.WriteAsync("temp content".AsMemory(), CancellationToken.None); // Seek and read tempStream.Seek(0, SeekOrigin.Begin); var content = await tempStream.ReadAllAsync(CancellationToken.None); - Assert.That(content.ReadString(), Is.EqualTo("temp content")); + Assert.That(content, Is.EqualTo("temp content")); } } finally @@ -363,19 +246,19 @@ public async Task Buffering_Modes_Work() { var testFile = GetTestFilePath("buffer_test.txt"); - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write,CancellationToken.None)) { // Set no buffering stream.SetVBuf(LuaFileBufferingMode.NoBuffering, 0); - await stream.WriteAsync(new("No buffer"), CancellationToken.None); + await stream.WriteAsync(("No buffer"), CancellationToken.None); // Set line buffering stream.SetVBuf(LuaFileBufferingMode.LineBuffering, 1024); - await stream.WriteAsync(new("\nLine buffer"), CancellationToken.None); + await stream.WriteAsync(("\nLine buffer"), CancellationToken.None); // Set full buffering stream.SetVBuf(LuaFileBufferingMode.FullBuffering, 4096); - await stream.WriteAsync(new("\nFull buffer"), CancellationToken.None); + await stream.WriteAsync(("\nFull buffer"), CancellationToken.None); // Explicit flush await stream.FlushAsync(CancellationToken.None); @@ -395,28 +278,28 @@ public async Task LuaFileContent_Memory_Variations() // Test with char array var charArray = "Hello from char array".ToCharArray(); - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText, CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write, CancellationToken.None)) { - await stream.WriteAsync(new(charArray), CancellationToken.None); + await stream.WriteAsync(charArray, CancellationToken.None); } - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Read,CancellationToken.None)) { var content = await stream.ReadAllAsync(CancellationToken.None); - Assert.That(content.ReadString(), Is.EqualTo("Hello from char array")); + Assert.That(content, Is.EqualTo("Hello from char array")); } // Test with partial char array var longCharArray = "Hello World!!!".ToCharArray(); - using (var stream = await fileSystem.Open(testFile, LuaFileMode.WriteText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Write,CancellationToken.None)) { - await stream.WriteAsync(new(longCharArray.AsMemory(0, 11)), CancellationToken.None); // Only "Hello World" + await stream.WriteAsync((longCharArray.AsMemory(0, 11)), CancellationToken.None); // Only "Hello World" } - using (var stream = await fileSystem.Open(testFile, LuaFileMode.ReadText,CancellationToken.None)) + using (var stream = await fileSystem.Open(testFile, LuaFileOpenMode.Read,CancellationToken.None)) { var content = await stream.ReadAllAsync(CancellationToken.None); - Assert.That(content.ReadString(), Is.EqualTo("Hello World")); + Assert.That(content, Is.EqualTo("Hello World")); } } } \ No newline at end of file