2
0
Эх сурвалжийг харах

Merge pull request #169 from nuskey8/revert-bytes

revert allows bytes
Akeit0 6 сар өмнө
parent
commit
f023db39d5

+ 0 - 16
src/Lua/IO/BinaryData.cs

@@ -1,16 +0,0 @@
-using System.Buffers;
-
-namespace Lua.IO;
-
-public class BinaryData(ReadOnlyMemory<byte> bytes) : IBinaryData
-{
-    public ReadOnlyMemory<byte> Memory => bytes;
-}
-
-public interface IBinaryData
-{
-    /// <summary>
-    /// Gets the bytes of the binary data.
-    /// </summary>
-    public ReadOnlyMemory<byte> Memory { get; }
-}

+ 0 - 88
src/Lua/IO/BinaryLuaStream.cs

@@ -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<LuaFileContent> 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<byte> 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();
-    }
-}

+ 1 - 1
src/Lua/IO/CompositeLoaderFileSystem.cs

@@ -40,7 +40,7 @@ public class CompositeLoaderFileSystem(ILuaFileLoader[] loaders, ILuaFileSystem?
         return false;
     }
 
-    public async ValueTask<ILuaStream> Open(string path, LuaFileMode mode, CancellationToken cancellationToken)
+    public async ValueTask<ILuaStream> Open(string path, LuaFileOpenMode mode, CancellationToken cancellationToken)
     {
         if (cached != null)
         {

+ 12 - 26
src/Lua/IO/FileSystem.cs

@@ -9,9 +9,9 @@
                 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 @@
         }
 
 
-        ILuaStream Open(string path, LuaFileOpenMode openMode, LuaFileContentType contentType)
+        public ValueTask<ILuaStream> 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 @@
                 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<ILuaStream> 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 @@
             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 ValueTask<ILuaStream> 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)));
         }
     }
 }

+ 1 - 1
src/Lua/IO/ILuaFileSystem.cs

@@ -3,7 +3,7 @@
 public interface ILuaFileSystem
 {
     public bool IsReadable(string path);
-    public ValueTask<ILuaStream> Open(string path, LuaFileMode mode, CancellationToken cancellationToken);
+    public ValueTask<ILuaStream> 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 => "/";

+ 15 - 28
src/Lua/IO/ILuaStream.cs

@@ -2,9 +2,9 @@
 {
     public interface ILuaStream : IDisposable
     {
-        public LuaFileMode Mode { get; }
+        public LuaFileOpenMode Mode { get; }
 
-        public ValueTask<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
+        public ValueTask<string> ReadAllAsync(CancellationToken cancellationToken)
         {
             Mode.ThrowIfNotReadable();
 
@@ -16,7 +16,6 @@
         {
             Mode.ThrowIfNotReadable();
 
-            Mode.ThrowIfNotText();
 
             // Default implementation using ReadStringAsync
             throw new NotImplementedException($"ReadLineAsync must be implemented by {GetType().Name}");
@@ -26,26 +25,19 @@
         {
             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<char> 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 @@
             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<char> content)
         {
-            if (content.Type == LuaFileContentType.Binary)
-            {
-                return new ByteMemoryStream(content.ReadBytes() );
-            }
-            else
-            {
-                return new StringStream(content.ReadString());
-            }
+            return new CharMemoryStream(content);
         }
 
 

+ 0 - 107
src/Lua/IO/LuaChunkStream.cs

@@ -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<byte>.Shared.Rent((int)length);
-            try
-            {
-                var count = stream.Read(bytesToReturnToPool.AsSpan());
-                bytes = bytesToReturnToPool.AsMemory(0, count);
-            }
-            catch (Exception)
-            {
-                ArrayPool<byte>.Shared.Return(bytesToReturnToPool);
-            }
-        }
-    }
-
-    public LuaChunkStream(ReadOnlyMemory<byte> bytes, IDisposable? disposable = null)
-    {
-        this.bytes = bytes;
-        this.disposable = disposable;
-    }
-
-    byte[]? bytesToReturnToPool;
-    char[]? charsToReturnToPool;
-    private readonly ReadOnlyMemory<byte> bytes;
-    private IDisposable? disposable;
-
-    public void Dispose()
-    {
-        if (bytesToReturnToPool is not null)
-        {
-            ArrayPool<byte>.Shared.Return(bytesToReturnToPool);
-            bytesToReturnToPool = null!;
-        }
-
-        if (charsToReturnToPool is not null)
-        {
-            ArrayPool<char>.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<LuaFileContent> 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<char>.Shared.Rent(encoding.GetMaxCharCount(span.Length));
-            var charCount = encoding.GetChars(span, array);
-            charsToReturnToPool = array;
-            return new(new LuaFileContent(array.AsMemory(0, charCount)));
-        }
-    }
-
-    public ValueTask<string?> ReadLineAsync(CancellationToken cancellationToken)
-    {
-        throw new NotSupportedException();
-    }
-
-    public ValueTask<string?> 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();
-    }
-}

+ 0 - 201
src/Lua/IO/LuaFileMode.cs

@@ -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+
-
-    /// <summary>
-    /// This is used for load files. bt mode.
-    /// </summary>
-    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.");
-        }
-    }
-}

