Skip to main content

vercel_rpc_cli/parser/
types.rs

1use syn::{Fields, FieldsNamed, Type};
2
3use super::serde as serde_attr;
4use crate::model::{FieldDef, RustType};
5
6/// Converts a `syn::Type` into our `RustType` representation.
7///
8/// Handles paths (simple and generic), references, tuples, arrays, and unit.
9/// Unknown or unsupported types fall back to their token representation.
10pub fn extract_rust_type(ty: &Type) -> RustType {
11    match ty {
12        Type::Path(type_path) => {
13            let segment = type_path
14                .path
15                .segments
16                .last()
17                .expect("Type::Path always has at least one segment");
18            let name = segment.ident.to_string();
19            let generics = extract_generic_args(&segment.arguments);
20
21            if generics.is_empty() {
22                RustType::simple(name)
23            } else {
24                RustType::with_generics(name, generics)
25            }
26        }
27
28        Type::Reference(type_ref) => extract_rust_type(&type_ref.elem),
29
30        Type::Tuple(tuple) => {
31            if tuple.elems.is_empty() {
32                RustType::simple("()")
33            } else {
34                let inner: Vec<RustType> = tuple.elems.iter().map(extract_rust_type).collect();
35                RustType::with_generics("tuple", inner)
36            }
37        }
38
39        Type::Array(array) => {
40            let elem = extract_rust_type(&array.elem);
41            RustType::with_generics("Array", vec![elem])
42        }
43
44        Type::Slice(slice) => {
45            let elem = extract_rust_type(&slice.elem);
46            RustType::with_generics("Array", vec![elem])
47        }
48
49        _ => {
50            let token_str = quote::quote!(#ty).to_string();
51            RustType::simple(token_str)
52        }
53    }
54}
55
56/// Extracts generic type arguments from a path segment (e.g. `<String, i32>`).
57fn extract_generic_args(arguments: &syn::PathArguments) -> Vec<RustType> {
58    match arguments {
59        syn::PathArguments::AngleBracketed(args) => args
60            .args
61            .iter()
62            .filter_map(|arg| match arg {
63                syn::GenericArgument::Type(ty) => Some(extract_rust_type(ty)),
64                _ => None,
65            })
66            .collect(),
67        _ => vec![],
68    }
69}
70
71/// Extracts named fields from a struct/variant into `FieldDef` values,
72/// including serde attributes (`rename`, `skip`, `default`).
73pub fn extract_struct_fields(fields: &Fields) -> Vec<FieldDef> {
74    match fields {
75        Fields::Named(FieldsNamed { named, .. }) => named
76            .iter()
77            .filter_map(|f| {
78                let name = f.ident.as_ref()?.to_string();
79                let ty = extract_rust_type(&f.ty);
80                let rename = serde_attr::parse_rename(&f.attrs);
81                let skip = serde_attr::is_skipped(&f.attrs);
82                let has_default = serde_attr::has_default(&f.attrs);
83                Some(FieldDef {
84                    name,
85                    ty,
86                    rename,
87                    skip,
88                    has_default,
89                })
90            })
91            .collect(),
92        _ => vec![],
93    }
94}