use super::*;
use std::sync::Arc;
use std::{fs, io::BufReader};
use std::{os::unix::fs::PermissionsExt, path::PathBuf};
pub struct FSFile(fs::File);
impl From<fs::File> for FSFile {
fn from(value: fs::File) -> Self {
Self(value)
}
}
impl LuaUserData for FSFile {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method_mut("write", |_, this, data: String| {
this.0.write_all(data.as_bytes())?;
Ok(())
});
methods.add_method_mut("read_line", |_, this, _: ()| {
let mut buf = BufReader::new(this.0.try_clone()?);
let mut str = String::new();
buf.read_line(&mut str)?;
Ok(str.trim().to_owned())
});
methods.add_method_mut("read_all", |_, this, _: ()| {
let mut str = String::new();
this.0.read_to_string(&mut str)?;
Ok(str)
});
methods.add_method_mut("flush", |_, this, _: ()| {
this.0.flush()?;
Ok(())
});
methods.add_method("metadata", |_, this, _: ()| {
Ok(Metadata(this.0.metadata()?))
});
}
}
pub struct Directory(fs::ReadDir);
impl LuaUserData for Directory {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method_mut("next", |_, this, _: ()| match this.0.next() {
Some(Ok(entry)) => Ok(Some(DirectoryEntry(entry))),
Some(Err(e)) => Err(LuaError::external(Arc::new(e))),
None => Ok(None),
});
}
}
pub struct DirectoryEntry(fs::DirEntry);
impl LuaUserData for DirectoryEntry {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method("path", |_, this, _: ()| Ok(this.0.path()));
methods.add_method("metadata", |_, this, _: ()| {
Ok(Metadata(this.0.metadata()?))
});
}
}
pub struct Metadata(std::fs::Metadata);
impl LuaUserData for Metadata {
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method("is_file", |_, this, _: ()| Ok(this.0.is_file()));
methods.add_method("is_symlink", |_, this, _: ()| Ok(this.0.is_symlink()));
methods.add_method("is_dir", |_, this, _: ()| Ok(this.0.is_dir()));
}
}
pub struct Fs;
impl Module for Fs {
fn load(&self, state: &mut State) -> Result<(), LuaError> {
let module = state.lua.create_table()?;
module.set(
"create",
state
.lua
.create_function(|_, path: PathBuf| match fs::File::create(path) {
Ok(f) => Ok(FSFile::from(f)),
Err(e) => Err(e.into()),
})?,
)?;
module.set(
"open",
state
.lua
.create_function(|_, path: PathBuf| match fs::File::open(path) {
Ok(f) => Ok(FSFile::from(f)),
Err(e) => Err(e.into()),
})?,
)?;
module.set(
"exists",
state
.lua
.create_function(|_, path: PathBuf| match fs::exists(path) {
Ok(b) => Ok(b),
Err(e) => Err(e.into()),
})?,
)?;
module.set(
"rename",
state
.lua
.create_function(|_, (from, to): (PathBuf, PathBuf)| {
match fs::rename(from, to) {
Ok(_) => Ok(()),
Err(e) => Err(e.into()),
}
})?,
)?;
module.set(
"copy",
state
.lua
.create_function(
|_, (from, to): (PathBuf, PathBuf)| match fs::copy(from, to) {
Ok(written) => Ok(written),
Err(e) => Err(e.into()),
},
)?,
)?;
module.set(
"remove",
state
.lua
.create_function(|_, (path, recursive): (PathBuf, Option<bool>)| {
let metadata = match fs::metadata(&path) {
Ok(m) => m,
Err(e) => return Err(e.into()),
};
let recursive = recursive.unwrap_or(false);
let mut result = Ok(());
if metadata.is_dir() {
if recursive {
if let Err(e) = fs::remove_dir_all(path) {
result = Err(e.into())
}
} else if let Err(e) = fs::remove_dir(path) {
result = Err(e.into())
}
} else if let Err(e) = fs::remove_file(path) {
result = Err(e.into())
}
result
})?,
)?;
module.set(
"mkdir",
state.lua.create_function(|_, path: PathBuf| {
fs::create_dir_all(path)?;
Ok(())
})?,
)?;
module.set(
"set_mode",
state
.lua
.create_function(|_, (path, mode): (PathBuf, u32)| {
fs::set_permissions(path, std::fs::Permissions::from_mode(mode))?;
Ok(())
})?,
)?;
module.set(
"symlink",
state
.lua
.create_function(|_, (from, to): (PathBuf, PathBuf)| {
std::os::unix::fs::symlink(from, to)?;
Ok(())
})?,
)?;
module.set(
"canonicalize",
state
.lua
.create_function(|_, path: PathBuf| Ok(fs::canonicalize(path)?))?,
)?;
module.set(
"follow_link",
state
.lua
.create_function(|_, path: PathBuf| Ok(fs::read_link(path)?))?,
)?;
module.set(
"read_dir",
state
.lua
.create_function(|_, path: PathBuf| Ok(Directory(fs::read_dir(path)?)))?,
)?;
create_module(&state.lua, "autosway.fs", module)?;
Ok(())
}
}