feat: add to_snake_case_string and to_snake_case_trait dependencies

This commit is contained in:
Andrew Phillips
2025-08-27 12:15:48 -03:00
committed by Andrew Phillips (aider)
parent 90fd8d013d
commit 091634433b
5 changed files with 16 additions and 99 deletions

16
Cargo.lock generated
View File

@@ -1368,6 +1368,8 @@ dependencies = [
"term 1.1.0",
"termsize",
"thiserror 1.0.69",
"to_snake_case_string",
"to_snake_case_trait",
"tokio",
"tokio-stream",
"tokio-util",
@@ -2511,6 +2513,20 @@ dependencies = [
"zerovec",
]
[[package]]
name = "to_snake_case_string"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.105",
"to_snake_case_trait",
]
[[package]]
name = "to_snake_case_trait"
version = "0.1.0"
[[package]]
name = "tokio"
version = "1.47.1"

View File

@@ -1,13 +0,0 @@
[package]
name = "to_snake_case_string"
version = "0.1.0"
edition = "2024"
[lib]
proc-macro = true
[dependencies]
syn = { version = "2.0", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"
to_snake_case_trait = { path = "../to_snake_case_trait" }

View File

@@ -1,79 +0,0 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput};
/// This is the derive macro function.
/// The `#[proc_macro_derive(ToSnakeCaseString)]` attribute tells the compiler
/// that this function implements the derive macro for the `ToSnakeCaseString` trait.
#[proc_macro_derive(ToSnakeCaseString)]
pub fn to_snake_case_string_derive(input: TokenStream) -> TokenStream {
// Parse the input tokens into a syntax tree
let ast = parse_macro_input!(input as DeriveInput);
// Get the name of the enum we're deriving for
let name = &ast.ident;
// Ensure we're working with an enum
let data_enum = match ast.data {
Data::Enum(data) => data,
_ => panic!("ToSnakeCaseString can only be derived for enums"),
};
// Iterate over the enum variants and generate a match arm for each one
let match_arms = data_enum.variants.iter().map(|variant| {
let variant_ident = &variant.ident;
// Convert the PascalCase variant name to snake_case for the string literal
let snake_case_string = to_snake_case(variant_ident.to_string());
// Generate the code for a single match arm, e.g.,
// `Self::MyVariant => "my_variant".to_string(),`
// We ignore variant fields (e.g., `MyVariant(u32)`) by using `..`
quote! {
#name::#variant_ident { .. } => #snake_case_string.to_string(),
}
});
// Generate the full implementation of the trait for the enum
let generated = quote! {
// This is the implementation of our custom trait
impl to_snake_case_trait::ToSnakeCaseString for #name {
// This is the implementation of the trait's method
fn to_snake_case(&self) -> String {
match self {
// Expand the generated match arms inside the match block
#( #match_arms )*
}
}
}
// We can also optionally implement the standard `ToString` or `Display` trait
impl std::string::ToString for #name {
fn to_string(&self) -> String {
self.to_snake_case()
}
}
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_snake_case())
}
}
};
// Return the generated code as a TokenStream
generated.into()
}
/// Helper function to convert a PascalCase string to a snake_case string.
fn to_snake_case(pascal_case: String) -> String {
let mut snake = String::new();
for (i, ch) in pascal_case.chars().enumerate() {
if i > 0 && ch.is_uppercase() {
snake.push('_');
}
snake.push(ch.to_ascii_lowercase());
}
snake
}

View File

@@ -1,4 +0,0 @@
[package]
name = "to_snake_case_trait"
version = "0.1.0"
edition = "2024"

View File

@@ -1,3 +0,0 @@
pub trait ToSnakeCaseString {
fn to_snake_case(&self) -> String;
}