From caecf9edd1e1f233ff333ce756db6707fa5fd19e Mon Sep 17 00:00:00 2001 From: Erica Marigold <hi@devcomp.xyz> Date: Sun, 21 Jan 2024 01:39:29 +0530 Subject: [PATCH] feat: buffer support for @lune/fs * fs.readFile now returns a buffer, instead of a string * fs.writeFile now accepts a string or a buffer for the contents argument --- src/lune/builtins/fs/mod.rs | 47 +++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/lune/builtins/fs/mod.rs b/src/lune/builtins/fs/mod.rs index 210608d..0d1fd8f 100644 --- a/src/lune/builtins/fs/mod.rs +++ b/src/lune/builtins/fs/mod.rs @@ -14,6 +14,19 @@ use copy::copy; use metadata::FsMetadata; use options::FsWriteOptions; +const BYTES_TO_BUF_IMPL: &str = r#" + local tbl = select(1, ...) + local buf = buffer.create(#tbl * 4) -- Each u32 is 4 bytes + + for offset, byte in tbl do + buffer.writeu32(buf, offset, byte) + end + + return buf +"#; + +const BUF_TO_STR_IMPL: &str = "return buffer.tostring(select(1, ...))"; + pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> { TableBuilder::new(lua)? .with_async_function("readFile", fs_read_file)? @@ -30,9 +43,24 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> { .build_readonly() } -async fn fs_read_file(lua: &Lua, path: String) -> LuaResult<LuaString> { +fn create_lua_buffer(lua: &Lua, bytes: impl AsRef<[u8]>) -> LuaResult<LuaValue> { + let lua_bytes = bytes.as_ref().into_lua(lua)?; + + let buf_constructor = lua.load(BYTES_TO_BUF_IMPL).into_function()?; + + buf_constructor.call::<_, LuaValue>(lua_bytes) +} + +fn buf_to_str(lua: &Lua, buf: LuaValue<'_>) -> LuaResult<String> { + let str_constructor = lua.load(BUF_TO_STR_IMPL).into_function()?; + + str_constructor.call(buf) +} + +async fn fs_read_file(lua: &Lua, path: String) -> LuaResult<LuaValue> { let bytes = fs::read(&path).await.into_lua_err()?; - lua.create_string(bytes) + + create_lua_buffer(lua, bytes) } async fn fs_read_dir(_: &Lua, path: String) -> LuaResult<Vec<String>> { @@ -64,8 +92,19 @@ async fn fs_read_dir(_: &Lua, path: String) -> LuaResult<Vec<String>> { Ok(dir_strings_no_prefix) } -async fn fs_write_file(_: &Lua, (path, contents): (String, LuaString<'_>)) -> LuaResult<()> { - fs::write(&path, &contents.as_bytes()).await.into_lua_err() +async fn fs_write_file(lua: &Lua, (path, contents): (String, LuaValue<'_>)) -> LuaResult<()> { + let contents_str = match contents { + LuaValue::String(str) => Ok(str.to_str()?.to_string()), + LuaValue::UserData(inner) => Ok(buf_to_str(lua, LuaValue::UserData(inner))?), + other => Err(LuaError::runtime(format!( + "Expected type string or buffer, got {}", + other.type_name() + ))), + }?; + + fs::write(&path, contents_str.as_bytes()) + .await + .into_lua_err() } async fn fs_write_dir(_: &Lua, path: String) -> LuaResult<()> {