use darling::FromMeta;
use quote::format_ident;
use syn::{Expr, Ident, Type};
pub fn qualify_type_with_crate(ty: &Type) -> Type {
if let Type::Path(type_path) = ty {
if let Some(first_seg) = type_path.path.segments.first() {
let first_str = first_seg.ident.to_string();
if first_str == "crate" || first_str == "super" || first_str == "self" {
return ty.clone();
}
}
if type_path.path.leading_colon.is_some() {
return ty.clone();
}
let mut qualified_path = type_path.clone();
let crate_segment: syn::PathSegment = syn::parse_quote!(crate);
qualified_path.path.segments.insert(0, crate_segment);
Type::Path(qualified_path)
} else {
ty.clone()
}
}
pub fn make_packed_type(ty: &Type) -> Option<Type> {
let qualified = qualify_type_with_crate(ty);
if let Type::Path(type_path) = &qualified {
let mut packed_path = type_path.clone();
if let Some(last_seg) = packed_path.path.segments.last_mut() {
let packed_name = format_ident!("Packed{}", last_seg.ident);
last_seg.ident = packed_name;
}
Some(Type::Path(packed_path))
} else {
None
}
}
pub fn ident_to_type(ident: &Ident) -> Type {
let path: syn::Path = ident.clone().into();
Type::Path(syn::TypePath { qself: None, path })
}
#[derive(Clone)]
pub struct MetaExpr(Expr);
impl FromMeta for MetaExpr {
fn from_expr(expr: &Expr) -> darling::Result<Self> {
Ok(MetaExpr(expr.clone()))
}
}
impl From<MetaExpr> for Expr {
fn from(meta: MetaExpr) -> Expr {
meta.0
}
}
#[inline]
pub fn is_constant_identifier(ident: &str) -> bool {
if ident.is_empty() {
return false;
}
let mut chars = ident.chars();
let first = chars.next().unwrap();
if first == '_' {
match chars.next() {
Some(c) if c.is_uppercase() => {}
_ => return false, }
} else if !first.is_uppercase() {
return false;
}
chars.all(|c| c.is_uppercase() || c == '_' || c.is_ascii_digit())
}
#[inline]
pub fn is_base_path(expr: &Expr, base: &str) -> bool {
matches!(expr, Expr::Path(p) if p.path.segments.first().is_some_and(|s| s.ident == base))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_constant_identifier() {
assert!(is_constant_identifier("MY_CONSTANT"));
assert!(is_constant_identifier("SEED"));
assert!(is_constant_identifier("SEED_123"));
assert!(is_constant_identifier("A"));
assert!(is_constant_identifier("_UNDERSCORE_CONST"));
assert!(is_constant_identifier("_A"));
assert!(is_constant_identifier("_SEED_PREFIX"));
assert!(!is_constant_identifier("myVariable"));
assert!(!is_constant_identifier("my_variable"));
assert!(!is_constant_identifier("MyConstant"));
assert!(!is_constant_identifier(""));
assert!(!is_constant_identifier("_")); assert!(!is_constant_identifier("_lowercase")); assert!(!is_constant_identifier("_mixedCase")); }
}