use std::path::{Path, PathBuf};
use super::config::PastaConfig;
#[derive(Debug, Clone)]
pub struct LoaderContext {
pub base_dir: PathBuf,
pub lua_search_paths: Vec<String>,
pub custom_fields: toml::Table,
}
impl LoaderContext {
pub fn new(
base_dir: impl Into<PathBuf>,
lua_search_paths: Vec<String>,
custom_fields: toml::Table,
) -> Self {
Self {
base_dir: base_dir.into(),
lua_search_paths,
custom_fields,
}
}
pub fn from_config(base_dir: &Path, config: &PastaConfig) -> Self {
let abs_base = base_dir
.canonicalize()
.unwrap_or_else(|_| base_dir.to_path_buf());
let abs_base = Self::strip_windows_prefix(&abs_base);
Self {
base_dir: abs_base,
lua_search_paths: config.loader.lua_search_paths.clone(),
custom_fields: config.custom_fields.clone(),
}
}
#[cfg(windows)]
fn strip_windows_prefix(path: &Path) -> PathBuf {
let path_str = path.to_string_lossy();
if let Some(stripped) = path_str.strip_prefix(r"\\?\") {
PathBuf::from(stripped)
} else {
path.to_path_buf()
}
}
#[cfg(not(windows))]
fn strip_windows_prefix(path: &Path) -> PathBuf {
path.to_path_buf()
}
pub fn absolute_search_paths(&self) -> Vec<PathBuf> {
self.lua_search_paths
.iter()
.map(|p| self.base_dir.join(p))
.collect()
}
pub fn generate_package_path(&self) -> String {
self.lua_search_paths
.iter()
.flat_map(|p| {
let abs_path = self.base_dir.join(p);
let path_str = abs_path.to_string_lossy().replace('\\', "/");
vec![
format!("{}/?.lua", path_str),
format!("{}/?/init.lua", path_str),
]
})
.collect::<Vec<_>>()
.join(";")
}
pub fn generate_package_path_bytes(&self) -> std::io::Result<Vec<u8>> {
let path_str = self.generate_package_path();
crate::encoding::to_ansi_bytes(&path_str)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let ctx = LoaderContext::new(
"/ghost/master",
vec!["scripts".to_string(), "lib".to_string()],
toml::Table::new(),
);
assert_eq!(ctx.base_dir, PathBuf::from("/ghost/master"));
assert_eq!(ctx.lua_search_paths, vec!["scripts", "lib"]);
assert!(ctx.custom_fields.is_empty());
}
#[test]
fn test_absolute_search_paths() {
let ctx = LoaderContext::new(
"/ghost/master",
vec!["profile/pasta/save/lua".to_string(), "scripts".to_string()],
toml::Table::new(),
);
let paths = ctx.absolute_search_paths();
assert_eq!(paths.len(), 2);
assert_eq!(
paths[0],
PathBuf::from("/ghost/master/profile/pasta/save/lua")
);
assert_eq!(paths[1], PathBuf::from("/ghost/master/scripts"));
}
#[test]
fn test_generate_package_path() {
let ctx = LoaderContext::new(
"/ghost/master",
vec!["scripts".to_string(), "lib".to_string()],
toml::Table::new(),
);
let path = ctx.generate_package_path();
assert!(path.contains("/ghost/master/scripts/?.lua"));
assert!(path.contains("/ghost/master/lib/?.lua"));
assert!(path.contains(";"));
}
#[test]
fn test_from_config() {
let config = PastaConfig::default();
let ctx = LoaderContext::from_config(Path::new("/ghost/master"), &config);
assert_eq!(ctx.lua_search_paths, config.loader.lua_search_paths);
assert!(ctx.custom_fields.is_empty());
}
#[test]
fn test_from_config_with_custom_fields() {
let mut custom = toml::Table::new();
custom.insert(
"ghost_name".to_string(),
toml::Value::String("Test".to_string()),
);
let config = PastaConfig {
loader: super::super::config::LoaderConfig::default(),
custom_fields: custom.clone(),
};
let ctx = LoaderContext::from_config(Path::new("/ghost/master"), &config);
assert_eq!(ctx.custom_fields, custom);
}
#[test]
fn test_generate_package_path_bytes_ascii() {
let ctx = LoaderContext::new(
"/ghost/master",
vec!["scripts".to_string()],
toml::Table::new(),
);
let bytes = ctx.generate_package_path_bytes().unwrap();
let expected = ctx.generate_package_path();
assert_eq!(bytes, expected.as_bytes());
}
#[test]
fn test_generate_package_path_bytes_not_empty() {
let ctx = LoaderContext::new(
"/ghost/master",
vec!["scripts".to_string(), "lib".to_string()],
toml::Table::new(),
);
let bytes = ctx.generate_package_path_bytes().unwrap();
assert!(!bytes.is_empty());
assert!(bytes.contains(&b';'));
}
#[cfg(windows)]
#[test]
fn test_generate_package_path_bytes_japanese() {
let ctx = LoaderContext::new(
"C:\\ユーザー\\テスト",
vec!["scripts".to_string()],
toml::Table::new(),
);
let bytes = ctx.generate_package_path_bytes().unwrap();
assert!(!bytes.is_empty());
let utf8_bytes = ctx.generate_package_path().into_bytes();
assert_ne!(bytes, utf8_bytes);
}
}