Skip to content

Instantly share code, notes, and snippets.

@pyrrho
Created April 1, 2024 19:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pyrrho/3f3c12f065eba3bacad91422c5980b2a to your computer and use it in GitHub Desktop.
Save pyrrho/3f3c12f065eba3bacad91422c5980b2a to your computer and use it in GitHub Desktop.
syn type extraction
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