Skip to main content

lua_assembler/formats/luac/reader/
mod.rs

1#![doc = include_str!("readme.md")]
2
3use crate::{
4    formats::luac::LuacReadConfig,
5    program::{LuaProgram, LuaVersion, LuacCodeObject, LuacHeader},
6};
7use gaia_binary::{BinaryReader, Fixed, LittleEndian};
8use gaia_types::{GaiaDiagnostics, GaiaError};
9use std::{
10    cell::RefCell,
11    io::{Read, Seek},
12    sync::OnceLock,
13};
14
15/// LuacInfo 表示 .luac 文件的基本信息视图
16#[derive(Debug, Clone, Copy)]
17pub struct LuacInfo {
18    /// .luac 文件头信息
19    pub header: LuacHeader,
20    /// Lua 版本信息
21    pub version: LuaVersion,
22}
23
24/// 现代化的惰性 .luac 文件读取器
25///
26/// 采用惰性加载模式,只在需要时才解析数据,提高性能。
27/// 使用 `OnceLock` 确保数据只被解析一次。
28#[derive(Debug)]
29pub struct LuacReader<'config, R: std::io::Read> {
30    config: &'config LuacReadConfig,
31    reader: RefCell<BinaryReader<R, Fixed<LittleEndian>>>,
32    info: OnceLock<LuacInfo>,
33    program: OnceLock<LuaProgram>,
34}
35
36impl LuacReadConfig {
37    /// 创建一个新的 LuacReader 实例
38    ///
39    /// # 参数
40    ///
41    /// * `reader` - 实现了 Read + Seek 的数据源
42    ///
43    /// # 返回值
44    ///
45    /// 返回一个新的 LuacReader 实例
46    pub fn as_reader<R: Read + Seek>(&self, reader: R) -> LuacReader<'_, R> {
47        LuacReader::new(reader, self)
48    }
49}
50
51impl<'config, R: std::io::Read> LuacReader<'config, R> {
52    /// 创建一个新的 LuacReader 实例
53    ///
54    /// # 参数
55    ///
56    /// * `reader` - 实现了 Read + Seek 的数据源
57    /// * `config` - 读取配置
58    ///
59    /// # 返回值
60    ///
61    /// 返回一个新的 LuacReader 实例
62    pub fn new(reader: R, config: &'config LuacReadConfig) -> Self {
63        Self {
64            config,
65            reader: RefCell::new(BinaryReader::<R, Fixed<LittleEndian>>::new(reader)),
66            info: Default::default(),
67            program: Default::default(),
68        }
69    }
70
71    /// 完成读取并返回 LuaProgram 结果
72    ///
73    /// # 返回值
74    ///
75    /// 返回包含 LuaProgram 和诊断信息的 GaiaDiagnostics
76    pub fn finish(self) -> GaiaDiagnostics<LuaProgram>
77    where
78        R: std::io::Read + std::io::Seek,
79    {
80        match self.get_program() {
81            Ok(program) => {
82                let errors = self.reader.borrow_mut().take_errors();
83                GaiaDiagnostics { result: Ok(program.clone()), diagnostics: errors }
84            }
85            Err(e) => {
86                let errors = self.reader.borrow_mut().take_errors();
87                GaiaDiagnostics { result: Err(e), diagnostics: errors }
88            }
89        }
90    }
91}
92
93impl<'config, R: std::io::Read + std::io::Seek> LuacReader<'config, R> {
94    /// 获取解析后的 LuaProgram
95    ///
96    /// # 返回值
97    ///
98    /// 返回 LuaProgram 的引用,如果解析失败则返回错误
99    pub fn get_program(&self) -> Result<&LuaProgram, GaiaError> {
100        match self.program.get() {
101            Some(program) => Ok(program),
102            None => {
103                let program = self.read_program()?;
104                Ok(self.program.get_or_init(|| program))
105            }
106        }
107    }
108
109    /// 获取 .luac 文件的基本信息
110    ///
111    /// # 返回值
112    ///
113    /// 返回 LuacInfo 的引用,如果解析失败则返回错误
114    pub fn get_info(&self) -> Result<&LuacInfo, GaiaError> {
115        match self.info.get() {
116            Some(info) => Ok(info),
117            None => {
118                let info = self.read_info()?;
119                Ok(self.info.get_or_init(|| info))
120            }
121        }
122    }
123
124    fn read_info(&self) -> Result<LuacInfo, GaiaError> {
125        let mut reader = self.reader.borrow_mut();
126
127        // 重新定位到文件开头
128        reader.seek(std::io::SeekFrom::Start(0))?;
129
130        // 检查文件是否为空
131        let current_pos = reader.stream_position()?;
132        reader.seek(std::io::SeekFrom::End(0))?;
133        let file_size = reader.stream_position()?;
134        reader.seek(std::io::SeekFrom::Start(current_pos))?;
135
136        if file_size == 0 {
137            return Err(GaiaError::custom_error("File is empty".to_string()));
138        }
139
140        // 读取 .luac 文件头
141        let header = self.read_header(&mut reader)?;
142
143        // 从配置或头部确定版本
144        let version = if self.config.version != LuaVersion::Unknown {
145            self.config.version
146        }
147        else {
148            LuaVersion::from_byte(header.version.to_byte())
149        };
150
151        Ok(LuacInfo { header, version })
152    }
153
154    fn read_program(&self) -> Result<LuaProgram, GaiaError> {
155        let mut reader = self.reader.borrow_mut();
156
157        // 重新定位到文件开头
158        reader.seek(std::io::SeekFrom::Start(0))?;
159
160        // 读取头部信息
161        let header = self.read_header(&mut reader)?;
162
163        // 确定 Lua 版本
164        let version = if self.config.version != LuaVersion::Unknown {
165            self.config.version
166        }
167        else {
168            LuaVersion::from_byte(header.version.to_byte())
169        };
170
171        // 读取代码对象
172        let code_object = self.read_code_object(&mut reader)?;
173
174        // 构建 LuaProgram
175        let program = LuaProgram { header, code_object };
176
177        Ok(program)
178    }
179
180    fn read_header(&self, reader: &mut BinaryReader<R, Fixed<LittleEndian>>) -> Result<LuacHeader, GaiaError> {
181        // 读取 Lua 字节码魔数 "\x1bLua"
182        let mut magic = [0u8; 4];
183        reader.read_exact(&mut magic).map_err(|e| GaiaError::custom_error(format!("Failed to read magic bytes: {}", e)))?;
184
185        // 验证魔数(如果配置要求检查)
186        if self.config.check_magic_head {
187            let expected_magic = [0x1b, b'L', b'u', b'a'];
188            if magic != expected_magic {
189                return Err(GaiaError::custom_error(format!(
190                    "Invalid Lua bytecode magic: expected {:?}, got {:?}",
191                    expected_magic, magic
192                )));
193            }
194        }
195
196        // 读取版本信息
197        let version_byte =
198            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read version byte: {}", e)))?;
199        let version = LuaVersion::from_byte(version_byte);
200
201        // 读取格式版本
202        let format_version =
203            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read format version: {}", e)))?;
204
205        // 读取字节序标识
206        let endianness = reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read endianness: {}", e)))?;
207
208        // 读取各种大小信息
209        let int_size = reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read int_size: {}", e)))?;
210        let size_t_size =
211            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read size_t_size: {}", e)))?;
212        let instruction_size =
213            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read instruction_size: {}", e)))?;
214        let lua_number_size =
215            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read lua_number_size: {}", e)))?;
216        let integral_flag =
217            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read integral_flag: {}", e)))?;
218
219        Ok(LuacHeader {
220            magic,
221            version,
222            format_version,
223            endianness,
224            int_size,
225            size_t_size,
226            instruction_size,
227            lua_number_size,
228            integral_flag,
229            flags: 0,
230            timestamp: None,
231            size: None,
232            hash: None,
233        })
234    }
235
236    fn read_code_object(&self, _reader: &mut BinaryReader<R, Fixed<LittleEndian>>) -> Result<LuacCodeObject, GaiaError> {
237        // 暂时返回默认的代码对象
238        // 完整的实现需要解析 Lua 字节码的复杂结构
239        Ok(LuacCodeObject {
240            source_name: String::new(),
241            first_line: 0,
242            last_line: 0,
243            num_params: 0,
244            is_vararg: 0,
245            max_stack_size: 0,
246            nested_functions: Vec::new(),
247            upvalues: Vec::new(),
248            local_vars: Vec::new(),
249            line_info: Vec::new(),
250            co_argcount: 0,
251            co_nlocal: 0,
252            co_stacks: 0,
253            num_upval: 0,
254            co_code: Vec::new(),
255            co_consts: Vec::new(),
256            upvalue_n: 0,
257        })
258    }
259}
260
261impl Default for LuaProgram {
262    fn default() -> Self {
263        Self { header: LuacHeader::default(), code_object: LuacCodeObject::default() }
264    }
265}
266
267impl Default for LuacHeader {
268    fn default() -> Self {
269        Self {
270            magic: [0x1b, b'L', b'u', b'a'],
271            version: LuaVersion::Unknown,
272            format_version: 0,
273            endianness: 1, // 小端序
274            int_size: 4,
275            size_t_size: 8,
276            instruction_size: 4,
277            lua_number_size: 8,
278            integral_flag: 0,
279            flags: 0,
280            timestamp: None,
281            size: None,
282            hash: None,
283        }
284    }
285}
286
287impl Default for LuacCodeObject {
288    fn default() -> Self {
289        Self {
290            source_name: String::new(),
291            first_line: 0,
292            last_line: 0,
293            num_params: 0,
294            is_vararg: 0,
295            max_stack_size: 0,
296            nested_functions: Vec::new(),
297            upvalues: Vec::new(),
298            local_vars: Vec::new(),
299            line_info: Vec::new(),
300            co_argcount: 0,
301            co_nlocal: 0,
302            co_stacks: 0,
303            num_upval: 0,
304            co_code: Vec::new(),
305            co_consts: Vec::new(),
306            upvalue_n: 0,
307        }
308    }
309}