Advertisement
Cool_Dalek

Scala3 example of using actors with cats

Feb 15th, 2022 (edited)
951
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 2.19 KB | None | 0 0
  1. import akka.actor.typed.*
  2. import akka.actor.typed.scaladsl.AskPattern.*
  3. import akka.util.Timeout
  4. import cats.effect.*
  5. import cats.syntax.all.*
  6.  
  7. import scala.annotation.targetName
  8. import scala.annotation.unchecked.uncheckedVariance
  9. import scala.concurrent.Future
  10.  
  11. trait SummonerK[G[_[_]]] {
  12.  
  13.   def apply[F[_]: G]: G[F] = summon[G[F]]
  14.  
  15. }
  16.  
  17. trait FromFuture[F[_]] {
  18.  
  19.   def fromFuture[T](f: => Future[T]): F[T]
  20.  
  21. }
  22. object FromFuture extends SummonerK[FromFuture] {
  23.  
  24.   given [F[_]: Async]: FromFuture[F] = new FromFuture[F] {
  25.  
  26.     override def fromFuture[T](f: => Future[T]): F[T] =
  27.       Async[F].fromFuture {
  28.         Async[F].delay {
  29.           f
  30.         }
  31.       }
  32.  
  33.   }
  34.  
  35. }
  36.  
  37. trait Actor[F[_], -T] {
  38.  
  39.   @targetName("tell")
  40.   def !(message: T): F[Unit]
  41.  
  42.   @targetName("ask")
  43.   def ?[R](message: ActorRef[R] => T)(using timeout: Timeout, scheduler: Scheduler): F[R]
  44.  
  45.   def unsafe(): ActorRef[T @uncheckedVariance]
  46.  
  47. }
  48. object Actor {
  49.  
  50.   private class Impl[F[_]: Async, -T](underlying: ActorRef[T]) extends Actor[F, T] {
  51.  
  52.     @targetName("tell")
  53.     override def !(message: T): F[Unit] =
  54.       Async[F].delay {
  55.         underlying ! message
  56.       }
  57.  
  58.     @targetName("ask")
  59.     override def ?[R](message: ActorRef[R] => T)(using timeout: Timeout, scheduler: Scheduler): F[R] =
  60.       FromFuture[F].fromFuture {
  61.         underlying.ask[R](message)
  62.       }
  63.  
  64.     override def unsafe(): ActorRef[T] = underlying
  65.  
  66.   }
  67.  
  68.   def apply[F[_]: Async, T](underlying: ActorRef[T]): Actor[F, T] = Impl[F, T](underlying)
  69.  
  70. }
  71.  
  72. trait SpawnActor[F[_]] {
  73.  
  74.   def actor[T](name: String, behavior: Behavior[T]): F[Actor[F, T]]
  75.  
  76. }
  77. object SpawnActor extends SummonerK[SpawnActor] {
  78.  
  79.   given [F[_]: Async](using system: ActorSystem[SpawnProtocol.Command],
  80.                       timeout: Timeout): SpawnActor[F] =
  81.     new SpawnActor[F] {
  82.  
  83.       override def actor[T](name: String, behavior: Behavior[T]): F[Actor[F, T]] =
  84.         FromFuture[F].fromFuture {
  85.           system.ask[ActorRef[T]] { replyTo =>
  86.             SpawnProtocol.Spawn(
  87.               behavior,
  88.               name,
  89.               Props.empty,
  90.               replyTo,
  91.             )
  92.           }
  93.         }.map(Actor.apply)
  94.  
  95.     }
  96.  
  97. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement