use std::any::Any;
use std::sync::{atomic::AtomicUsize, Arc};
use inflector::Inflector;
use proc_macro2::Ident as Ident2;
use crate::config::MetaType;
use crate::traits::{NameBuilder as NameBuilderTrait, Naming as NamingTrait};
use crate::TypeIdent;
use super::{Name, NameBuilder};
#[derive(Debug, Clone)]
pub struct ExplicitNaming {
id: Arc<AtomicUsize>,
unify_names: bool,
element_field_postfix: Option<String>,
attribute_field_postfix: Option<String>,
}
impl ExplicitNaming {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn unify_names(mut self, value: bool) -> Self {
self.unify_names = value;
self
}
#[must_use]
pub fn with_element_field_postfix<S: Into<String>>(mut self, postfix: S) -> Self {
self.element_field_postfix = Some(postfix.into());
self
}
#[must_use]
pub fn with_attribute_field_postfix<S: Into<String>>(mut self, postfix: S) -> Self {
self.attribute_field_postfix = Some(postfix.into());
self
}
}
impl Default for ExplicitNaming {
fn default() -> Self {
Self {
id: Arc::new(AtomicUsize::new(0)),
unify_names: true,
element_field_postfix: None,
attribute_field_postfix: None,
}
}
}
impl NamingTrait for ExplicitNaming {
fn clone_boxed(&self) -> Box<dyn NamingTrait> {
Box::new(self.clone())
}
fn builder(&self) -> Box<dyn NameBuilderTrait> {
Box::new(ExplicitNameBuilder::new(
self.id.clone(),
self.clone_boxed(),
))
}
fn unify(&self, s: &str) -> String {
if self.unify_names {
super::unify_string(s)
} else {
s.replace(|c: char| !c.is_alphanumeric(), "_")
}
}
fn make_type_name(&self, postfixes: &[String], ty: &MetaType, ident: &TypeIdent) -> Name {
let _ty = ty;
let postfix = postfixes.get(ident.type_ as usize).map(String::as_str);
let s = self.format_type_name(ident.name.as_str());
Name::new_generated(if let Some(postfix) = postfix {
format!("{s}{postfix}")
} else {
s
})
}
fn make_unknown_variant(&self, id: usize) -> Ident2 {
super::format_unknown_variant(id)
}
fn format_module_name(&self, s: &str) -> String {
let s = self.unify(s).to_snake_case();
super::format_ident(s)
}
fn format_type_name(&self, s: &str) -> String {
let s = self.unify(s);
super::format_ident(s)
}
fn format_field_name(&self, s: &str) -> String {
let s = self.unify(s).to_snake_case();
super::format_ident(s)
}
fn format_variant_name(&self, s: &str) -> String {
let s = self.unify(s);
super::format_ident(s)
}
fn format_constant_name(&self, s: &str) -> String {
let s = self.unify(s).to_screaming_snake_case();
super::format_ident(s)
}
fn format_element_field_name(&self, s: &str) -> String {
if let Some(postfix) = &self.element_field_postfix {
self.format_field_name(&format!("{s}{postfix}"))
} else {
self.format_field_name(s)
}
}
fn format_attribute_field_name(&self, s: &str) -> String {
if let Some(postfix) = &self.attribute_field_postfix {
self.format_field_name(&format!("{s}{postfix}"))
} else {
self.format_field_name(s)
}
}
}
#[must_use]
#[derive(Debug, Clone)]
pub struct ExplicitNameBuilder(NameBuilder);
impl ExplicitNameBuilder {
pub fn new(id: Arc<AtomicUsize>, naming: Box<dyn NamingTrait>) -> Self {
Self(NameBuilder::new(id, naming))
}
}
impl NameBuilderTrait for ExplicitNameBuilder {
#[inline]
fn finish(&self) -> Name {
self.0.finish()
}
#[inline]
fn merge(&mut self, other: &dyn NameBuilderTrait) {
let other: &Self = (other as &dyn Any).downcast_ref().unwrap();
self.0.merge(&other.0);
}
#[inline]
fn clone_boxed(&self) -> Box<dyn NameBuilderTrait> {
Box::new(self.clone())
}
#[inline]
fn has_name(&self) -> bool {
self.0.has_name()
}
#[inline]
fn has_extension(&self) -> bool {
self.0.has_extension()
}
#[inline]
fn set_name(&mut self, name: String) {
self.0.set_name(name);
}
#[inline]
fn set_with_id(&mut self, value: bool) {
self.0.set_with_id(value);
}
#[inline]
fn set_generated(&mut self, value: bool) {
self.0.set_generated(value);
}
#[inline]
fn add_extension(&mut self, replace: bool, extension: String) {
self.0.add_extension(replace, extension);
}
#[inline]
fn strip_suffix(&mut self, suffix: &str) {
let _suffix = suffix;
}
fn generate_unique_id(&mut self) {
self.0.generate_unique_id();
}
fn prepare_type_name(&mut self) {}
fn prepare_field_name(&mut self) {}
fn prepare_content_type_name(&mut self) {}
}