+ 96 - 31
src/Lua/IO/LuaFileOpenMode.cs

@@ -1,35 +1,100 @@
-namespace Lua.IO
+namespace Lua.IO;
+
+public enum LuaFileOpenMode
+{
+    /// <summary>
+    /// r
+    /// </summary>
+    Read,
+
+    /// <summary>
+    /// w
+    /// </summary>
+    Write,
+
+    /// <summary>
+    /// a
+    /// </summary>
+    Append,
+
+    /// <summary>
+    /// r+
+    /// </summary>
+    ReadUpdate,
+
+    /// <summary>
+    /// w+
+    /// </summary>
+    WriteUpdate,
+
+    /// <summary>
+    /// a+
+    /// </summary>
+    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)
     {
-        /// <summary>
-        /// r
-        /// </summary>
-        Read,
-
-        /// <summary>
-        /// w
-        /// </summary>
-        Write,
-
-        /// <summary>
-        /// a
-        /// </summary>
-        Append,
-
-        /// <summary>
-        /// r+
-        /// </summary>
-        ReadWriteOpen,
-
-        /// <summary>
-        /// w+
-        /// </summary>
-        ReadWriteCreate,
-
-        /// <summary>
-        /// a+
-        /// </summary>
-        ReadAppend,
+        if (!mode.CanWrite())
+        {
+            throw new IOException($"Cannot write to a file opened with mode {mode}");
+        }
     }
 }

+ 8 - 93
src/Lua/IO/MemoryStreams.cs

@@ -1,113 +1,28 @@
 namespace Lua.IO;
 
-public sealed class ByteMemoryStream(ReadOnlyMemory<byte> 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<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
-    {
-        ThrowIfDisposed();
-        cancellationToken.ThrowIfCancellationRequested();
-
-        var remaining = bytes.Slice(position);
-        position = bytes.Length;
-        return new(new LuaFileContent(remaining));
-    }
-
-    public ValueTask<string?> ReadLineAsync(CancellationToken cancellationToken)
-    {
-        ThrowIfDisposed();
-        cancellationToken.ThrowIfCancellationRequested();
-
-        throw new InvalidOperationException("Cannot read lines string from a binary stream.");
-    }
-
-    public ValueTask<string?> 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<char> 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<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
+    public virtual ValueTask<string> 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<string?> ReadLineAsync(CancellationToken cancellationToken)
@@ -160,9 +75,9 @@ public class CharMemoryStream(ReadOnlyMemory<char> contents) : ILuaStream
         return new(result);
     }
 
