use std::path::Path;
use std::sync::LazyLock;
use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
use serde::Deserialize;
pub static CONFIG: LazyLock<Config> =
LazyLock::new(|| Config::load(Path::new(crate::MANIFEST_DIR.as_str())));
#[derive(Deserialize, Clone, Copy)]
pub enum CaseStyle {
SnakeCase,
CamelCase,
PascalCase,
ScreamingSnakeCase,
Raw,
}
impl CaseStyle {
pub fn format(&self, name: &str) -> String {
match self {
CaseStyle::SnakeCase => name.to_snake_case(),
CaseStyle::CamelCase => name.to_lower_camel_case(),
CaseStyle::PascalCase => name.to_upper_camel_case(),
CaseStyle::ScreamingSnakeCase => name.to_shouty_snake_case(),
CaseStyle::Raw => name.to_string(),
}
}
}
#[derive(Deserialize)]
struct NamingSection {
prefix: Option<String>,
suffix: Option<String>,
case_style: Option<CaseStyle>,
}
#[derive(Deserialize, Default)]
pub struct Config {
#[serde(skip)]
crate_name: String,
types: Option<NamingSection>,
methods: Option<NamingSection>,
fns: Option<NamingSection>,
free_fns: Option<NamingSection>,
}
impl Config {
pub fn load(manifest_dir: &Path) -> Config {
let content = std::fs::read_to_string(manifest_dir.join("ezffi.toml")).unwrap_or_default();
let mut config: Config = toml::from_str(&content).unwrap_or_default();
config.crate_name = crate::PKG_NAME.clone();
config
}
fn resolve_prefix(section: &Option<NamingSection>, default: impl FnOnce() -> String) -> String {
section
.as_ref()
.and_then(|s| s.prefix.clone())
.unwrap_or_else(default)
}
fn resolve_suffix(section: &Option<NamingSection>, default: impl FnOnce() -> String) -> String {
section
.as_ref()
.and_then(|s| s.suffix.clone())
.unwrap_or_else(default)
}
fn resolve_case(section: &Option<NamingSection>, default: CaseStyle) -> CaseStyle {
section
.as_ref()
.and_then(|s| s.case_style)
.unwrap_or(default)
}
pub fn type_prefix(&self) -> String {
Self::resolve_prefix(&self.types, || self.crate_name.clone())
}
pub fn type_suffix(&self) -> String {
Self::resolve_suffix(&self.types, String::new)
}
pub fn type_case_style(&self) -> CaseStyle {
Self::resolve_case(&self.types, CaseStyle::PascalCase)
}
pub fn methods_prefix(&self) -> String {
Self::resolve_prefix(&self.methods, String::new)
}
pub fn methods_suffix(&self) -> String {
Self::resolve_suffix(&self.methods, String::new)
}
pub fn methods_case_style(&self) -> CaseStyle {
Self::resolve_case(&self.methods, CaseStyle::SnakeCase)
}
pub fn fns_prefix(&self) -> String {
Self::resolve_prefix(&self.fns, || format!("{}_", self.crate_name))
}
pub fn fns_suffix(&self) -> String {
Self::resolve_suffix(&self.fns, String::new)
}
pub fn fns_case_style(&self) -> CaseStyle {
Self::resolve_case(&self.fns, CaseStyle::SnakeCase)
}
pub fn free_fns_prefix(&self) -> String {
Self::resolve_prefix(&self.free_fns, String::new)
}
pub fn free_fns_suffix(&self) -> String {
Self::resolve_suffix(&self.free_fns, || String::from("_free"))
}
pub fn free_fns_case_style(&self) -> CaseStyle {
Self::resolve_case(&self.free_fns, CaseStyle::SnakeCase)
}
}