From cddd4800cb57a570b621b79459e712c75b8fcb75 Mon Sep 17 00:00:00 2001 From: Juha Kukkonen Date: Wed, 16 Feb 2022 23:53:48 +0200 Subject: [PATCH] Enhance the tag & default tag support (#29) * Remove Tag and DefaultTag traits along with the need for those traits * Remove useless assert struct * Make path to be more neutral about its location -> allows path macro attributed methods within methods where as previously they needed to exists only in module level --- src/lib.rs | 10 +--------- tests/path_derive.rs | 13 ++++++------- tests/utoipa_gen_test.rs | 2 -- utoipa-gen/src/lib.rs | 6 +++++- utoipa-gen/src/openapi.rs | 26 +++++--------------------- utoipa-gen/src/path.rs | 24 ++++++------------------ 6 files changed, 23 insertions(+), 58 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index edc9f90f..c87f4628 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,13 +235,5 @@ pub trait Component { pub trait Path { fn path() -> &'static str; - fn path_item() -> openapi::path::PathItem; -} - -pub trait DefaultTag { - fn tag() -> &'static str; -} - -pub trait Tag { - fn tag() -> &'static str; + fn path_item(defalt_tag: Option<&str>) -> openapi::path::PathItem; } diff --git a/tests/path_derive.rs b/tests/path_derive.rs index e6020b40..bf4ad1f6 100644 --- a/tests/path_derive.rs +++ b/tests/path_derive.rs @@ -123,15 +123,14 @@ fn derive_path_with_all_info_success() { } } -test_api_fn! { - name: test_operation3, - module: derive_path_with_defaults, - operation: post, - path: "/foo/bar"; -} - #[test] fn derive_path_with_defaults_success() { + test_api_fn! { + name: test_operation3, + module: derive_path_with_defaults, + operation: post, + path: "/foo/bar"; + } let operation = test_api_fn_doc! { derive_path_with_defaults::test_operation3, operation: post, diff --git a/tests/utoipa_gen_test.rs b/tests/utoipa_gen_test.rs index ee4b6b00..ceda215f 100644 --- a/tests/utoipa_gen_test.rs +++ b/tests/utoipa_gen_test.rs @@ -1,8 +1,6 @@ #![cfg(feature = "actix_extras")] #![allow(dead_code)] -use std::borrow::Cow; - use serde::{Deserialize, Serialize}; use utoipa::{Component, OpenApi}; diff --git a/utoipa-gen/src/lib.rs b/utoipa-gen/src/lib.rs index 4ce12d31..2a4f0bdc 100644 --- a/utoipa-gen/src/lib.rs +++ b/utoipa-gen/src/lib.rs @@ -1,4 +1,8 @@ -//! This is private utoipa codegen library and is not used alone +//! This is **private** utoipa codegen library and is not used alone +//! +//! The library contains macro implementations for utoipa library. Content +//! of the libarary documentation is available through **utoipa** library itself. +//! Consider browsing via the **utoipa** crate so all links will work correctly. #![warn(missing_docs)] #![warn(rustdoc::broken_intra_doc_links)] diff --git a/utoipa-gen/src/openapi.rs b/utoipa-gen/src/openapi.rs index 13bd0af4..6f221a20 100644 --- a/utoipa-gen/src/openapi.rs +++ b/utoipa-gen/src/openapi.rs @@ -172,7 +172,7 @@ impl ToTokens for OpenApi { }, ); - let path_items = impl_paths(&attributes.handlers, tokens); + let path_items = impl_paths(&attributes.handlers); tokens.extend(quote! { impl utoipa::OpenApi for #ident { @@ -186,14 +186,14 @@ impl ToTokens for OpenApi { } } -fn impl_paths(handler_paths: &[ExprPath], quote: &mut TokenStream) -> TokenStream { +fn impl_paths(handler_paths: &[ExprPath]) -> TokenStream { handler_paths.iter().fold( quote! { utoipa::openapi::path::Paths::new() }, |mut paths, handler| { let segments = handler.path.segments.iter().collect::>(); let handler_fn_name = &*segments.last().unwrap().ident.to_string(); - let tag = segments + let tag = &*segments .iter() .take(segments.len() - 1) .map(|part| part.ident.to_string()) @@ -205,12 +205,7 @@ fn impl_paths(handler_paths: &[ExprPath], quote: &mut TokenStream) -> TokenStrea let usage = syn::parse_str::( &vec![ - if tag.starts_with("crate") { - None - } else { - Some("crate") - }, - if tag.is_empty() { None } else { Some(&tag) }, + if tag.is_empty() { None } else { Some(tag) }, Some(handler_ident_name), ] .into_iter() @@ -220,19 +215,8 @@ fn impl_paths(handler_paths: &[ExprPath], quote: &mut TokenStream) -> TokenStrea ) .unwrap(); - let assert_handler_ident = format_ident!("__assert_{}", handler_ident_name); - quote.extend(quote! { - #[allow(non_camel_case_types)] - struct #assert_handler_ident where #handler_ident : utoipa::Path; - use #usage; - impl utoipa::DefaultTag for #handler_ident { - fn tag() -> &'static str { - #tag - } - } - }); paths.extend(quote! { - .append(#handler_ident::path(), #handler_ident::path_item()) + .append(#usage::path(), #usage::path_item(Some(#tag))) }); paths diff --git a/utoipa-gen/src/path.rs b/utoipa-gen/src/path.rs index a721be22..5a89e2df 100644 --- a/utoipa-gen/src/path.rs +++ b/utoipa-gen/src/path.rs @@ -355,7 +355,7 @@ impl ToTokens for Path { .as_ref() .or(Some(&self.fn_name)) .expect_or_abort("expected to find operation id but was None"); - let tag = self + let tag = &*self .path_attr .tag .as_ref() @@ -375,7 +375,6 @@ impl ToTokens for Path { .expect_or_abort("expected to find path but was None"); let operation = Operation { - path_struct: &path_struct, deprecated: &self.deprecated, operation_id, summary: self @@ -392,22 +391,19 @@ impl ToTokens for Path { #[allow(non_camel_case_types)] pub struct #path_struct; - impl utoipa::Tag for #path_struct { - fn tag() -> &'static str { - #tag - } - } - impl utoipa::Path for #path_struct { fn path() -> &'static str { #path } - fn path_item() -> utoipa::openapi::path::PathItem { + fn path_item(default_tag: Option<&str>) -> utoipa::openapi::path::PathItem { use utoipa::openapi::ToArray; utoipa::openapi::PathItem::new( #path_operation, - #operation + #operation.with_tag(*[Some(#tag), default_tag, Some("crate")].iter() + .flatten() + .find(|t| !t.is_empty()).unwrap() + ) ) } } @@ -416,7 +412,6 @@ impl ToTokens for Path { } struct Operation<'a> { - path_struct: &'a Ident, operation_id: &'a String, summary: Option<&'a String>, description: Option<&'a Vec>, @@ -441,15 +436,8 @@ impl ToTokens for Operation<'_> { .with_responses(#responses) }); // // .with_security() - let path_struct = self.path_struct; let operation_id = self.operation_id; tokens.extend(quote! { - .with_tag( - [<#path_struct as utoipa::Tag>::tag(), - <#path_struct as utoipa::DefaultTag>::tag() - ] - .into_iter().find(|s| !s.is_empty()).unwrap_or_else(|| "crate") - ) .with_operation_id( #operation_id )