An Iteratee consumes a stream of elements of type E, producing a result of type A.

An Iteratee consumes a stream of elements of type E, producing a result of type A.
The stream itself is represented by the Input trait. An Iteratee is an immutable
data type, so each step in consuming the stream generates a new Iteratee with a new
state.

At a high level, an Iteratee is just a function that takes a piece of input and
returns either a final result or a new function that takes another piece of input.
To represent this, an Iteratee can be in one of three states
(see the play.api.libs.iteratee.Step trait):
play.api.libs.iteratee.Done, which means it contains a result and potentially some unconsumed part of the stream;
play.api.libs.iteratee.Cont, which means it contains a function to be invoked to generate a new Iteratee from the next piece of input;
play.api.libs.iteratee.Error, which means it contains an error message and potentially some unconsumed part of the stream.

One would expect to transform an Iteratee through the Cont state N times, eventually
arriving at either the Done or Error state.

The Iteratee does not do any resource management (such as closing streams);
the producer pushing stuff into the Iteratee has that responsibility.+ *
The state of an Iteratee (the current play.api.libs.iteratee.Step may not be available
synchronously; it may be pending an asynchronous computation. This is the difference
between Iteratee and Step.