-    public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken)
+    public ValueTask WriteAsync(ReadOnlyMemory<char> 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 @@ public class CharMemoryStream(ReadOnlyMemory<char> contents) : ILuaStream
 
 public sealed class StringStream(string content) : CharMemoryStream(content.AsMemory())
 {
-    public override ValueTask<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
+    public override ValueTask<string> ReadAllAsync(CancellationToken cancellationToken)
     {
         ThrowIfDisposed();
         cancellationToken.ThrowIfCancellationRequested();
         if (Position == 0)
-            return new(new LuaFileContent(content));
+            return new((content));
         return base.ReadAllAsync(cancellationToken);
     }
 }

+ 3 - 3
src/Lua/IO/StandardIOStream.cs

@@ -5,9 +5,9 @@
     /// </summary>
     internal sealed class StandardIOStream(ILuaStream innerStream) : ILuaStream
     {
-        public LuaFileMode Mode => innerStream.Mode;
+        public LuaFileOpenMode Mode => innerStream.Mode;
 
-        public ValueTask<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
+        public ValueTask<string> ReadAllAsync(CancellationToken cancellationToken)
             => innerStream.ReadAllAsync(cancellationToken);
 
         public ValueTask<string?> ReadLineAsync(CancellationToken cancellationToken)
@@ -16,7 +16,7 @@
         public ValueTask<string?> ReadStringAsync(int count, CancellationToken cancellationToken)
             => innerStream.ReadStringAsync(count, cancellationToken);
 
-        public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken)
+        public ValueTask WriteAsync(ReadOnlyMemory<char> content, CancellationToken cancellationToken)
             => innerStream.WriteAsync(content, cancellationToken);
 
         public ValueTask FlushAsync(CancellationToken cancellationToken)

+ 4 - 9
src/Lua/IO/TextLuaStream.cs

@@ -3,13 +3,13 @@ using System.Text;
 
 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<string?> ReadLineAsync(CancellationToken cancellationToken)
     {
@@ -18,12 +18,12 @@ internal sealed class TextLuaStream(LuaFileMode mode, Stream innerStream) : ILua
         return new(reader.ReadLine(innerStream));
     }
 
-    public ValueTask<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
+    public ValueTask<string> ReadAllAsync(CancellationToken cancellationToken)
     {
         mode.ThrowIfNotReadable();
         reader ??= new();
         var text = reader.ReadToEnd(innerStream);
-        return new(new LuaFileContent(text));
+        return new(text);
     }
 
     public ValueTask<string?> ReadStringAsync(int count, CancellationToken cancellationToken)
@@ -33,11 +33,6 @@ internal sealed class TextLuaStream(LuaFileMode mode, Stream innerStream) : ILua
         return new(reader.Read(innerStream, count));
     }
 
-    public ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken)
-    {
-        mode.ThrowIfNotWritable();
-        return WriteAsync(content.ReadText(), cancellationToken);
-    }
 
     public ValueTask WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken)
     {

+ 0 - 19
src/Lua/Loaders/FileModuleLoader.cs

@@ -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<LuaModule> 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);
-    }
-}

+ 0 - 73
src/Lua/LuaFileContent.cs

@@ -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<char> memory)
-    {
-        type = LuaFileContentType.Text;
-        referenceValue = memory;
-    }
-
-    public LuaFileContent(ReadOnlyMemory<byte> 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<char> 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<char>)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<char>)referenceValue).ToString();
-    }
-
-    public ReadOnlyMemory<byte> 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();
-        }
-    }
-}

+ 14 - 37
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<char> text;
+    readonly ReadOnlyMemory<byte> bytes;
 
-    public LuaModule(string name, string text)
+    public LuaModule(string name, ReadOnlyMemory<char> text)
     {
         this.name = name;
         type = LuaModuleType.Text;
-        referenceValue = text;
+        this.text = text;
     }
 
-    public LuaModule(string name, byte[] bytes)
+    public LuaModule(string name, ReadOnlyMemory<byte> bytes)
     {
         this.name = name;
         type = LuaModuleType.Bytes;
-        referenceValue = bytes;
+        this.bytes = bytes;
     }
 
-    public LuaModule(string name, IMemoryOwner<char> bytes)
-    {
-        this.name = name;
-        type = LuaModuleType.Text;
-        referenceValue = bytes;
-    }
+    public LuaModule(string name, string text) : this(name, text.AsMemory()) { }
 
