Last active
June 13, 2017 20:39
-
-
Save rudogma/a4f6deaddd368e86676aacfea3dcda9a to your computer and use it in GitHub Desktop.
Count nested implicits level using shapeless.Nat (flatten future as example)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import shapeless.ops.nat.ToInt | |
import shapeless.{Nat, Succ} | |
import scala.concurrent.Promise | |
import scala.util.{Failure, Success} | |
import scala.concurrent.Future | |
import scala.concurrent.ExecutionContext.Implicits._ | |
val future = Future(Future(Future(Future(Future(5))))) | |
val f2 = future.flatten // Scala Future.flatten 5 - 1 = 4lvl - Future[Future[Future[Future[Int]]]]] | |
val f = flatten(future) // Future[Int] | |
for( v <- f){ | |
println("v: "+v) // v: 5 | |
} | |
Thread.sleep(100) | |
/** | |
* | |
* ex:Extractor used only in compile time for type evidence. Very lightweight, however it will be easily cleaned by JIT | |
* | |
*/ | |
def flatten[R, O, MaxLevel <: Nat](f0:Future[R])(implicit ex:Extractor[Future[R], O, Nat._0, MaxLevel], maxLevel:ToInt[MaxLevel]):Future[ex.Out] = { | |
next( | |
maxLevel.apply(), | |
f0, | |
Promise[ex.Out]() | |
).future // future of Promise above | |
} | |
protected def next[R](level:Int, f:Future[_], promise:Promise[R]): Promise[R] = { | |
if(level > 0){ | |
f.asInstanceOf[Future[Future[_]]].onComplete { | |
case Success(r) => | |
next(level - 1, r, promise) | |
case Failure(e) => promise.failure(e) | |
} | |
}else{ | |
promise.completeWith(f.asInstanceOf[Future[R]]) | |
} | |
promise | |
} | |
trait Extractor[F, T, Level <: Nat, MaxLevel <: Nat] { | |
type Out | |
} | |
object Extractor extends ExtractorLowPriority { | |
implicit def recur[T, Inner, Level <: Nat, Max <: Nat](implicit nested:Extractor[Inner, T, Succ[Level], Max]):Aux[Future[Inner], Inner, nested.Out, Level, Max] = dummy | |
} | |
trait ExtractorLowPriority { | |
type Aux[F, T, Out0, Level <: Nat, Max <: Nat] = Extractor[F, T, Level, Max]{ type Out = Out0 } | |
implicit def base[T, Level <: Nat]:Aux[Future[T], T, T, Level, Level] = dummy | |
// Re-using it, because we don't want to make garbage | |
protected val dummyStub = new Extractor[Nothing,Nothing,Nothing,Nothing]{ | |
type Out = Nothing | |
} | |
def dummy[T]:T = dummyStub.asInstanceOf[T] | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment