prebindgen_flat/
types_util.rs1use proc_macro2::Span;
7
8pub fn option_inner_type(ty: &syn::Type) -> Option<syn::Type> {
10 generic_inner(ty, "Option")
11}
12
13pub fn vec_inner_type(ty: &syn::Type) -> Option<syn::Type> {
15 generic_inner(ty, "Vec")
16}
17
18fn generic_inner(ty: &syn::Type, wrapper: &str) -> Option<syn::Type> {
19 let syn::Type::Path(tp) = ty else { return None };
20 let seg = tp.path.segments.last()?;
21 if seg.ident != wrapper {
22 return None;
23 }
24 let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
25 return None;
26 };
27 match ab.args.first()? {
28 syn::GenericArgument::Type(inner) => Some(inner.clone()),
29 _ => None,
30 }
31}
32
33pub fn path_tail_ident(ty: &syn::Type) -> Option<syn::Ident> {
37 match ty {
38 syn::Type::Path(tp) => tp.path.segments.last().map(|s| s.ident.clone()),
39 _ => None,
40 }
41}
42
43fn path_tail_is(ty: &syn::Type, name: &str) -> bool {
45 path_tail_ident(ty).is_some_and(|i| i == name)
46}
47
48pub fn is_result_type(ty: &syn::Type) -> bool {
50 path_tail_is(ty, "Result")
51}
52
53pub fn result_parts(ty: &syn::Type) -> Option<(syn::Type, syn::Type)> {
55 let syn::Type::Path(tp) = ty else { return None };
56 let seg = tp.path.segments.last()?;
57 if seg.ident != "Result" {
58 return None;
59 }
60 let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
61 return None;
62 };
63 let mut args = ab.args.iter().filter_map(|a| match a {
64 syn::GenericArgument::Type(t) => Some(t.clone()),
65 _ => None,
66 });
67 let ok = args.next()?;
68 let err = args.next()?;
69 Some((ok, err))
70}
71
72pub fn result_ok_type(ty: &syn::Type) -> Option<syn::Type> {
74 result_parts(ty).map(|(ok, _)| ok)
75}
76
77pub fn bare_path_ident(ty: &syn::Type) -> Option<syn::Ident> {
91 let syn::Type::Path(tp) = ty else { return None };
92 let seg = tp.path.segments.last()?;
93 if !matches!(seg.arguments, syn::PathArguments::None) {
94 return None;
95 }
96 Some(seg.ident.clone())
97}
98
99pub fn ident(s: &str) -> syn::Ident {
104 syn::Ident::new(s, Span::call_site())
105}
106
107pub fn pascal_to_snake(s: &str) -> String {
112 let mut out = String::new();
113 for (i, c) in s.chars().enumerate() {
114 if c.is_uppercase() {
115 if i != 0 {
116 out.push('_');
117 }
118 out.extend(c.to_lowercase());
119 } else {
120 out.push(c);
121 }
122 }
123 out
124}
125
126#[cfg(test)]
127mod tests;