Skip to main content

lua_types/
filehandle.rs

1//! Minimal file-handle abstraction shared between `lua-vm` (hook type) and
2//! `lua-stdlib` (io library).
3//!
4//! `std::fs` and `std::io` are banned in `lua-stdlib` by PORTING.md §1. The
5//! concrete implementation (backed by `std::fs::File`) lives in `lua-cli` and
6//! is installed via [`crate::error::LuaError`]-returning function pointers on
7//! [`lua_vm::state::GlobalState`]. This trait is the shared seam that allows
8//! `lua-stdlib` to program against file handles without importing `std::fs`.
9//!
10//! ## Trait design
11//! The trait mirrors the subset of `LuaFileOps` (defined in `lua-stdlib`) that
12//! is required to run the built-in io library at the level needed for
13//! `attrib.lua`-class tests: sequential write, byte-by-byte read, flush, and
14//! seek. `LuaFileOps` in `lua-stdlib` extends this trait so that a single
15//! concrete type (the `FsFile` in `lua-cli`) satisfies both.
16
17use std::io::{self, SeekFrom};
18
19/// Capabilities required by the io library from an OS file handle.
20///
21/// Designed to be object-safe (`Box<dyn LuaFileHandle>`). Implementations
22/// backed by `std::fs::File` live in `lua-cli`; implementations for the
23/// standard streams live in `lua-stdlib/src/io_lib.rs`.
24pub trait LuaFileHandle: Send {
25    /// Read one byte from the handle; return it as `i32`, or `-1` on EOF/error.
26    fn read_byte(&mut self) -> i32;
27
28    /// Push back a previously-read byte so the next `read_byte` returns it.
29    fn unread_byte(&mut self, byte: i32);
30
31    /// Write a byte slice; return the number of bytes actually written.
32    fn write_bytes(&mut self, data: &[u8]) -> io::Result<usize>;
33
34    /// Flush any write buffers to the underlying OS handle.
35    fn flush(&mut self) -> io::Result<()>;
36
37    /// Seek within the file.
38    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64>;
39
40    /// Return the current file position without moving it.
41    fn tell(&mut self) -> io::Result<u64>;
42
43    /// Clear the error/EOF flag on the handle.
44    fn clear_error(&mut self);
45
46    /// Return `true` if the handle has a pending error.
47    fn has_error(&self) -> bool;
48
49    /// Return the last pending OS error as `(errno, message)` when available.
50    ///
51    /// Some real Lua programs probe platform behavior through specific errno
52    /// values. LuaRocks' macOS directory detection, for example, expects
53    /// reading an opened directory to report `EISDIR` rather than look like EOF.
54    fn last_error_info(&self) -> Option<(i32, String)> {
55        None
56    }
57
58    /// Control write buffering. Mode values mirror `file:setvbuf` option order:
59    /// 0 = no buffering, 1 = full buffering, 2 = line buffering.
60    fn set_buf_mode(&mut self, _mode: i32, _size: usize) -> io::Result<()> {
61        Ok(())
62    }
63}
64
65// ──────────────────────────────────────────────────────────────────────────
66// PORT STATUS
67//   source:        (new abstraction — not a direct port of a C file)
68//   target_crate:  lua-types
69//   confidence:    high
70//   todos:         0
71//   port_notes:    0
72//   unsafe_blocks: 0
73//   notes:         Introduced in Phase B to break the dependency cycle that
74//                  would arise if `lua-vm` tried to use `LuaFileOps` from
75//                  `lua-stdlib`. The concrete `FsFile` implementation in
76//                  `lua-cli` implements this trait; `LuaFileOps` in
77//                  `lua-stdlib` is a type alias for this same trait.
78// ──────────────────────────────────────────────────────────────────────────