Skip to content

Commit

Permalink
Add a default impl of ToSchema::name() (#1096)
Browse files Browse the repository at this point in the history
  • Loading branch information
ValentinColin authored Oct 6, 2024
1 parent 7034022 commit c9f8408
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
1 change: 1 addition & 0 deletions utoipa/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
64 changes: 63 additions & 1 deletion utoipa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>` )
///
/// # Example
///
/// ```rust
/// # use utoipa::ToSchema;
/// #
/// struct Foo<T>(T);
///
/// impl<T: ToSchema> ToSchema for Foo<T> {}
/// # impl<T: ToSchema> utoipa::PartialSchema for Foo<T> {
/// # fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
/// # Default::default()
/// # }
/// # }
///
/// assert_eq!(Foo::<()>::name(), std::borrow::Cow::Borrowed("Foo"));
/// assert_eq!(Foo::<()>::name(), Foo::<i32>::name()); // WARNING: these types have the same name
/// ```
fn name() -> Cow<'static, str> {
let full_type_name = std::any::type_name::<Self>();
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<T: ToSchema> From<T> for openapi::RefOr<openapi::schema::Schema> {
Expand Down Expand Up @@ -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<openapi::schema::Schema> {
Default::default()
}
}
assert_eq!(Foo::name(), Cow::Borrowed("Foo"));

struct FooGeneric<T: ToSchema, U: ToSchema>(T, U);
impl<T: ToSchema, U: ToSchema> ToSchema for FooGeneric<T, U> {}
impl<T: ToSchema, U: ToSchema> PartialSchema for FooGeneric<T, U> {
fn schema() -> openapi::RefOr<openapi::schema::Schema> {
Default::default()
}
}
assert_eq!(
FooGeneric::<Foo, String>::name(),
Cow::Borrowed("FooGeneric")
);
assert_eq!(
FooGeneric::<Foo, String>::name(),
FooGeneric::<(), ()>::name(),
);
}

#[cfg(not(feature = "non_strict_integers"))]
#[test]
fn test_partial_schema_strict_integers() {
Expand Down

0 comments on commit c9f8408

Please sign in to comment.