api-macro: more option type handling
infer_type now also returns whether it was encapsualted in an Option<>. So `type: String, optional: true` is now inferred propertly from `Option<String>`. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
45af06f090
commit
3626f57d2c
@ -140,11 +140,14 @@ fn handle_function_signature(
|
||||
let (pat_type, pat) = check_input_type(input)?;
|
||||
|
||||
// For any named type which exists on the function signature...
|
||||
if let Some((_ident, _optional, ref mut schema)) =
|
||||
if let Some((_ident, optional, ref mut schema)) =
|
||||
input_schema.find_obj_property_by_ident_mut(&pat.ident.to_string())
|
||||
{
|
||||
// try to infer the type in the schema if it is not specified explicitly:
|
||||
util::infer_type(schema, &*pat_type.ty)?;
|
||||
let is_option = util::infer_type(schema, &*pat_type.ty)?;
|
||||
if !is_option && *optional {
|
||||
bail!(pat_type => "non-optional `Option` type");
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
@ -442,13 +442,18 @@ pub fn derive_descriptions(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn infer_type(schema: &mut Schema, ty: &syn::Type) -> Result<(), Error> {
|
||||
pub fn infer_type(schema: &mut Schema, ty: &syn::Type) -> Result<bool, Error> {
|
||||
if let SchemaItem::Inferred(_) = schema.item {
|
||||
//
|
||||
} else {
|
||||
return Ok(());
|
||||
return Ok(is_option_type(ty).is_some());
|
||||
}
|
||||
|
||||
let (ty, is_option) = match is_option_type(ty) {
|
||||
Some(ty) => (ty, true),
|
||||
None => (ty, false),
|
||||
};
|
||||
|
||||
// infer the type from a rust type:
|
||||
match ty {
|
||||
syn::Type::Path(path) if path.qself.is_none() => {
|
||||
@ -467,5 +472,32 @@ pub fn infer_type(schema: &mut Schema, ty: &syn::Type) -> Result<(), Error> {
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(is_option)
|
||||
}
|
||||
|
||||
/// Note that we cannot handle renamed imports at all here...
|
||||
fn is_option_type(ty: &syn::Type) -> Option<&syn::Type> {
|
||||
if let syn::Type::Path(p) = ty {
|
||||
if p.qself.is_some() {
|
||||
return None;
|
||||
}
|
||||
let segs = &p.path.segments;
|
||||
let is_option = match segs.len() {
|
||||
1 => segs.last().unwrap().ident == "Option",
|
||||
2 => segs.first().unwrap().ident == "std" && segs.last().unwrap().ident == "Option",
|
||||
_ => false,
|
||||
};
|
||||
if !is_option {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let syn::PathArguments::AngleBracketed(generic) = &segs.last().unwrap().arguments {
|
||||
if generic.args.len() == 1 {
|
||||
if let syn::GenericArgument::Type(ty) = generic.args.first().unwrap() {
|
||||
return Some(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ pub struct OkString(String);
|
||||
pub struct Foo {
|
||||
/// A test string.
|
||||
test: String,
|
||||
|
||||
/// An optional auto-derived value for testing:
|
||||
another: Option<String>,
|
||||
}
|
||||
|
||||
// generates the following without the '_' prefix in the constant:
|
||||
|
Loading…
Reference in New Issue
Block a user