Skip to content

Commit

Permalink
Move backends into their own package
Browse files Browse the repository at this point in the history
  • Loading branch information
romac committed Jan 30, 2024
1 parent bb17309 commit a7490df
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 108 deletions.
108 changes: 0 additions & 108 deletions core/src/main/scala/Backend.scala

This file was deleted.

1 change: 1 addition & 0 deletions core/src/main/scala/Choreo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import cats.effect.kernel.Concurrent
import cats.syntax.all.*
import cats.arrow.FunctionK

import choreo.backend.Backend
import choreo.utils.toFunctionK

type Choreo[M[_], A] = Free[[X] =>> ChoreoSig[M, X], A]
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/scala/backend/Backend.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package choreo
package backend

import cats.Monad
import cats.effect.std.Queue
import cats.effect.kernel.Concurrent
import cats.syntax.all.*

trait Backend[B, M[_]]:
extension (backend: B)
def runNetwork[A](at: Loc)(network: Network[M, A]): M[A]

object Backend:
def local[M[_]: Concurrent](locs: List[Loc]): M[LocalBackend[M]] =
LocalBackend.make(locs)

def http[M[_]: Concurrent](locs: List[Loc]): HTTPBackend[M] =
HTTPBackend(locs)
46 changes: 46 additions & 0 deletions core/src/main/scala/backend/HTTP.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package choreo
package backend

import cats.Monad
import cats.arrow.FunctionK
import cats.effect.kernel.Concurrent
import cats.syntax.all.*

import choreo.utils.toFunctionK

class HTTPBackend[M[_]](locs: List[Loc]):
def runNetwork[A](at: Loc)(network: Network[M, A])(using M: Monad[M]): M[A] =
network.foldMap(run(at, locs).toFunctionK)

private[choreo] def run(at: Loc, locs: List[Loc])(using
M: Monad[M]
): [A] => NetworkSig[M, A] => M[A] = [A] =>
(na: NetworkSig[M, A]) =>
na match
case NetworkSig.Run(ma) =>
ma

case NetworkSig.Send(a, to, ser) =>
val encoded = ser.encode(a)
// TODO: send to network
M.pure(())

case NetworkSig.Recv(from, ser) =>
val encoded: ser.Encoding = ??? // TODO: receive from network
val value = ser.decode(encoded).get
M.pure(value)

case NetworkSig.Broadcast(a, ser) =>
locs
.filter(_ != at)
.traverse_ { to =>
run(at, locs)(NetworkSig.Send(a, to, ser))
}
end HTTPBackend

object HTTPBackend:
given backend[M[_]: Monad]: Backend[HTTPBackend[M], M] with
extension (backend: HTTPBackend[M])
def runNetwork[A](at: Loc)(network: Network[M, A]): M[A] =
runNetwork(at)(network)
end HTTPBackend
57 changes: 57 additions & 0 deletions core/src/main/scala/backend/Local.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package choreo
package backend

import cats.Monad
import cats.arrow.FunctionK
import cats.effect.std.Queue
import cats.effect.kernel.Concurrent
import cats.syntax.all.*

import choreo.utils.toFunctionK

class LocalBackend[M[_]](inboxes: Map[Loc, Queue[M, Any]]):
val locs = inboxes.keys.toSeq

def runNetwork[A](at: Loc)(network: Network[M, A])(using M: Monad[M]): M[A] =
network.foldMap(run(at, inboxes).toFunctionK)

private[choreo] def run(
at: Loc,
inboxes: Map[Loc, Queue[M, Any]]
)(using M: Monad[M]): [A] => NetworkSig[M, A] => M[A] = [A] =>
(na: NetworkSig[M, A]) =>
na match
case NetworkSig.Run(ma) =>
ma

case NetworkSig.Send(a, to, ser) =>
val inbox = inboxes.get(to).get
inbox.offer(a)

case NetworkSig.Recv(from, ser) =>
val inbox = inboxes.get(at).get
inbox.take.map(_.asInstanceOf[A])

case NetworkSig.Broadcast(a, ser) =>
locs
.filter(_ != at)
.traverse_ { to =>
run(at, inboxes)(NetworkSig.Send(a, to, ser))
}
end LocalBackend

object LocalBackend:
def make[M[_]: Concurrent](locs: List[Loc]): M[LocalBackend[M]] =
makeInboxes(locs).map(LocalBackend(_))

given backend[M[_]: Monad]: Backend[LocalBackend[M], M] with
extension (backend: LocalBackend[M])
def runNetwork[A](at: Loc)(network: Network[M, A]): M[A] =
runNetwork(at)(network)
end LocalBackend

private[this] def makeInboxes[M[_]: Concurrent](
locs: Seq[Loc]
): M[Map[Loc, Queue[M, Any]]] =
for queues <- locs.traverse(_ => Queue.unbounded[M, Any])
yield locs.zip(queues).toMap
2 changes: 2 additions & 0 deletions examples/src/main/scala/Bookseller.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import cats.effect.IO
import cats.effect.IO.asyncForIO
import cats.syntax.all.*

import choreo.backend.Backend

case class Book(title: String, price: Double)

case class Date(year: Int, month: Int, day: Int):
Expand Down
2 changes: 2 additions & 0 deletions examples/src/main/scala/KV.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import cats.effect.IO.asyncForIO
import cats.effect.kernel.Ref
import cats.syntax.all.*

import choreo.backend.Backend

type State = Map[String, String]

enum Request:
Expand Down

0 comments on commit a7490df

Please sign in to comment.