-    public LuaModule(string name, IMemoryOwner<byte> bytes)
+    public LuaModule(string name, byte[] bytes)
+        : this(name, new ReadOnlyMemory<byte>(bytes))
     {
-        this.name = name;
-        type = LuaModuleType.Bytes;
-        referenceValue = bytes;
     }
 
     public ReadOnlySpan<char> ReadText()
     {
         if (type != LuaModuleType.Text) throw new Exception(); // TODO: add message
-        if (referenceValue is IMemoryOwner<char> mem)
-        {
-            return mem.Memory.Span;
-        }
-
-        return ((string)referenceValue);
+        return text.Span;
     }
 
     public ReadOnlySpan<byte> ReadBytes()
     {
         if (type != LuaModuleType.Bytes) throw new Exception(); // TODO: add message
-        if (referenceValue is IMemoryOwner<byte> mem)
-        {
-            return mem.Memory.Span;
-        }
-
-        return (byte[])referenceValue;
-    }
-
-    public void Dispose()
-    {
-        if (referenceValue is IDisposable memoryOwner)
-        {
-            memoryOwner.Dispose();
-        }
+        return bytes.Span;
     }
 }

+ 1 - 2
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.");

+ 3 - 24
src/Lua/LuaStateExtensions.cs

@@ -38,30 +38,9 @@ public static class LuaStateExtensions
     public static async ValueTask<LuaClosure> 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;
     }

+ 4 - 8
src/Lua/Standard/BasicLibrary.cs

@@ -200,10 +200,6 @@ public sealed class BasicLibrary
                 // TODO: 
                 throw new NotImplementedException();
             }
-            else if (arg0.TryRead<IBinaryData>(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 sealed class BasicLibrary
     public async ValueTask<int> 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<string>()), cancellationToken);
+            await stdout.WriteAsync(context.Thread.Stack.Pop().Read<string>(), 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();
     }

+ 5 - 13
src/Lua/Standard/FileHandle.cs

@@ -46,7 +46,7 @@ public class FileHandle : ILuaUserData
         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 class FileHandle : ILuaUserData
         return stream.ReadLineAsync(cancellationToken);
     }
 
-    public ValueTask<LuaFileContent> ReadToEndAsync(CancellationToken cancellationToken)
+    public ValueTask<string> ReadToEndAsync(CancellationToken cancellationToken)
     {
         return stream.ReadAllAsync(cancellationToken);
     }
@@ -68,25 +68,17 @@ public class FileHandle : ILuaUserData
         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<char> 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 class FileHandle : ILuaUserData
         }
         catch (IOException ex)
         {
-            return (context.Return(LuaValue.Nil, ex.Message, ex.HResult));
+            return context.Return(LuaValue.Nil, ex.Message, ex.HResult);
         }
     });
 

+ 14 - 14
src/Lua/Standard/IOLibrary.cs

@@ -13,16 +13,16 @@ public sealed class 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 sealed class IOLibrary
         }
         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 sealed class IOLibrary
             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<FileHandle>();
             var upValues = new LuaValue[context.Arguments.Length];
@@ -168,7 +168,7 @@ public sealed class IOLibrary
         }
         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 sealed class IOLibrary
 
     public async ValueTask<int> 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))));
     }
 }

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

@@ -6,13 +6,13 @@ namespace Lua.Standard.Internal;
 
 internal static class IOHelper
 {
-    public static async ValueTask<int> Open(LuaThread thread, string fileName, string mode, bool throwError,CancellationToken cancellationToken)
+    public static async ValueTask<int> 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 @@ internal static class IOHelper
                     using var fileBuffer = new PooledArray<char>(64);
                     var span = fileBuffer.AsSpan();
                     d.TryFormat(span, out var charsWritten);
-                    await file.WriteAsync(fileBuffer.UnderlyingArray.AsMemory(0,charsWritten) , cancellationToken);
-                }
-                else if (arg.TryRead<IBinaryData>(out var binaryData))
-                {
-                    await file.WriteAsync( binaryData, cancellationToken);
+                    await file.WriteAsync(fileBuffer.UnderlyingArray.AsMemory(0, charsWritten), cancellationToken);
                 }
                 else
                 {
@@ -103,7 +99,7 @@ internal static class IOHelper
                             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":

+ 14 - 1
src/Lua/Standard/ModuleLibrary.cs

@@ -24,7 +24,20 @@ public sealed class ModuleLibrary
 
         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;

+ 2 - 2
tests/Lua.Tests/AbstractFileTests.cs

@@ -9,14 +9,14 @@ public class AbstractFileTests
 {
     class ReadOnlyFileSystem(Dictionary<string, string> dictionary) : NotImplementedExceptionFileSystemBase
     {
-        public override  ValueTask<ILuaStream> Open(string path, LuaFileMode mode,CancellationToken cancellationToken)
+        public override ValueTask<ILuaStream> 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()));
         }

