Skip to content

breaking: remove the Handler and StateManager traits - #289

Open
danieleades wants to merge 1 commit into
httpmock:masterfrom
danieleades:agent/rust-private-bounds
Open

breaking: remove the Handler and StateManager traits#289
danieleades wants to merge 1 commit into
httpmock:masterfrom
danieleades:agent/rust-private-bounds

Conversation

@danieleades

Copy link
Copy Markdown
Contributor

What changed

  • remove the Handler and StateManager traits
  • make MockServer and HttpMockHandler concrete, so HttpMockServer becomes a real type rather than an alias over internal generics
  • rename HttpMockHandler to handler::Handler, HttpMockStateManager to state::Manager, and MockServerState to a private state::Inner
  • make HttpMockServer::new infallible and pub(crate)
  • remove private_bounds from the temporary allow list

Why

private_bounds fired four times because pub type HttpMockServer = MockServer<HttpMockHandler<HttpMockStateManager>> made both generics publicly reachable while their bounds were pub(crate).

Keeping the traits and just hiding the structs does not work: it trades the four private_bounds errors for four private_interfaces ones, because HttpMockServerBuilder::build is public and returns the server. The options were to export a 22-method trait publicly forever, or to stop pretending the generics were doing anything.

They were not. Each trait had exactly one implementor and neither is dyn compatible, StateManager::record being generic and Handler::handle returning impl Future, so neither could ever have been a dynamic dispatch seam. Nothing substitutes an alternative state manager or handler, including the tests. Manager is a pure in-memory type over a Mutex, with no I/O to fake.

Dropping them also frees the good names. Handler and Manager were only spelled HttpMockHandler and HttpMockStateManager because the traits held those names, and state::Inner is the conventional spelling for data guarded by a lock. HttpMockServer keeps its prefix, since httpmock::MockServer is already the client-side handle.

Breaking changes

  • httpmock::server::state::HttpMockStateManager is now state::Manager
  • httpmock::server::state::MockServerState is now private
  • HttpMockServer is a struct rather than a type alias, and HttpMockServer::new is pub(crate)

Nothing that was callable downstream has been removed. MockServer::new took an unnameable argument type, and every Manager method other than new and default was already behind a pub(crate) trait. Construction still goes through HttpMockServerBuilder, and start, start_with_signals and run_accept_loop are unchanged. Runtime behavior is unchanged.

Validation

  • cargo clippy --all-targets --all-features
  • cargo clippy --all-targets
  • cargo clippy --all-targets --no-default-features
  • cargo clippy --all-targets --features standalone
  • cargo hack check --feature-powerset --depth 2 --all-targets
  • cargo hack check --rust-version --each-feature --no-dev-deps on 1.88
  • cargo test --all-features
  • cargo fmt --all -- --check
  • git diff --check

Both had a single implementor, were never used as dyn, and could not
have been: StateManager::record is generic and Handler::handle returns
impl Future, so neither is dyn compatible. Their only effect was to
leak pub(crate) bounds through the public HttpMockServer alias.

Making the server concrete lets the alias become a real type, and frees
the names Handler and Manager for the types that were carrying an
HttpMock prefix to avoid them.
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.59459% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/server/state.rs 90.62% 3 Missing ⚠️
src/server/persistence.rs 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

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