miniextendr_macros/
naming.rs1pub(crate) fn r_wrapper_const_ident_for(rust_ident: &syn::Ident) -> syn::Ident {
11 let upper = rust_ident.to_string().to_uppercase();
12 quote::format_ident!("R_WRAPPER_{upper}")
13}
14
15pub(crate) fn crate_prefix() -> String {
51 std::env::var("CARGO_CRATE_NAME").unwrap_or_else(|_| {
52 std::env::var("CARGO_PKG_NAME")
53 .map(|n| n.replace('-', "_"))
54 .unwrap_or_else(|_| "crate".to_string())
55 })
56}
57
58pub(crate) fn bare_fn_c_wrapper_ident(rust_ident: &syn::Ident) -> syn::Ident {
62 let prefix = crate_prefix();
63 quote::format_ident!("C_{prefix}_{rust_ident}")
64}
65
66pub(crate) fn impl_method_c_wrapper_ident(
69 type_ident: &syn::Ident,
70 label: Option<&str>,
71 method_ident: &syn::Ident,
72) -> syn::Ident {
73 let prefix = crate_prefix();
74 if let Some(label) = label {
75 quote::format_ident!("C_{prefix}_{type_ident}_{label}_{method_ident}")
76 } else {
77 quote::format_ident!("C_{prefix}_{type_ident}__{method_ident}")
78 }
79}
80
81pub(crate) fn trait_member_c_wrapper_string(
86 type_ident: &syn::Ident,
87 trait_name: &syn::Ident,
88 member_ident: &syn::Ident,
89) -> String {
90 let prefix = crate_prefix();
91 format!("C_{prefix}_{type_ident}__{trait_name}__{member_ident}")
92}
93
94pub(crate) fn trait_member_c_wrapper_ident(
97 type_ident: &syn::Ident,
98 trait_name: &syn::Ident,
99 member_ident: &syn::Ident,
100) -> syn::Ident {
101 quote::format_ident!(
102 "{}",
103 trait_member_c_wrapper_string(type_ident, trait_name, member_ident)
104 )
105}
106
107pub(crate) fn sidecar_getter_c_name(type_name: &str, field_name: &str) -> String {
109 let prefix = crate_prefix();
110 format!("C_{prefix}__mx_rdata_get_{type_name}_{field_name}")
111}
112
113pub(crate) fn sidecar_setter_c_name(type_name: &str, field_name: &str) -> String {
115 let prefix = crate_prefix();
116 format!("C_{prefix}__mx_rdata_set_{type_name}_{field_name}")
117}
118
119pub(crate) fn altrep_reg_fn_ident(ident: &syn::Ident) -> syn::Ident {
121 let prefix = crate_prefix();
122 quote::format_ident!("__mx_altrep_reg_{prefix}_{ident}")
123}
124
125pub(crate) fn vtable_static_ident(trait_name_upper: &str, type_name_str: &str) -> syn::Ident {
131 let crate_upper = crate_prefix().to_uppercase();
132 quote::format_ident!("__VTABLE_{crate_upper}_{trait_name_upper}_FOR_{type_name_str}")
133}
134
135pub(crate) fn vtshim_ident(
137 type_ident: &syn::Ident,
138 trait_name: &syn::Ident,
139 method_ident: &syn::Ident,
140) -> syn::Ident {
141 let prefix = crate_prefix();
142 quote::format_ident!("__vtshim_{prefix}_{type_ident}__{trait_name}__{method_ident}")
143}
144pub(crate) fn to_snake_case(s: &str) -> String {
152 let mut out = String::new();
153 for (i, c) in s.char_indices() {
154 if c.is_uppercase() && i > 0 {
155 out.push('_');
156 }
157 out.extend(c.to_lowercase());
158 }
159 out
160}
161
162pub(crate) fn to_kebab_case(s: &str) -> String {
164 to_snake_case(s).replace('_', "-")
165}
166
167pub(crate) fn apply_rename_all(name: &str, rename_all: Option<&str>) -> String {
172 match rename_all {
173 Some("snake_case") => to_snake_case(name),
174 Some("kebab-case") => to_kebab_case(name),
175 Some("lower") => name.to_lowercase(),
176 Some("upper") => name.to_uppercase(),
177 _ => name.to_string(),
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
192 fn crate_prefix_fallback_is_normalized_pkg_name() {
193 assert_eq!(crate_prefix(), "miniextendr_macros");
194 }
195
196 #[test]
197 fn c_symbols_are_crate_prefixed() {
198 let ty = quote::format_ident!("Counter");
199 let tr = quote::format_ident!("Resettable");
200 let m = quote::format_ident!("reset");
201 assert_eq!(
202 bare_fn_c_wrapper_ident(&m).to_string(),
203 "C_miniextendr_macros_reset"
204 );
205 assert_eq!(
206 impl_method_c_wrapper_ident(&ty, None, &m).to_string(),
207 "C_miniextendr_macros_Counter__reset"
208 );
209 assert_eq!(
210 impl_method_c_wrapper_ident(&ty, Some("basic"), &m).to_string(),
211 "C_miniextendr_macros_Counter_basic_reset"
212 );
213 assert_eq!(
214 trait_member_c_wrapper_string(&ty, &tr, &m),
215 "C_miniextendr_macros_Counter__Resettable__reset"
216 );
217 assert_eq!(
218 trait_member_c_wrapper_ident(&ty, &tr, &m).to_string(),
219 trait_member_c_wrapper_string(&ty, &tr, &m)
220 );
221 assert_eq!(
222 sidecar_getter_c_name("Counter", "count"),
223 "C_miniextendr_macros__mx_rdata_get_Counter_count"
224 );
225 assert_eq!(
226 sidecar_setter_c_name("Counter", "count"),
227 "C_miniextendr_macros__mx_rdata_set_Counter_count"
228 );
229 assert_eq!(
230 altrep_reg_fn_ident(&ty).to_string(),
231 "__mx_altrep_reg_miniextendr_macros_Counter"
232 );
233 assert_eq!(
234 vtable_static_ident("RESETTABLE", "COUNTER").to_string(),
235 "__VTABLE_MINIEXTENDR_MACROS_RESETTABLE_FOR_COUNTER"
236 );
237 assert_eq!(
238 vtshim_ident(&ty, &tr, &m).to_string(),
239 "__vtshim_miniextendr_macros_Counter__Resettable__reset"
240 );
241 }
242
243 #[test]
244 fn snake_case() {
245 assert_eq!(to_snake_case("HelloWorld"), "hello_world");
246 assert_eq!(to_snake_case("InProgress"), "in_progress");
247 assert_eq!(to_snake_case("ABC"), "a_b_c");
248 assert_eq!(to_snake_case("Red"), "red");
249 }
250
251 #[test]
252 fn kebab_case() {
253 assert_eq!(to_kebab_case("HelloWorld"), "hello-world");
254 assert_eq!(to_kebab_case("InProgress"), "in-progress");
255 }
256
257 #[test]
258 fn rename_all() {
259 assert_eq!(
260 apply_rename_all("HelloWorld", Some("snake_case")),
261 "hello_world"
262 );
263 assert_eq!(
264 apply_rename_all("HelloWorld", Some("kebab-case")),
265 "hello-world"
266 );
267 assert_eq!(apply_rename_all("HelloWorld", Some("lower")), "helloworld");
268 assert_eq!(apply_rename_all("HelloWorld", Some("upper")), "HELLOWORLD");
269 assert_eq!(apply_rename_all("HelloWorld", None), "HelloWorld");
270 }
271}