api-macro: factor out type inference for reuse with structs

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-01-07 13:09:08 +01:00
parent b9769de6b6
commit e960a68b60
3 changed files with 45 additions and 36 deletions

View File

@ -47,7 +47,7 @@ pub struct Schema {
pub description: Option<syn::LitStr>,
/// The specific schema type (Object, String, ...)
item: SchemaItem,
pub item: SchemaItem,
/// The remaining key-value pairs the `SchemaItem` parser did not extract will be appended as
/// builder-pattern method calls to this schema.
@ -100,6 +100,15 @@ impl TryFrom<JSONObject> for Schema {
}
impl Schema {
fn blank(span: Span) -> Self {
Self {
span,
description: None,
item: SchemaItem::Inferred(span),
properties: Vec::new(),
}
}
fn to_typed_schema(&self, ts: &mut TokenStream) -> Result<(), Error> {
self.item.to_schema(
ts,
@ -148,7 +157,7 @@ impl Schema {
}
}
enum SchemaItem {
pub enum SchemaItem {
Null,
Boolean,
Integer,
@ -317,7 +326,7 @@ impl SchemaItem {
#[derive(Default)]
/// Contains a sorted list of properties:
struct SchemaObject {
pub struct SchemaObject {
properties: Vec<(FieldName, bool, Schema)>,
}
@ -388,7 +397,7 @@ impl SchemaObject {
}
}
struct SchemaArray {
pub struct SchemaArray {
item: Box<Schema>,
}

View File

@ -140,42 +140,14 @@ fn handle_function_signature(
let (pat_type, pat) = check_input_type(input)?;
// For any named type which exists on the function signature...
let schema: &mut Schema = if let Some((_ident, _optional, schema)) =
if let Some((_ident, _optional, ref mut schema)) =
input_schema.find_obj_property_by_ident_mut(&pat.ident.to_string())
{
match &mut schema.item {
// ... if it has no `type` property (item = SchemaItem::Inferred), get a mutable
// reference to the schema, so that we can...
SchemaItem::Inferred(_span) => schema,
// other types are fine:
_ => continue,
}
// try to infer the type in the schema if it is not specified explicitly:
util::infer_type(schema, &*pat_type.ty)?;
} else {
continue;
};
// ... infer the type from the function parameters:
match &*pat_type.ty {
syn::Type::Path(path) if path.qself.is_none() => {
if path.path.is_ident("String") {
schema.item = SchemaItem::String;
continue;
} else if path.path.is_ident("bool") {
schema.item = SchemaItem::Boolean;
continue;
} else if super::INTNAMES.iter().any(|n| path.path.is_ident(n)) {
schema.item = SchemaItem::Integer;
continue;
} else if super::NUMBERNAMES.iter().any(|n| path.path.is_ident(n)) {
schema.item = SchemaItem::Number;
continue;
}
}
_ => (),
}
// if we can't, bail out:
bail!(&pat_type.ty => "cannot infer parameter type from this rust type");
}
for input in sig.inputs.iter() {

View File

@ -10,7 +10,7 @@ use syn::Token;
use failure::Error;
use crate::api::Schema;
use crate::api::{self, Schema, SchemaItem};
/// A more relaxed version of Ident which allows hyphens.
///
@ -441,3 +441,31 @@ pub fn derive_descriptions(
Ok(())
}
pub fn infer_type(schema: &mut Schema, ty: &syn::Type) -> Result<(), Error> {
if let SchemaItem::Inferred(_) = schema.item {
//
} else {
return Ok(());
}
// infer the type from a rust type:
match ty {
syn::Type::Path(path) if path.qself.is_none() => {
if path.path.is_ident("String") {
schema.item = SchemaItem::String;
} else if path.path.is_ident("bool") {
schema.item = SchemaItem::Boolean;
} else if api::INTNAMES.iter().any(|n| path.path.is_ident(n)) {
schema.item = SchemaItem::Integer;
} else if api::NUMBERNAMES.iter().any(|n| path.path.is_ident(n)) {
schema.item = SchemaItem::Number;
} else {
bail!(ty => "cannot infer parameter type from this rust type");
}
}
_ => (),
}
Ok(())
}