use syn::{
Ident,
Type,
TypePath,
Path,
PathSegment,
PathArguments,
AngleBracketedGenericArguments,
GenericArgument,
Field,
};
fn inner_option_type(path: &Path) -> Option<&Type> {
match path {
Path {leading_colon: None, segments} if segments.len() == 1 => {
let last = segments.last().unwrap();
match last {
PathSegment {
ident: type_name,
arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
colon2_token: None,
args,
..
}),
} if type_name == "Option" && args.len() == 1 => {
match args.last().unwrap() {
GenericArgument::Type(ty) => Some(ty),
_ => None,
}
},
_ => None,
}
},
_ => None,
}
}
pub struct ComponentField<'a> {
pub ident: &'a Ident,
pub ty: &'a Type,
pub is_optional: bool,
}
impl<'a> From<&'a Field> for ComponentField<'a> {
fn from(Field {ident, ty, ..}: &'a Field) -> Self {
let (ty, is_optional) = match ty {
Type::Path(TypePath {
qself: None,
path,
}) => match inner_option_type(path) {
Some(ty) => (ty, true),
_ => (ty, false),
},
_ => (ty, false),
};
Self {
ident: ident.as_ref().unwrap(),
ty,
is_optional,
}
}
}