use crate::dir_context::DirContext;
use crate::types::FileRef;
use mlua::{IntoLua, Lua};
use serde::{Serialize, Serializer};
use simple_fs::SPath;
#[derive(Debug)]
pub struct FileInfo {
pub path: String,
pub dir: String,
pub name: String,
pub stem: String,
pub ext: String,
pub ctime: Option<i64>, pub mtime: Option<i64>,
pub size: Option<i64>, pub is_likely_text: bool,
}
pub struct WithMeta<'a> {
full_path: Option<&'a SPath>,
with_meta: bool,
}
impl From<bool> for WithMeta<'_> {
fn from(with_meta: bool) -> Self {
WithMeta {
full_path: None,
with_meta,
}
}
}
impl<'a> From<&'a SPath> for WithMeta<'a> {
fn from(full_path: &'a SPath) -> Self {
WithMeta {
full_path: Some(full_path),
with_meta: true,
}
}
}
impl FileInfo {
pub fn new<'a>(dir_context: &DirContext, rel_path: impl Into<SPath>, with_meta: impl Into<WithMeta<'a>>) -> Self {
let path: SPath = rel_path.into();
let path = dir_context.maybe_home_path_into_tilde(path);
let with_meta: WithMeta = with_meta.into();
if with_meta.with_meta {
let mut res = FileInfo::from_path(path.clone());
let full_path = match with_meta.full_path {
Some(full_path) => full_path.clone(),
None => dir_context.maybe_tilde_path_into_home(path),
};
if let Ok(meta) = full_path.meta() {
res.ctime = Some(meta.created_epoch_us);
res.mtime = Some(meta.modified_epoch_us);
res.size = Some(meta.size as i64);
res.is_likely_text = full_path.is_likely_text();
}
res
} else {
FileInfo::from_path(path)
}
}
pub fn from_file_ref(dir_context: &DirContext, file_ref: FileRef) -> Self {
let smeta = file_ref.smeta;
let spath = dir_context.maybe_home_path_into_tilde(file_ref.spath.clone());
let mut file_info = FileInfo::from_path(spath);
if let Some(smeta) = smeta {
file_info.ctime = Some(smeta.created_epoch_us);
file_info.mtime = Some(smeta.modified_epoch_us);
file_info.size = Some(smeta.size as i64);
file_info.is_likely_text = file_ref.spath.is_likely_text();
}
file_info
}
fn from_path(file: SPath) -> Self {
let dir = file.parent().map(|p| p.to_string()).unwrap_or_default();
let is_likely_text = file.is_likely_text();
FileInfo {
path: file.to_string(),
name: file.name().to_string(),
dir,
stem: file.stem().to_string(),
ext: file.ext().to_string(),
ctime: None,
mtime: None,
size: None,
is_likely_text,
}
}
}
impl Serialize for FileInfo {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct("FileInfo", 10)?;
state.serialize_field("_type", "FileInfo")?;
state.serialize_field("path", &self.path)?;
state.serialize_field("dir", &self.dir)?;
state.serialize_field("name", &self.name)?;
state.serialize_field("stem", &self.stem)?;
state.serialize_field("ext", &self.ext)?;
if let Some(ctime) = self.ctime {
state.serialize_field("ctime", &ctime)?;
}
if let Some(mtime) = self.mtime {
state.serialize_field("mtime", &mtime)?;
}
if let Some(size) = self.size {
state.serialize_field("size", &size)?;
}
state.serialize_field("is_likely_text", &self.is_likely_text)?;
state.end()
}
}
impl IntoLua for FileInfo {
fn into_lua(self, lua: &Lua) -> mlua::Result<mlua::Value> {
let table = lua.create_table()?;
table.set("_type", "FileInfo")?;
table.set("path", self.path)?;
table.set("dir", self.dir)?;
table.set("name", self.name)?;
table.set("stem", self.stem)?;
table.set("ext", self.ext)?;
if let Some(ctime) = self.ctime {
table.set("ctime", ctime)?;
}
if let Some(mtime) = self.mtime {
table.set("mtime", mtime)?;
}
if let Some(size) = self.size {
table.set("size", size)?;
}
table.set("is_likely_text", self.is_likely_text)?;
Ok(mlua::Value::Table(table))
}
}