diff --git a/utoipa/CHANGELOG.md b/utoipa/CHANGELOG.md index 5ba11240..0c4b52e8 100644 --- a/utoipa/CHANGELOG.md +++ b/utoipa/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added +* Add default implementation of `ToSchema` trait (https://github.com/juhaku/utoipa/pull/1096) * Add support for `property_names` for object (https://github.com/juhaku/utoipa/pull/1084) * Add auto collect schemas for utoipa-axum (https://github.com/juhaku/utoipa/pull/1072) * Add global config for `utiopa` (https://github.com/juhaku/utoipa/pull/1048) diff --git a/utoipa/src/lib.rs b/utoipa/src/lib.rs index 6ccfdfb7..09225dc6 100644 --- a/utoipa/src/lib.rs +++ b/utoipa/src/lib.rs @@ -407,7 +407,41 @@ pub trait ToSchema: PartialSchema { /// /// In case a generic schema the _`name`_ will be used as prefix for the name in the OpenAPI /// documentation. - fn name() -> Cow<'static, str>; + /// + /// The default implementation naively takes the TypeName by removing + /// the module path and generic elements. + /// But you probably don't want to use the default implementation for generic elements. + /// That will produce coliision between generics. (eq. `Foo` ) + /// + /// # Example + /// + /// ```rust + /// # use utoipa::ToSchema; + /// # + /// struct Foo(T); + /// + /// impl ToSchema for Foo {} + /// # impl utoipa::PartialSchema for Foo { + /// # fn schema() -> utoipa::openapi::RefOr { + /// # Default::default() + /// # } + /// # } + /// + /// assert_eq!(Foo::<()>::name(), std::borrow::Cow::Borrowed("Foo")); + /// assert_eq!(Foo::<()>::name(), Foo::::name()); // WARNING: these types have the same name + /// ``` + fn name() -> Cow<'static, str> { + let full_type_name = std::any::type_name::(); + let type_name_without_generic = full_type_name + .split_once("<") + .map(|(s1, _)| s1) + .unwrap_or(full_type_name); + let type_name = type_name_without_generic + .rsplit_once("::") + .map(|(_, tn)| tn) + .unwrap_or(type_name_without_generic); + Cow::Borrowed(type_name) + } } impl From for openapi::RefOr { @@ -1201,6 +1235,34 @@ mod tests { use super::*; + #[test] + fn test_toschema_name() { + struct Foo; + impl ToSchema for Foo {} + impl PartialSchema for Foo { + fn schema() -> openapi::RefOr { + Default::default() + } + } + assert_eq!(Foo::name(), Cow::Borrowed("Foo")); + + struct FooGeneric(T, U); + impl ToSchema for FooGeneric {} + impl PartialSchema for FooGeneric { + fn schema() -> openapi::RefOr { + Default::default() + } + } + assert_eq!( + FooGeneric::::name(), + Cow::Borrowed("FooGeneric") + ); + assert_eq!( + FooGeneric::::name(), + FooGeneric::<(), ()>::name(), + ); + } + #[cfg(not(feature = "non_strict_integers"))] #[test] fn test_partial_schema_strict_integers() {