Skip to content

Instantly share code, notes, and snippets.

@rudogma
Last active June 13, 2017 20:39
Show Gist options
  • Save rudogma/a4f6deaddd368e86676aacfea3dcda9a to your computer and use it in GitHub Desktop.
Save rudogma/a4f6deaddd368e86676aacfea3dcda9a to your computer and use it in GitHub Desktop.
Count nested implicits level using shapeless.Nat (flatten future as example)
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