Skip to content

feat(body): add UnsyncBoxBody::new constructor and From<ResponseBody>#682

Open
jlizen wants to merge 1 commit into
tower-rs:mainfrom
jlizen:feat/unsync-box-body
Open

feat(body): add UnsyncBoxBody::new constructor and From<ResponseBody>#682
jlizen wants to merge 1 commit into
tower-rs:mainfrom
jlizen:feat/unsync-box-body

Conversation

@jlizen
Copy link
Copy Markdown
Member

@jlizen jlizen commented May 22, 2026

Supersedes: #537

Motivation

Users who return responses with different body types (e.g., from multiple match branches) need to box them into a common type. When one branch uses ServeDir/ServeFile, the response body is already internally boxed, but wrapping it in UnsyncBoxBody::new() causes double-boxing (double allocation + double indirection).

PR #537 by @nanoqsh added From impls directly on http_body_util::combinators::UnsyncBoxBody, but tower-http has a policy of not leaking http_body_util types in its public API.

Solution

Expose tower-http's own UnsyncBoxBody wrapper with:

  1. A public new() constructor that type-erases any Body impl (analogous to http_body_util::combinators::UnsyncBoxBody::new)
  2. A From<ServeFileSystemResponseBody> impl that unwraps the already-boxed inner body without re-boxing

Usage becomes:

// Before (double-boxing):
.map(|res| res.map(UnsyncBoxBody::new))

// After (zero-cost conversion from ServeDir response):
.map(|res| res.map(UnsyncBoxBody::from))

The internal pub(crate) fn new() that previously accepted the raw http_body_util inner type was renamed to from_inner() to avoid ambiguity with the new public constructor.

Tests verify that UnsyncBoxBody::new correctly boxes a body and that the From<ResponseBody> conversion produces a valid, readable body from a real ServeDir response. The conversion is zero-cost by construction (it just moves the inner field), so correctness is primarily a compile-time guarantee.

@jlizen
Copy link
Copy Markdown
Member Author

jlizen commented May 22, 2026

@seanmonstar / @davidpdrsn - either of y'all have time to review this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant