Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async instance #50

Open
wants to merge 9 commits into
base: async-instance
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ lazy val `cats-scala-fx` = (project in file("./cats-scalafx"))
.settings(
catsScalaFXSettings
)
.dependsOn(`scala-fx`)
.dependsOn(`scala-fx`, `munit-scala-fx`)

lazy val `scalike-jdbc-scala-fx` = project
.dependsOn(`scala-fx`, `munit-scala-fx` % "test -> compile")
Expand Down
3 changes: 2 additions & 1 deletion cats-scalafx/src/main/scala/instances.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package fx.instances
package fx
package instances

import _root_.cats.Monad
import _root_.cats.effect.Async
Expand Down
22 changes: 22 additions & 0 deletions cats-scalafx/src/test/scala/DisciplineFXSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package munit
package fx

import _root_.fx.Structured
import munit.fx.ScalaFXSuite
import munit.DisciplineSuite
import munit.Location
import org.typelevel.discipline.Laws

import scala.reflect.Typeable

abstract class DisciplineFXSuite extends ScalaFXSuite, DisciplineSuite {

def checkAllLaws[G <: Laws#RuleSet](
name: String)(ruleSet: Structured ?=> G)(using Location): Unit =
testFX(name) {
checkAll(name, _root_.fx.structured{
ruleSet
})
}

}
133 changes: 120 additions & 13 deletions cats-scalafx/src/test/scala/StructurredFLaws.scala
Original file line number Diff line number Diff line change
@@ -1,20 +1,127 @@
package munit
package fx

import _root_.cats.effect.IO
import _root_.cats.effect.implicits._
import _root_.cats.effect.kernel.Async
import _root_.cats.effect.kernel.Outcome
import _root_.cats.effect.kernel.instances.*
import _root_.cats.effect.kernel.testkit.AsyncGenerators
import _root_.cats.effect.kernel.testkit.GenK
import _root_.cats.effect.kernel.testkit.OutcomeGenerators
import _root_.cats.effect.kernel.testkit.SyncTypeGenerators.arbitrarySyncType
import _root_.cats.effect.laws.AsyncLaws
import _root_.cats.effect.laws.AsyncTests
import _root_.cats.implicits._
import _root_.cats.kernel.Eq
import _root_.cats.kernel.Order
import _root_.cats.laws.discipline.arbitrary._
import _root_.fx.Structured
import _root_.fx.instances.FxAsync
import _root_.fx.instances.StructuredF
import _root_.fx.structured
import fx.Structured
import org.scalacheck.Cogen
import org.scalacheck.Gen
import org.scalacheck.Prop
import org.scalacheck.PropFromFun
import org.scalacheck.rng.Seed
import org.scalacheck.{Arbitrary => Arb}

import java.util.concurrent.Executors
import scala.concurrent.ExecutionContext
import scala.concurrent.duration.FiniteDuration
import munit.fx.ScalaFXSuite
import munit.DisciplineSuite
import cats.effect.laws.AsyncLaws
import fx.instances.{FxAsync, StructuredF}
import cats.implicits._
import cats.effect.implicits._
import org.scalacheck.{Arbitrary, Gen}
import cats.effect.laws.AsyncTests
import cats.effect.kernel.instances.*
import cats.effect.kernel.testkit.SyncTypeGenerators.arbitrarySyncType

