api-macro: allow external schemas in 'returns' specification
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
bf84e75603
commit
76641b0a72
@ -11,7 +11,7 @@ use std::mem;
|
|||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
use syn::ext::IdentExt;
|
use syn::ext::IdentExt;
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::visit_mut::{self, VisitMut};
|
use syn::visit_mut::{self, VisitMut};
|
||||||
@ -20,16 +20,53 @@ use syn::Ident;
|
|||||||
use super::{ObjectEntry, Schema, SchemaItem, SchemaObject};
|
use super::{ObjectEntry, Schema, SchemaItem, SchemaObject};
|
||||||
use crate::util::{self, FieldName, JSONObject, JSONValue, Maybe};
|
use crate::util::{self, FieldName, JSONObject, JSONValue, Maybe};
|
||||||
|
|
||||||
|
/// A return type in a schema can have an `optional` flag. Other than that it is just a regular
|
||||||
|
/// schema, but we also want to be able to reference external `ReturnType` values for this.
|
||||||
|
pub enum ReturnType {
|
||||||
|
Explicit(ReturnSchema),
|
||||||
|
Extern(syn::Expr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType {
|
||||||
|
fn as_mut_schema(&mut self) -> Option<&mut Schema> {
|
||||||
|
match self {
|
||||||
|
ReturnType::Explicit(ReturnSchema { ref mut schema, .. }) => Some(schema),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<JSONValue> for ReturnType {
|
||||||
|
type Error = syn::Error;
|
||||||
|
|
||||||
|
fn try_from(value: JSONValue) -> Result<Self, syn::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
JSONValue::Object(obj) => ReturnType::Explicit(obj.try_into()?),
|
||||||
|
JSONValue::Expr(ext) => ReturnType::Extern(ext),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnType {
|
||||||
|
fn to_schema(&self, ts: &mut TokenStream) -> Result<(), Error> {
|
||||||
|
match self {
|
||||||
|
ReturnType::Explicit(exp) => exp.to_schema(ts)?,
|
||||||
|
ReturnType::Extern(exp) => exp.to_tokens(ts),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A return type in a schema can have an `optional` flag. Other than that it is just a regular
|
/// A return type in a schema can have an `optional` flag. Other than that it is just a regular
|
||||||
/// schema.
|
/// schema.
|
||||||
pub struct ReturnType {
|
pub struct ReturnSchema {
|
||||||
/// If optional, we store `Some(span)`, otherwise `None`.
|
/// If optional, we store `Some(span)`, otherwise `None`.
|
||||||
optional: Option<Span>,
|
optional: Option<Span>,
|
||||||
|
|
||||||
schema: Schema,
|
schema: Schema,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnType {
|
impl ReturnSchema {
|
||||||
fn to_schema(&self, ts: &mut TokenStream) -> Result<(), Error> {
|
fn to_schema(&self, ts: &mut TokenStream) -> Result<(), Error> {
|
||||||
let optional = match self.optional {
|
let optional = match self.optional {
|
||||||
Some(span) => quote_spanned! { span => true },
|
Some(span) => quote_spanned! { span => true },
|
||||||
@ -46,17 +83,9 @@ impl ReturnType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<JSONValue> for ReturnType {
|
/// To go from a `JSONObject` to a `ReturnSchema` we first extract the `optional` flag, then forward
|
||||||
type Error = syn::Error;
|
|
||||||
|
|
||||||
fn try_from(value: JSONValue) -> Result<Self, syn::Error> {
|
|
||||||
Self::try_from(value.into_object("a return type definition")?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// To go from a `JSONObject` to a `ReturnType` we first extract the `optional` flag, then forward
|
|
||||||
/// to the `Schema` parser.
|
/// to the `Schema` parser.
|
||||||
impl TryFrom<JSONObject> for ReturnType {
|
impl TryFrom<JSONObject> for ReturnSchema {
|
||||||
type Error = syn::Error;
|
type Error = syn::Error;
|
||||||
|
|
||||||
fn try_from(mut obj: JSONObject) -> Result<Self, syn::Error> {
|
fn try_from(mut obj: JSONObject) -> Result<Self, syn::Error> {
|
||||||
@ -110,7 +139,7 @@ pub fn handle_method(mut attribs: JSONObject, mut func: syn::ItemFn) -> Result<T
|
|||||||
|
|
||||||
let mut return_type: Option<ReturnType> = attribs
|
let mut return_type: Option<ReturnType> = attribs
|
||||||
.remove("returns")
|
.remove("returns")
|
||||||
.map(|ret| ret.into_object("return schema definition")?.try_into())
|
.map(|ret| ret.try_into())
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
let access_setter = match attribs.remove("access") {
|
let access_setter = match attribs.remove("access") {
|
||||||
@ -151,7 +180,7 @@ pub fn handle_method(mut attribs: JSONObject, mut func: syn::ItemFn) -> Result<T
|
|||||||
let (doc_comment, doc_span) = util::get_doc_comments(&func.attrs)?;
|
let (doc_comment, doc_span) = util::get_doc_comments(&func.attrs)?;
|
||||||
util::derive_descriptions(
|
util::derive_descriptions(
|
||||||
&mut input_schema,
|
&mut input_schema,
|
||||||
return_type.as_mut().map(|rs| &mut rs.schema),
|
return_type.as_mut().and_then(ReturnType::as_mut_schema),
|
||||||
&doc_comment,
|
&doc_comment,
|
||||||
doc_span,
|
doc_span,
|
||||||
)?;
|
)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user