!str #15236 new transformer

This is far from finished, but I need to discuss.

The end goal of this is to provide a powerful, efficient, low level API for custom transformation operations. It is supposed to replace `Transformer`.

So far this is only using the API of the `impl.fusing.Op` (and subsclasses). These will be made more user friendly where needed. We can also consider providing higher level API that is more convenient for certain type of operations.

As first step I'm replacing all existing `Transformer` usage.

I'm currently stuck in `HttpEntity` and we must discuss how to go forward there. @jrudolph @sirthias should be part of that discussion.
Let me state the goal of the `transformDataBytes` API once again: it should be possible to apply any transformation on the entity data. IMO the main complication comes from dealing with `HttpEntity.Strict` which requires that we can do the transformation strictly to determine the new content-length and again return an `HttpEntity.Strict`.

If we let go of this restriction (and it already is somewhat weakened because in case the transformer throws we also now return an `HttpEntity.Chunked` with an instantly failed chunk stream) we could have `transformDataBytes` take a `Flow[ByteString, ByteString]`. Implementations then would look like this:

```scala
trait HttpEntity {
  def transformDataBytes(flow: Flow[ByteString, ByteString]): HttpEntity
}

class Strict(data: ByteString) {
  def transformDataBytes(flow: Flow[ByteString, ByteString]): Chunked =
    Chunked(data.connect(flow).map(Chunk(_)))
}
class Default(data: Source[ByteString]) {
  def transformDataBytes(flow: Flow[ByteString, ByteString]): Chunked =
    Chunked(data.connect(flow).map(Chunk(_)))
}
class CloseDelimited(data: Source[ByteString]) {
  def transformDataBytes(flow: Flow[ByteString, ByteString]): CloseDelimited =
    CloseDelimited(data.connect(flow))
}
class Chunked(data: Source[ChunkStreamPart]) {
  def transformDataBytes(flow: Flow[ByteString, ByteString]): Chunked =
    Chunked(data.connect(preserveChunks(flow)))
}

def preserveChunks(flow: Flow[ByteString, ByteString]): Flow[ChunkStreamPart, ChunkStreamPart] =
  // how to implement this, it looks very similar to the previously suggested `mapWithContext`
```

If we could figure out how to write `preserveChunks` (or decide to drop the requirement of preserving chunks, e.g. by requiring that all `Chunk`s must only contain data an not contain any extensions), we would have removed all complexity here and would move it into the actual implementation of the Flows which would be a good thing IMO.