mirror of https://github.com/sbt/sbt.git
Add a Task.tailRecM for stack safe loops (#846)
This commit is contained in:
parent
c469899040
commit
f003314317
|
|
@ -29,5 +29,18 @@ object Task extends PlatformTask {
|
|||
def never[A]: Task[A] =
|
||||
Task(_ => Promise[A].future)
|
||||
|
||||
def tailRecM[A, B](a: A)(fn: A => Task[Either[A, B]]): Task[B] =
|
||||
Task[B] { implicit ec =>
|
||||
def loop(a: A): Future[B] =
|
||||
fn(a).future().flatMap {
|
||||
case Right(b) =>
|
||||
Future.successful(b)
|
||||
case Left(a) =>
|
||||
// this is safe because recursive
|
||||
// flatMap is safe on Future
|
||||
loop(a)
|
||||
}
|
||||
loop(a)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package coursier.util
|
||||
|
||||
import utest._
|
||||
|
||||
import scala.concurrent.{Await, ExecutionContext}
|
||||
import scala.concurrent.duration.Duration
|
||||
|
||||
object TaskTests extends TestSuite {
|
||||
|
||||
val tests = Tests {
|
||||
'tailRecM {
|
||||
import ExecutionContext.Implicits.global
|
||||
|
||||
def countTo(i: Int): Task[Int] =
|
||||
Task.tailRecM(0) {
|
||||
case x if x >= i => Task.delay(Right(i))
|
||||
case toosmall => Task.delay(Left(toosmall + 1))
|
||||
}
|
||||
countTo(500000).map(_ == 500000).future().map(assert(_))
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue