diff --git a/utoipa-gen/CHANGELOG.md b/utoipa-gen/CHANGELOG.md index 32ef963b..6a24e786 100644 --- a/utoipa-gen/CHANGELOG.md +++ b/utoipa-gen/CHANGELOG.md @@ -26,6 +26,7 @@ ### Fixed +* Fix impl `ToSchema` for container types (https://github.com/juhaku/utoipa/pull/1107) * Fix description on `inline` field (https://github.com/juhaku/utoipa/pull/1102) * Fix `title` on unnamed struct and references (https://github.com/juhaku/utoipa/pull/1101) * Fix generic references (https://github.com/juhaku/utoipa/pull/1097) diff --git a/utoipa-gen/src/component.rs b/utoipa-gen/src/component.rs index 4d1118ff..5df329bc 100644 --- a/utoipa-gen/src/component.rs +++ b/utoipa-gen/src/component.rs @@ -1234,7 +1234,7 @@ impl ComponentSchema { utoipa::openapi::schema::ArrayBuilder::new() #nullable_schema_type .items(utoipa::openapi::schema::ArrayItems::False) - .prefix_items(#prefix_items.to_vec()) + .prefix_items(#prefix_items) #description_stream #deprecated }) diff --git a/utoipa-gen/tests/schema_generics.rs b/utoipa-gen/tests/schema_generics.rs index dc68b037..940a294a 100644 --- a/utoipa-gen/tests/schema_generics.rs +++ b/utoipa-gen/tests/schema_generics.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use serde::Serialize; use utoipa::openapi::{Info, RefOr, Schema}; -use utoipa::{schema, OpenApi, ToSchema}; +use utoipa::{schema, OpenApi, PartialSchema, ToSchema}; #[test] fn generic_schema_custom_bound() { @@ -129,6 +129,131 @@ fn schema_with_non_generic_root() { assert_eq!(actual.trim(), expected.trim()) } +#[test] +fn derive_generic_schema_enum_variants() { + #![allow(unused)] + + #[derive(ToSchema)] + pub struct FooStruct { + pub foo: B, + } + + #[derive(ToSchema)] + enum FoosEnum { + ThingNoAliasOption(FooStruct>), + FooEnumThing(#[schema(inline)] FooStruct>), + FooThingOptionVec(#[schema(inline)] FooStruct>>), + FooThingLinkedList(#[schema(inline)] FooStruct>), + FooThingBTreeMap(#[schema(inline)] FooStruct>), + FooThingHashMap(#[schema(inline)] FooStruct>), + FooThingHashSet(#[schema(inline)] FooStruct>), + FooThingBTreeSet(#[schema(inline)] FooStruct>), + } + + let schema = FoosEnum::schema(); + let json = serde_json::to_string_pretty(&schema).expect("Schema is JSON serializable"); + let value = json.trim(); + // println!("{value}"); + + #[derive(OpenApi)] + #[openapi(components(schemas(FoosEnum)))] + struct Api; + + let mut api = Api::openapi(); + api.info = Info::new("title", "version"); + let api_json = api.to_pretty_json().expect("OpenAPI is JSON serializable"); + println!("{api_json}"); + let expected = include_str!("./testdata/schema_generic_enum_variant_with_generic_type"); + assert_eq!(expected.trim(), api_json.trim()); +} + +#[test] +fn high_order_types() { + #![allow(unused)] + + #[derive(ToSchema)] + pub struct High { + high: T, + } + + #[derive(ToSchema)] + pub struct HighBox { + value: High>, + } + + #[derive(ToSchema)] + pub struct HighCow(High>); + + #[derive(ToSchema)] + pub struct HighRefCell(High>); + + #[derive(OpenApi)] + #[openapi(components(schemas(HighBox, HighCow, HighRefCell)))] + struct Api; + + let mut api = Api::openapi(); + api.info = Info::new("title", "version"); + let api_json = api.to_pretty_json().expect("OpenAPI is JSON serializable"); + println!("{api_json}"); + let expected = include_str!("./testdata/schema_high_order_types"); + assert_eq!(expected.trim(), api_json.trim()); +} + +#[test] +#[cfg(feature = "rc_schema")] +fn rc_schema_high_order_types() { + #![allow(unused)] + + #[derive(ToSchema)] + pub struct High { + high: T, + } + + #[derive(ToSchema)] + pub struct HighArc(High>); + + #[derive(ToSchema)] + pub struct HighRc(High>); + + #[derive(OpenApi)] + #[openapi(components(schemas(HighArc, HighRc)))] + struct Api; + + let mut api = Api::openapi(); + api.info = Info::new("title", "version"); + let api_json = api.to_pretty_json().expect("OpenAPI is JSON serializable"); + println!("{api_json}"); + + let expected = include_str!("./testdata/rc_schema_high_order_types"); + assert_eq!(expected.trim(), api_json.trim()); +} + +#[test] +#[ignore = "arrays, slices, tuples as generic argument is not supported at the moment"] +fn slice_generic_args() { + #![allow(unused)] + + #[derive(ToSchema)] + pub struct High { + high: T, + } + + // // #[derive(ToSchema)] + // pub struct HighSlice(High<&'static [i32]>); + // + // #[derive(OpenApi)] + // // #[openapi(components(schemas(HighSlice)))] + // struct Api; + // + // let mut api = Api::openapi(); + // api.info = Info::new("title", "version"); + // let api_json = api.to_pretty_json().expect("OpenAPI is JSON serializable"); + // println!("{api_json}"); + // + // let expected = include_str!("./testdata/rc_schema_high_order_types"); + // assert_eq!(expected.trim(), api_json.trim()); +} + #[test] #[ignore = "For debugging only"] fn schema_macro_run() { diff --git a/utoipa-gen/tests/testdata/rc_schema_high_order_types b/utoipa-gen/tests/testdata/rc_schema_high_order_types new file mode 100644 index 00000000..fec4ce54 --- /dev/null +++ b/utoipa-gen/tests/testdata/rc_schema_high_order_types @@ -0,0 +1,42 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "title", + "version": "version" + }, + "paths": {}, + "components": { + "schemas": { + "HighArc": { + "$ref": "#/components/schemas/High_Arc_i32" + }, + "HighRc": { + "$ref": "#/components/schemas/High_Rc_i32" + }, + "High_Arc_i32": { + "type": "object", + "required": [ + "high" + ], + "properties": { + "high": { + "type": "integer", + "format": "int32" + } + } + }, + "High_Rc_i32": { + "type": "object", + "required": [ + "high" + ], + "properties": { + "high": { + "type": "integer", + "format": "int32" + } + } + } + } + } +} diff --git a/utoipa-gen/tests/testdata/schema_generic_enum_variant_with_generic_type b/utoipa-gen/tests/testdata/schema_generic_enum_variant_with_generic_type new file mode 100644 index 00000000..5455092e --- /dev/null +++ b/utoipa-gen/tests/testdata/schema_generic_enum_variant_with_generic_type @@ -0,0 +1,340 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "title", + "version": "version" + }, + "paths": {}, + "components": { + "schemas": { + "FooStruct_BTreeMap_String_String": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + } + } + }, + "FooStruct_BTreeSet_i32": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "uniqueItems": true + } + } + }, + "FooStruct_HashMap_i32_String": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "integer", + "format": "int32" + } + } + } + }, + "FooStruct_HashSet_i32": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "uniqueItems": true + } + } + }, + "FooStruct_LinkedList_i32": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + }, + "FooStruct_Option_Vec_i32": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "allOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + ] + } + } + }, + "FooStruct_Option_i32": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "allOf": [ + { + "type": "null" + }, + { + "type": "integer", + "format": "int32" + } + ] + } + } + }, + "FooStruct_Vec_i32": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + }, + "FoosEnum": { + "oneOf": [ + { + "type": "object", + "required": [ + "ThingNoAliasOption" + ], + "properties": { + "ThingNoAliasOption": { + "$ref": "#/components/schemas/FooStruct_Option_i32" + } + } + }, + { + "type": "object", + "required": [ + "FooEnumThing" + ], + "properties": { + "FooEnumThing": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + { + "type": "object", + "required": [ + "FooThingOptionVec" + ], + "properties": { + "FooThingOptionVec": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "allOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + ] + } + } + } + } + }, + { + "type": "object", + "required": [ + "FooThingLinkedList" + ], + "properties": { + "FooThingLinkedList": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + { + "type": "object", + "required": [ + "FooThingBTreeMap" + ], + "properties": { + "FooThingBTreeMap": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + } + } + } + } + } + }, + { + "type": "object", + "required": [ + "FooThingHashMap" + ], + "properties": { + "FooThingHashMap": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "integer", + "format": "int32" + } + } + } + } + } + }, + { + "type": "object", + "required": [ + "FooThingHashSet" + ], + "properties": { + "FooThingHashSet": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "uniqueItems": true + } + } + } + } + }, + { + "type": "object", + "required": [ + "FooThingBTreeSet" + ], + "properties": { + "FooThingBTreeSet": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "uniqueItems": true + } + } + } + } + } + ] + } + } + } +} diff --git a/utoipa-gen/tests/testdata/schema_high_order_types b/utoipa-gen/tests/testdata/schema_high_order_types new file mode 100644 index 00000000..35c0f837 --- /dev/null +++ b/utoipa-gen/tests/testdata/schema_high_order_types @@ -0,0 +1,65 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "title", + "version": "version" + }, + "paths": {}, + "components": { + "schemas": { + "HighBox": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "$ref": "#/components/schemas/High_Box_i32" + } + } + }, + "HighCow": { + "$ref": "#/components/schemas/High_Cow_i32" + }, + "HighRefCell": { + "$ref": "#/components/schemas/High_RefCell_i32" + }, + "High_Box_i32": { + "type": "object", + "required": [ + "high" + ], + "properties": { + "high": { + "type": "integer", + "format": "int32" + } + } + }, + "High_Cow_i32": { + "type": "object", + "required": [ + "high" + ], + "properties": { + "high": { + "type": "integer", + "format": "int32" + } + } + }, + "High_RefCell_i32": { + "type": "object", + "required": [ + "high" + ], + "properties": { + "high": { + "type": "integer", + "format": "int32" + } + } + } + } + } +} diff --git a/utoipa/CHANGELOG.md b/utoipa/CHANGELOG.md index ed5f836f..c8537559 100644 --- a/utoipa/CHANGELOG.md +++ b/utoipa/CHANGELOG.md @@ -29,6 +29,7 @@ to look into changes introduced to **`utoipa-gen`**. ### Fixed +* Fix impl `ToSchema` for container types (https://github.com/juhaku/utoipa/pull/1107) * Fix typos in changelog * Fix broken doc links * Fix testing without explicit features (https://github.com/juhaku/utoipa/pull/1041) diff --git a/utoipa/src/lib.rs b/utoipa/src/lib.rs index 09225dc6..04d0befb 100644 --- a/utoipa/src/lib.rs +++ b/utoipa/src/lib.rs @@ -275,6 +275,7 @@ pub mod openapi; use std::borrow::Cow; use std::collections::BTreeMap; +use std::option::Option; #[cfg(feature = "macros")] #[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] @@ -492,7 +493,7 @@ macro_rules! impl_partial_schema_primitive { } macro_rules! impl_to_schema { - ( $( $ty:ident ,)* ) => { + ( $( $ty:ident ),* ) => { $( impl ToSchema for $ty { fn name() -> std::borrow::Cow<'static, str> { @@ -502,11 +503,97 @@ macro_rules! impl_to_schema { )* }; } + #[rustfmt::skip] impl_to_schema!( - i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, bool, f32, f64, String, str, char, + i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, bool, f32, f64, String, str, char ); +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for Option where Option: PartialSchema {} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for Vec where Vec: PartialSchema {} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for std::collections::LinkedList where + std::collections::LinkedList: PartialSchema +{ +} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for [T] where [T]: PartialSchema {} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl<'t, T: ToSchema> ToSchema for &'t [T] where &'t [T]: PartialSchema {} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl<'t, T: ToSchema> ToSchema for &'t mut [T] where &'t mut [T]: PartialSchema {} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for std::collections::HashMap where + std::collections::HashMap: PartialSchema +{ +} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for std::collections::BTreeMap where + std::collections::BTreeMap: PartialSchema +{ +} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for std::collections::HashSet where + std::collections::HashSet: PartialSchema +{ +} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for std::collections::BTreeSet where + std::collections::BTreeSet: PartialSchema +{ +} + +#[cfg(all(feature = "macros", feature = "indexmap"))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "indexmap")))] +impl ToSchema for indexmap::IndexMap where + indexmap::IndexMap: PartialSchema +{ +} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for std::boxed::Box where std::boxed::Box: PartialSchema {} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl<'a, T: PartialSchema + Clone> ToSchema for std::borrow::Cow<'a, T> where + std::borrow::Cow<'a, T>: PartialSchema +{ +} + +#[cfg(feature = "macros")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] +impl ToSchema for std::cell::RefCell where std::cell::RefCell: PartialSchema {} + +#[cfg(all(feature = "macros", feature = "rc_schema"))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "rc_schema")))] +impl ToSchema for std::rc::Rc where std::rc::Rc: PartialSchema {} + +#[cfg(all(feature = "macros", feature = "rc_schema"))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "rc_schema")))] +impl ToSchema for std::sync::Arc where std::sync::Arc: PartialSchema {} + // Create `utoipa` module so we can use `utoipa-gen` directly from `utoipa` crate. // ONLY for internal use! #[doc(hidden)] @@ -599,162 +686,6 @@ impl<'a> ToSchema for &'a str { impl_partial_schema!(&str); -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for Vec { - fn schema() -> openapi::RefOr { - schema!(#[inline] Vec).into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for Option> { - fn schema() -> openapi::RefOr { - schema!(#[inline] Option>).into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for [T] { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - [T] - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for &[T] { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - &[T] - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for &mut [T] { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - &mut [T] - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for Option<&[T]> { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - Option<&[T]> - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for Option<&mut [T]> { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - Option<&mut [T]> - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for Option { - fn schema() -> openapi::RefOr { - schema!(#[inline] Option).into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for BTreeMap { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - BTreeMap - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for Option> { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - Option> - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for BTreeMap> { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - BTreeMap> - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for std::collections::HashMap { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - std::collections::HashMap - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for Option> { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - Option> - ) - .into() - } -} - -#[cfg(feature = "macros")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] -impl PartialSchema for std::collections::HashMap> { - fn schema() -> openapi::RefOr { - schema!( - #[inline] - std::collections::HashMap> - ) - .into() - } -} - /// Trait for implementing OpenAPI PathItem object with path. /// /// This trait is implemented via [`#[utoipa::path(...)]`][derive] attribute macro and there @@ -1129,7 +1060,7 @@ macro_rules! impl_from_for_number { #[rustfmt::skip] impl_from_for_number!( f32 => Float as f64, f64 => Float, - i8 => Int as isize, i16 => Int as isize, i32 => Int as isize, i64 => Int as isize, + i8 => Int as isize, i16 => Int as isize, i32 => Int as isize, i64 => Int as isize, u8 => UInt as usize, u16 => UInt as usize, u32 => UInt as usize, u64 => UInt as usize, isize => Int, usize => UInt ); @@ -1139,7 +1070,9 @@ impl_from_for_number!( #[cfg(feature = "macros")] #[cfg_attr(doc_cfg, doc(cfg(feature = "macros")))] pub mod __dev { - use crate::{utoipa, OpenApi}; + use utoipa_gen::schema; + + use crate::{utoipa, OpenApi, PartialSchema, ToSchema}; pub trait PathConfig { fn path() -> String; @@ -1218,6 +1151,187 @@ pub mod __dev { } } + impl ComposeSchema for Option { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!(#[inline] Option).into() + } + } + + impl ComposeSchema for Vec { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!(#[inline] Vec).into() + } + } + + impl ComposeSchema for std::collections::LinkedList { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!(#[inline] LinkedList).into() + } + } + + impl ComposeSchema for [T] { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + [T] + ) + .into() + } + } + + impl ComposeSchema for &[T] { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + [T] + ) + .into() + } + } + + impl ComposeSchema for &mut [T] { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + [T] + ) + .into() + } + } + + impl ComposeSchema for std::collections::HashMap { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + HashMap + ) + .into() + } + } + + impl ComposeSchema for std::collections::BTreeMap { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + BTreeMap + ) + .into() + } + } + + impl ComposeSchema for std::collections::HashSet { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + HashSet + ) + .into() + } + } + + impl ComposeSchema for std::collections::BTreeSet { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + BTreeSet + ) + .into() + } + } + + #[cfg(feature = "indexmap")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "indexmap")))] + impl ComposeSchema for indexmap::IndexMap { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + IndexMap + ) + .into() + } + } + + impl<'a, T: PartialSchema + Clone> ComposeSchema for std::borrow::Cow<'a, T> { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + Cow + ) + } + } + + impl ComposeSchema for std::boxed::Box { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + Box + ) + } + } + + impl ComposeSchema for std::cell::RefCell { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + RefCell + ) + } + } + + #[cfg(feature = "rc_schema")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "rc_schema")))] + impl ComposeSchema for std::rc::Rc { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + Rc + ) + } + } + + #[cfg(feature = "rc_schema")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "rc_schema")))] + impl ComposeSchema for std::sync::Arc { + fn compose( + _: Vec>, + ) -> utoipa::openapi::RefOr { + schema!( + #[inline] + Arc + ) + } + } + pub trait SchemaReferences { fn schemas( schemas: &mut Vec<(