Skip to content

Commit 3e0905d

Browse files
fix: immediately return zero or single values instead of merging (#2)
1 parent 61cb542 commit 3e0905d

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

examples/axum/src/main.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ mod error;
33
mod state;
44
mod user;
55

6+
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
7+
68
use anyhow::Result;
79
use tokio::net::TcpListener;
810
use utoipa_axum::router::OpenApiRouter;
@@ -22,7 +24,10 @@ async fn main() -> Result<()> {
2224
.merge(Scalar::with_url("/api/reference", openapi))
2325
.with_state(AppState::default());
2426

25-
let listener = TcpListener::bind("0.0.0.0:8080").await?;
27+
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 8080));
28+
let listener = TcpListener::bind(addr).await?;
29+
println!("listening on http://{:?}", addr);
30+
2631
axum::serve(listener, router).await?;
2732

2833
Ok(())

packages/breach/src/utoipa.rs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,72 @@ pub fn merge_responses(
1616
.flatten()
1717
.chunk_by(|(code, _)| code.clone())
1818
.into_iter()
19-
.map(|(code, chunk)| {
19+
.filter_map(|(code, chunk)| {
2020
let response = merge_response(
2121
StatusCode::from_bytes(code.as_bytes()).expect("valid status code"),
2222
chunk.map(|(_, response)| response),
2323
);
2424

25-
(code, RefOr::T(response))
25+
response.map(|response| (code, RefOr::T(response)))
2626
})
2727
.collect()
2828
}
2929

3030
/// Merge multiple [`RefOr<Response>`] into a single [`Response`].
31-
fn merge_response(code: StatusCode, responses: impl Iterator<Item = RefOr<Response>>) -> Response {
32-
let responses = responses.filter_map(|response| match response {
33-
RefOr::Ref(_) => None,
34-
RefOr::T(response) => Some(response),
35-
});
31+
fn merge_response(
32+
code: StatusCode,
33+
responses: impl Iterator<Item = RefOr<Response>>,
34+
) -> Option<Response> {
35+
let mut responses = responses
36+
.filter_map(|response| match response {
37+
RefOr::Ref(_) => None,
38+
RefOr::T(response) => Some(response),
39+
})
40+
.collect::<Vec<_>>();
3641

3742
let mut builder = ResponseBuilder::new();
3843

44+
if responses.is_empty() {
45+
return None;
46+
} else if responses.len() == 1 {
47+
return Some(responses.remove(0));
48+
}
49+
3950
if let Some(canonical_reason) = code.canonical_reason() {
4051
builder = builder.description(canonical_reason)
4152
}
4253

4354
builder = responses
55+
.into_iter()
4456
.flat_map(|response| response.content)
4557
.chunk_by(|(content_type, _)| content_type.clone())
4658
.into_iter()
4759
.fold(builder, |builder, (content_type, chunk)| {
48-
let content = merge_content(chunk.map(|(_, content)| content));
60+
let content = merge_content(
61+
chunk
62+
.map(|(_, content)| content)
63+
.collect::<Vec<_>>()
64+
.into_iter(),
65+
);
4966

5067
// TODO: Merge content.
51-
builder.content(content_type, content)
68+
if let Some(content) = content {
69+
builder.content(content_type, content)
70+
} else {
71+
builder
72+
}
5273
});
5374

5475
// TODO: Merge headers, extensions, links.
5576

56-
builder.build()
77+
Some(builder.build())
5778
}
5879

59-
fn merge_content(contents: impl Iterator<Item = Content>) -> Content {
80+
fn merge_content(mut contents: impl ExactSizeIterator<Item = Content>) -> Option<Content> {
81+
if contents.len() <= 1 {
82+
return contents.next();
83+
}
84+
6085
let mut builder = ContentBuilder::new();
6186
let mut one_of_builder = OneOfBuilder::new();
6287

@@ -83,5 +108,5 @@ fn merge_content(contents: impl Iterator<Item = Content>) -> Content {
83108
builder = builder.schema(Some(Schema::from(one_of)));
84109
}
85110

86-
builder.build()
111+
Some(builder.build())
87112
}

0 commit comments

Comments
 (0)