use rlua::prelude::*;
use crate::bindings::system::LuaMetadata;
use std::{fs, path};
use std::sync::Arc;
pub struct LuaPath(pub path::PathBuf);
impl LuaUserData for LuaPath {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("file_stem", |_, this: &LuaPath, _:() |{
Ok(this.0.file_stem().map(|p| p.to_str().map(|s| s.to_string())))
});
methods.add_method("file_name", |_, this: &LuaPath, _:() |{
Ok(this.0.file_name().map(|p| p.to_str().map(|s| s.to_string())))
});
methods.add_method("ext", |_, this: &LuaPath, _:() |{
Ok(this.0.extension().map(|p| p.to_str().map(|s| s.to_string())))
});
methods.add_method("exists", |_, this: &LuaPath, _:() |{
Ok(this.0.exists())
});
methods.add_method("is_dir", |_, this: &LuaPath, _:() |{
Ok(this.0.is_dir())
});
methods.add_method("is_file", |_, this: &LuaPath, _:() |{
Ok(this.0.is_file())
});
methods.add_method("create_file", |_, this: &LuaPath, _: ()| {
fs::OpenOptions::new()
.write(true)
.create(true)
.open(this.0.as_path())
.map(|_| ())
.map_err(LuaError::external)
});
methods.add_method("create_dir", |_, this: &LuaPath, opt: Option<bool>| {
match opt {
Some(true) => fs::create_dir_all(this.0.as_path()).map_err(LuaError::external),
_ => fs::create_dir(this.0.as_path()).map_err(LuaError::external)
}
});
methods.add_method("remove", |_, this: &LuaPath, opt: Option<bool>| {
if this.0.exists() {
if this.0.is_file() {
return fs::remove_file(&this.0).map_err(LuaError::external);
} else if this.0.is_dir() {
return match opt {
Some(true) => fs::remove_dir_all(&this.0).map_err(LuaError::external),
_ => fs::remove_dir(&this.0).map_err(LuaError::external)
};
}
}
Ok(())
});
methods.add_method("is_relative", |_, this: &LuaPath, _:() |{
Ok(this.0.is_relative())
});
methods.add_method("is_absolute", |_, this: &LuaPath, _:() |{
Ok(this.0.is_absolute())
});
methods.add_method("has_root", |_, this: &LuaPath, _:() |{
Ok(this.0.has_root())
});
methods.add_method("parent", |_, this: &LuaPath, _:() |{
Ok(this.0.parent().map(|p| LuaPath(p.to_path_buf())))
});
methods.add_method_mut("push", |_, this: &mut LuaPath, val: String |{
Ok(this.0.push(&val))
});
methods.add_method("join", |_, this: &LuaPath, path: String |{
Ok(LuaPath(this.0.join(path)))
});
methods.add_method("metadata", |_, this: &LuaPath, _:() |{
Ok(LuaMetadata(this.0.metadata().map_err(LuaError::external)?))
});
methods.add_method("canonicalize", |_, this: &LuaPath, _:() |{
fs::canonicalize(&this.0).map(|can| can.to_str().map(|s| s.to_string())).map_err(LuaError::external)
});
methods.add_method("read_dir", |lua, this: &LuaPath, _: ()| {
match this.0.read_dir() {
Ok(iter) => {
let mut arc_iter = Arc::new(Some(iter));
let f = move |_, _: ()| {
let result = match Arc::get_mut(&mut arc_iter).expect("entries iterator is mutably borrowed") {
Some(iter) => iter.next().map(|entry| entry.map(|e| LuaPath(e.path())).ok()),
None => None
};
if result.is_none() { *Arc::get_mut(&mut arc_iter).unwrap() = None; }
Ok(result)
};
Ok(lua.create_function_mut(f)?)
}, Err(err) => Err(LuaError::external(err))
}
});
methods.add_meta_method(LuaMetaMethod::ToString, |_, this: &LuaPath, _: ()| {
Ok(this.0.to_str().map(|s| s.to_string()))
});
}
}
pub fn init(lua: &Lua) -> crate::Result<()> {
let module = lua.create_table()?;
module.set("empty", lua.create_function( |_, _: ()| {
Ok(LuaPath(path::PathBuf::new()))
})? )?;
module.set("new", lua.create_function( |_, path: String| {
Ok(LuaPath(path::Path::new(&path).to_path_buf()))
})? )?;
lua.globals().set("path", module)?;
Ok(())
}