+ 3 - 2
tests/Lua.Tests/Helpers/CharMemoryStream.cs

@@ -45,10 +45,11 @@ internal sealed class ReadOnlyCharMemoryLuaIOStream(ReadOnlyMemory<char> buffer,
         return new(line);
     }
 
-    public override ValueTask<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
+    public override ValueTask<string> ReadAllAsync(CancellationToken cancellationToken)
     {
+        var remaining = Buffer[position..];
         position = Buffer.Length;
-        return new( new LuaFileContent(Buffer.ToArray()));
+        return new( remaining.ToString());
     }
 
     public override ValueTask<string?> ReadStringAsync(int count, CancellationToken cancellationToken)

+ 1 - 1
tests/Lua.Tests/Helpers/NotImplementedExceptionFileSystemBase.cs

@@ -9,7 +9,7 @@ namespace Lua.Tests.Helpers
             throw new NotImplementedException();
         }
 
-        public virtual ValueTask<ILuaStream> Open(string path, LuaFileMode mode, CancellationToken cancellationToken)
+        public virtual ValueTask<ILuaStream> Open(string path, LuaFileOpenMode mode, CancellationToken cancellationToken)
         {
             throw new NotImplementedException();
         }

+ 3 - 4
tests/Lua.Tests/Helpers/NotSupportedStreamBase.cs

@@ -8,15 +8,14 @@ namespace Lua.Tests.Helpers
         {
         }
 
-        public virtual LuaFileMode Mode => throw IOThrowHelpers.GetNotSupportedException();
-        public LuaFileContentType ContentType=> throw IOThrowHelpers.GetNotSupportedException();
+        public virtual LuaFileOpenMode Mode => throw IOThrowHelpers.GetNotSupportedException();
 
         public virtual ValueTask<string?> ReadLineAsync(CancellationToken cancellationToken)
         {
             throw IOThrowHelpers.GetNotSupportedException();
         }
 
-        public virtual ValueTask<LuaFileContent> ReadAllAsync(CancellationToken cancellationToken)
+        public virtual ValueTask<string> ReadAllAsync(CancellationToken cancellationToken)
         {
             throw IOThrowHelpers.GetNotSupportedException();
         }
@@ -26,7 +25,7 @@ namespace Lua.Tests.Helpers
             throw IOThrowHelpers.GetNotSupportedException();
         }
 
-        public virtual ValueTask WriteAsync(LuaFileContent content, CancellationToken cancellationToken)
+        public virtual ValueTask WriteAsync(ReadOnlyMemory<char> content, CancellationToken cancellationToken)
         {
             throw IOThrowHelpers.GetNotSupportedException();
         }

+ 35 - 152
tests/Lua.Tests/IOTests.cs

@@ -28,58 +28,7 @@ public class IOTests : IDisposable
     {
         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 class IOTests : IDisposable
         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<InvalidOperationException>(
-            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<InvalidOperationException>(
-            async () => await stream.WriteAsync(textContent, CancellationToken.None)
-        );
-    }
 
     [Test]
     public async Task TextStream_ReadLine_Works()
@@ -155,13 +59,13 @@ public class IOTests : IDisposable
         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 class IOTests : IDisposable
         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 class IOTests : IDisposable
             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<InvalidOperationException>(
-                async () => await stream.ReadLineAsync(CancellationToken.None)
-            );
-
-            Assert.ThrowsAsync<InvalidOperationException>(
-                async () => await stream.ReadStringAsync(10, CancellationToken.None)
-            );
-        }
-    }
+    
 
     [Test]
     public async Task Append_Mode_Appends_Content()
@@ -232,22 +115,22 @@ public class IOTests : IDisposable
         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 class IOTests : IDisposable
         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 class IOTests : IDisposable
         {
             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 class IOTests : IDisposable
     {
         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 class IOTests : IDisposable
 
         // 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"));
         }
     }
 }