Created
April 1, 2024 19:29
-
-
Save pyrrho/3f3c12f065eba3bacad91422c5980b2a to your computer and use it in GitHub Desktop.
syn type extraction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fn is_option(ty: &syn::Type) -> bool { | |
// TODO: static this (Arc<Mutex<...>>?) | |
let valid_option_idents: [&[syn::Ident]; 3] = [ | |
&[syn::parse_quote!(Option)], | |
&[ | |
syn::parse_quote!(std), | |
syn::parse_quote!(option), | |
syn::parse_quote!(Option), | |
], | |
&[ | |
syn::parse_quote!(core), | |
syn::parse_quote!(option), | |
syn::parse_quote!(Option), | |
], | |
]; | |
let ty_path = match ty { | |
syn::Type::Path(syn::TypePath { qself: None, path }) => path, | |
_ => return false, | |
}; | |
'outer: for option_idents in valid_option_idents { | |
if option_idents.len() != ty_path.segments.len() { | |
continue; | |
} | |
let ty_idents = ty_path.segments.iter().map(|s| &s.ident); | |
for (oi, ti) in option_idents.iter().zip(ty_idents) { | |
if oi != ti { | |
continue 'outer; | |
} | |
} | |
return true; | |
} | |
false | |
} | |
fn is_vec(ty: &syn::Type) -> bool { | |
// TODO: static this (Arc<Mutex<...>>?) | |
let valid_vec_idents: [&[syn::Ident]; 3] = [ | |
&[syn::parse_quote!(Vec)], | |
&[ | |
syn::parse_quote!(std), | |
syn::parse_quote!(vec), | |
syn::parse_quote!(Vec), | |
], | |
&[ | |
syn::parse_quote!(alloc), | |
syn::parse_quote!(vec), | |
syn::parse_quote!(Vec), | |
], | |
]; | |
let ty_path = match ty { | |
syn::Type::Path(syn::TypePath { qself: None, path }) => path, | |
_ => return false, | |
}; | |
'outer: for vec_idents in valid_vec_idents { | |
if vec_idents.len() != ty_path.segments.len() { | |
continue; | |
} | |
let ty_idents = ty_path.segments.iter().map(|s| &s.ident); | |
for (vi, ti) in vec_idents.iter().zip(ty_idents) { | |
if vi != ti { | |
continue 'outer; | |
} | |
} | |
return true; | |
} | |
false | |
} | |
fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> { | |
if !is_option(ty) { | |
return None; | |
} | |
let ty_path = match ty { | |
syn::Type::Path(syn::TypePath { qself: None, path }) => path, | |
_ => return None, | |
}; | |
let option_segment = ty_path.segments.last().unwrap(); | |
let generic_args = match &option_segment.arguments { | |
syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { | |
args: generic_args, | |
.. | |
}) => generic_args, | |
_ => return None, | |
}; | |
if generic_args.len() != 1 { | |
return None; | |
} | |
return match &generic_args[0] { | |
syn::GenericArgument::Type(ty) => Some(ty), | |
_ => None, | |
}; | |
} | |
fn extract_type_from_vec(ty: &syn::Type) -> Option<&syn::Type> { | |
if !is_vec(ty) { | |
return None; | |
} | |
let ty_path = match ty { | |
syn::Type::Path(syn::TypePath { qself: None, path }) => path, | |
_ => return None, | |
}; | |
let vec_segment = ty_path.segments.last().unwrap(); | |
let generic_args = match &vec_segment.arguments { | |
syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { | |
args: generic_args, | |
.. | |
}) => generic_args, | |
_ => return None, | |
}; | |
if generic_args.len() != 1 { | |
return None; | |
} | |
return match &generic_args[0] { | |
syn::GenericArgument::Type(ty) => Some(ty), | |
_ => None, | |
}; | |
} | |
#[test] | |
fn test_extract_type_from_option() { | |
assert_eq!( | |
extract_type_from_option(&syn::parse_quote!(Option<String>)), | |
Some(&syn::parse_quote!(String)) | |
); | |
assert_eq!( | |
extract_type_from_option(&syn::parse_quote!(::Option<some::path::Thing<T>>)), | |
Some(&syn::parse_quote!(some::path::Thing<T>)) | |
); | |
assert_eq!( | |
extract_type_from_option(&syn::parse_quote!(std::option::Option<std::string::String>)), | |
Some(&syn::parse_quote!(std::string::String)) | |
); | |
assert_eq!( | |
extract_type_from_option(&syn::parse_quote!(::core::option::Option<(i32, u32, f64)>)), | |
Some(&syn::parse_quote!((i32, u32, f64))) | |
); | |
assert_eq!(extract_type_from_option(&syn::parse_quote!(Option)), None); | |
assert_eq!( | |
extract_type_from_option(&syn::parse_quote!(Vec<String>)), | |
None | |
); | |
} | |
#[test] | |
fn test_extract_type_from_vec() { | |
assert_eq!( | |
extract_type_from_vec(&syn::parse_quote!(Vec<String>)), | |
Some(&syn::parse_quote!(String)) | |
); | |
assert_eq!( | |
extract_type_from_vec(&syn::parse_quote!(::Vec<some::path::Thing<T>>)), | |
Some(&syn::parse_quote!(some::path::Thing<T>)) | |
); | |
assert_eq!( | |
extract_type_from_vec(&syn::parse_quote!(std::vec::Vec<std::string::String>)), | |
Some(&syn::parse_quote!(std::string::String)) | |
); | |
assert_eq!( | |
extract_type_from_vec(&syn::parse_quote!(::alloc::vec::Vec<(i32, u32, f64)>)), | |
Some(&syn::parse_quote!((i32, u32, f64))) | |
); | |
assert_eq!(extract_type_from_vec(&syn::parse_quote!(Vec)), None); | |
assert_eq!( | |
extract_type_from_vec(&syn::parse_quote!(Option<String>)), | |
None | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment