forked from proxmox-mirrors/proxmox
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)?;
|
let (pat_type, pat) = check_input_type(input)?;
|
||||||
|
|
||||||
// For any named type which exists on the function signature...
|
// 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())
|
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:
|
// 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 {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -442,13 +442,18 @@ pub fn derive_descriptions(
|
|||||||
Ok(())
|
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 {
|
if let SchemaItem::Inferred(_) = schema.item {
|
||||||
//
|
//
|
||||||
} else {
|
} 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:
|
// infer the type from a rust type:
|
||||||
match ty {
|
match ty {
|
||||||
syn::Type::Path(path) if path.qself.is_none() => {
|
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 {
|
pub struct Foo {
|
||||||
/// A test string.
|
/// A test string.
|
||||||
test: String,
|
test: String,
|
||||||
|
|
||||||
|
/// An optional auto-derived value for testing:
|
||||||
|
another: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// generates the following without the '_' prefix in the constant:
|
// generates the following without the '_' prefix in the constant:
|
||||||
|
Loading…
Reference in New Issue
Block a user