use proc_macro2::TokenStream;
use quote::quote;
mod parse;
#[derive(Default)]
pub(super) struct RumaEnumAttrs {
pub(super) rename_all: RenameAll,
}
pub(super) struct UnitVariant {
pub(super) ident: syn::Ident,
rename: Option<syn::LitStr>,
pub(super) aliases: Vec<syn::LitStr>,
}
impl UnitVariant {
pub(super) fn string_representation(&self, rename_all: &RenameAll) -> String {
if let Some(rename) = &self.rename {
rename.value()
} else {
rename_all.apply(&self.ident.to_string())
}
}
}
pub(super) struct VariantWithSingleField {
pub(super) ident: syn::Ident,
pub(super) field: syn::Field,
}
impl VariantWithSingleField {
pub(super) fn expand_variable(&self) -> TokenStream {
let ident = &self.ident;
match &self.field.ident {
Some(field) => quote! { #ident { #field: inner } },
None => quote! { #ident (inner) },
}
}
}
#[derive(Default)]
pub(super) struct RenameAll {
prefix: Option<syn::LitStr>,
rule: RenameRule,
}
impl RenameAll {
pub(super) fn apply(&self, variant: &str) -> String {
let mut renamed = self.rule.apply(variant);
if let Some(prefix) = &self.prefix {
renamed = format!("{}{renamed}", prefix.value());
}
renamed
}
}
#[derive(Copy, Clone, Default, PartialEq)]
pub(super) enum RenameRule {
#[default]
None,
LowerCase,
Uppercase,
CamelCase,
SnakeCase,
ScreamingSnakeCase,
KebabCase,
}
impl RenameRule {
fn split_variant_name(variant: &str, separator: char) -> String {
let mut s = String::with_capacity(variant.len());
for (i, ch) in variant.char_indices() {
if i > 0 && ch.is_uppercase() {
s.push(separator);
}
s.push(ch.to_ascii_lowercase());
}
s
}
pub(super) fn apply(&self, variant: &str) -> String {
match *self {
Self::None => variant.to_owned(),
Self::LowerCase => variant.to_ascii_lowercase(),
Self::Uppercase => variant.to_ascii_uppercase(),
Self::CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
Self::SnakeCase => Self::split_variant_name(variant, '_'),
Self::ScreamingSnakeCase => Self::SnakeCase.apply(variant).to_ascii_uppercase(),
Self::KebabCase => Self::split_variant_name(variant, '-'),
}
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::{RenameAll, RenameRule};
#[test]
fn rename_all_apply() {
let variant = "VeryTasty";
let rename_all = RenameAll::default();
assert_eq!(rename_all.apply(variant), variant);
let rename_all = RenameAll { rule: RenameRule::ScreamingSnakeCase, ..Default::default() };
assert_eq!(rename_all.apply(variant), "VERY_TASTY");
let rename_all = RenameAll { rule: RenameRule::SnakeCase, ..Default::default() };
assert_eq!(rename_all.apply(variant), "very_tasty");
let rename_all = RenameAll { prefix: Some(parse_quote!("m.rule.")), ..Default::default() };
assert_eq!(rename_all.apply(variant), "m.rule.VeryTasty");
let rename_all = RenameAll { prefix: Some(parse_quote!("M_")), ..Default::default() };
assert_eq!(rename_all.apply(variant), "M_VeryTasty");
let rename_all = RenameAll {
prefix: Some(parse_quote!("m.rule.")),
rule: RenameRule::ScreamingSnakeCase,
};
assert_eq!(rename_all.apply(variant), "m.rule.VERY_TASTY");
let rename_all =
RenameAll { prefix: Some(parse_quote!("m.rule.")), rule: RenameRule::SnakeCase };
assert_eq!(rename_all.apply(variant), "m.rule.very_tasty");
let rename_all =
RenameAll { prefix: Some(parse_quote!("M_")), rule: RenameRule::ScreamingSnakeCase };
assert_eq!(rename_all.apply(variant), "M_VERY_TASTY");
let rename_all =
RenameAll { prefix: Some(parse_quote!("M_")), rule: RenameRule::SnakeCase };
assert_eq!(rename_all.apply(variant), "M_very_tasty");
}
#[test]
fn rename_rule_apply() {
for &(original, lower, upper, camel, snake, screaming, kebab) in &[
("Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome"),
(
"VeryTasty",
"verytasty",
"VERYTASTY",
"veryTasty",
"very_tasty",
"VERY_TASTY",
"very-tasty",
),
("A", "a", "A", "a", "a", "A", "a"),
("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42"),
] {
assert_eq!(RenameRule::None.apply(original), original);
assert_eq!(RenameRule::LowerCase.apply(original), lower);
assert_eq!(RenameRule::Uppercase.apply(original), upper);
assert_eq!(RenameRule::CamelCase.apply(original), camel);
assert_eq!(RenameRule::SnakeCase.apply(original), snake);
assert_eq!(RenameRule::ScreamingSnakeCase.apply(original), screaming);
assert_eq!(RenameRule::KebabCase.apply(original), kebab);
}
}
}