object StructurredFLaws extends DisciplineSuite {
class StructurredFLaws
extends ScalaFXSuite,
DisciplineSuite,
AsyncGenerators[StructuredF],
OutcomeGenerators {

import FxAsync.*

override implicit val arbitraryE: Arb[Throwable] = Arb.arbThrowable

override implicit val F: Async[StructuredF] = FxAsync.asyncInstance

override implicit val cogenE: Cogen[Throwable] = Cogen((seed, _) => seed.next)

override protected implicit val cogenFU: Cogen[StructuredF[Unit]] =
Cogen((seed, _) => seed.next)

override protected implicit val arbitraryFD: Arb[FiniteDuration] = Arb.arbFiniteDuration

override protected implicit val arbitraryEC: Arb[ExecutionContext] = Arb {
Gen.const(ExecutionContext.fromExecutor(Executors.newVirtualThreadPerTaskExecutor()))
}

given arbI: Arb[Int] = Arb.arbInt

given Cogen[Int] = Cogen((seed, _) => seed.next)

given cogenStructuredFA[A]: Cogen[StructuredF[A]] = Cogen((seed, _) => seed.next)

given orderStructuredFFiniteDuration(
using o: Order[FiniteDuration],
s: Structured): Order[StructuredF[FiniteDuration]] =
new Order[StructuredF[FiniteDuration]]:
override def compare(
x: StructuredF[FiniteDuration],
y: StructuredF[FiniteDuration]): Int =
Order[FiniteDuration].compare(x(using s), y(using s))

given Eq[ExecutionContext] with
override def eqv(x: ExecutionContext, y: ExecutionContext): Boolean = x === y

given eqfa[A: Eq](using s: Structured): Eq[StructuredF[A]] = new Eq[StructuredF[A]] {
override def eqv(x: StructuredF[A], y: StructuredF[A]): Boolean =
Eq[A].eqv(x(using s), y(using s))
}

given Eq[Throwable] with
override def eqv(x: Throwable, y: Throwable): Boolean =
x.getMessage == y.getMessage && (x.getCause == null && y.getCause == null) || x
.getCause
.getMessage == y.getCause.getMessage

given arbInt(using Structured): Arb[StructuredF[Int]] = Arb {
Gen.posNum[Int].map[Structured ?=> Int](identity)
}

given arbStrin(using Structured): Arb[StructuredF[String]] = Arb {
Gen.alphaLowerStr.map[Structured ?=> String](identity)
}

given arbUnit(using Structured): Arb[StructuredF[Unit]] = Arb {
Arb.arbUnit.arbitrary.map[Structured ?=> Unit](identity)
}

given arbFAtoB(using Structured): Arb[StructuredF[Int => Int]] = Arb {
Arb.arbFunction1[Int, Int].arbitrary.map[Structured ?=> Int => Int](identity)
}

given arbFBtoC(using Structured): Arb[StructuredF[Int => String]] = Arb {
Arb.arbFunction1[Int, String].arbitrary.map[Structured ?=> Int => String](identity)
}

implicit def boolToProp(fa: StructuredF[Boolean])(using s: Structured): Prop = Prop(
fa(using s))

import FxAsync.{given, *}
testFX("check eq uncancellable") {
structured{
val x: StructuredF[Int] = uncancellable(() => structured{fork(() => 3).join})
val y: StructuredF[Int] = fork(() => 3).join

given arbInt[A: Arbitrary]: Arbitrary[StructuredF[A]] = ???
assertFX(Eq[StructuredF[Int]].eqv(x, y))
}
}

checkAll("StructuredF.AsyncLaws", AsyncTests[StructuredF].async[Int, Int, String])
testFX("StructuredF.AsyncLaws") {
checkAll(
"StructuredF.AsyncLaws",
structured {
AsyncTests[StructuredF].async[Int, Int, String](FiniteDuration(500, "milliseconds"))
})
}
}
39 changes: 39 additions & 0 deletions docs/StructuredFAsyncDiagram.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
classDiagram
class Future~A~
<<interface>> Future~A~
class Fiber~A~
<<interface>> Fiber~A~
Fiber: get() A
Fiber: cancel(mayInterrupt Boolean) Boolean
Future <|-- Fiber : Opaque
class UncancellableFiber~A~
UncancellableFiber: -scope Structured
UncancellableFiber: -underlying Fiber
UncancellableFiber: +fork(Function0 B) UncancellableFiber
UncancellableFiber: +join() A
class CancellableFiber~A~
CancellableFiber: -scope Structured
CancellableFiber: -underlying Fiber
CancellableFiber: +fork(Function0 B) CancellableFiber
CancellableFiber: +cancel(Function0 B) CancellableFiber
CancellableFiber: +join() A
class Structured
Structured: +fork(Function0 B) CancellableFiber
Structured: +uncancellable(Function1 => CancellableFiber) UncancellableFiber
Structured: -scope StructuredTaskScope
Structured: -token UUID
Structured: +name() String
Structured: +newThread() VirtualThread
Structured: -externalFibers List[Fiber]
Structured: +addExternalFiber(fiber Fiber)
Structured: -lock ReentrantLock
Structured: -joinAll() Unit
Structured: +close() Unit
Fiber <.. UncancellableFiber
Fiber <.. CancellableFiber
Structured <.. UncancellableFiber : OwnedBy
Structured <.. CancellableFiber : OwnedBy
class StructuredF~A~
<<interface>> StructuredF~A~
StructuredF <|-- UncancellableFiber
StructuredF <|-- CancellableFiber
4 changes: 2 additions & 2 deletions http-scala-fx/src/test/scala/fx/HttpServerFixtures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ trait HttpServerFixtures:
setup = _ => {
for {
server <- Resource(
HttpServer.create(InetSocketAddress(0), 0),
() => HttpServer.create(InetSocketAddress(0), 0),
(server, _) => server.stop(0))
serverExecutor <- Resource(
Executors.newVirtualThreadPerTaskExecutor,
() => Executors.newVirtualThreadPerTaskExecutor,
(executor, _) => executor.shutdown())
_ = server.setExecutor(serverExecutor)
httpContext = server.createContext("/root", handler)
Expand Down
Loading