Why was the `Stream` trait split out into `Stream` and `StreamExt`?

In futures-rs commit 0124b79, the default methods on the Stream trait got split out into their own StreamExt trait, which is automatically implemented on all Streams.

What was the rationale for splitting it up this way?

Was it simply to allow Stream to remain in futures-core while StreamExt was moved into futures-util, to help stabilize futures-core?

Or is there some deeper problem with the way trait default methods work that make ...Ext traits the preferred way to provide utility methods like filter and map in new code?

The commit message doesn't mention an issue or a PR, and I haven't been able to find the discussion around this.

Yes, that's exactly it. The rationale is spelled out in the Futures 0.2 proposal in the futures-rfcs repo:

futures-core will include Future, Stream, IntoFuture traits and their dependencies. This is a central crate that includes only essential items, designed to minimize future breakage.

Combinator methods will be removed from the Future and Stream and moved to the FutureExt and StreamExt traits in the futures-util crate. poll will be the only remaining method on the Future and Stream traits.

This separation allows combinator functions to evolve over time without breaking changes to the public API surface of async libraries.

Ah, perfect, this is exactly what I was looking for.

Thank you!