From c5afb1b1c8a5c246016ae42d0a5ba39e5a9e410e Mon Sep 17 00:00:00 2001
From: Arman Bilge
Date: Thu, 26 Jan 2023 19:33:11 +0000
Subject: [PATCH 1/6] `EventProp` is a `Functor`
---
calico/src/main/scala/calico/html/Prop.scala | 13 +++++++++++--
.../scala/calico/html/codegen/CalicoGenerator.scala | 2 +-
.../calico/html/codegen/DomDefsGenerator.scala | 7 +++++--
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/calico/src/main/scala/calico/html/Prop.scala b/calico/src/main/scala/calico/html/Prop.scala
index a1988c8c..76743036 100644
--- a/calico/src/main/scala/calico/html/Prop.scala
+++ b/calico/src/main/scala/calico/html/Prop.scala
@@ -18,6 +18,7 @@ package calico
package html
import calico.syntax.*
+import cats.Functor
import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.syntax.all.*
@@ -133,15 +134,23 @@ private trait PropModifiers[F[_]](using F: Async[F]):
Modifier.forSignalResource[F, Any, OptionSignalResourceModifier[F, Any, Any], Option[Any]](
_.values) { (m, n) => setPropOption(n, m.name, m.codec) }
-final class EventProp[F[_], E] private[calico] (key: String):
+sealed abstract class EventProp[F[_], E, A] private[calico]:
import EventProp.*
- inline def -->(sink: Pipe[F, E, Nothing]): PipeModifier[F, E] = PipeModifier(key, sink)
+ def -->(sink: Pipe[F, A, Nothing]): PipeModifier[F, E]
object EventProp:
+ def apply[F[_], E](key: String): EventProp[F, E, E] = new:
+ def -->(sink: Pipe[F, E, Nothing]) = PipeModifier(key, sink)
+
final class PipeModifier[F[_], E](
private[calico] val key: String,
private[calico] val sink: Pipe[F, E, Nothing])
+ given [F[_], E]: Functor[EventProp[F, E, _]] = new:
+ def map[A, B](fa: EventProp[F, E, A])(f: A => B): EventProp[F, E, B] = new:
+ def -->(sink: Pipe[F, B, Nothing]) =
+ fa --> (_.map(f).through(sink))
+
private trait EventPropModifiers[F[_]](using F: Async[F]):
import EventProp.*
inline given forPipeEventProp[T <: fs2.dom.Node[F], E]: Modifier[F, T, PipeModifier[F, E]] =
diff --git a/project/src/main/scala/calico/html/codegen/CalicoGenerator.scala b/project/src/main/scala/calico/html/codegen/CalicoGenerator.scala
index f9e0a6af..cbbe2ae3 100644
--- a/project/src/main/scala/calico/html/codegen/CalicoGenerator.scala
+++ b/project/src/main/scala/calico/html/codegen/CalicoGenerator.scala
@@ -248,7 +248,7 @@ private[codegen] class CalicoGenerator(srcManaged: File)
val baseImplDef =
if (outputBaseImpl)
List(
- s"@inline private[calico] def ${keyImplName}[Ev <: ${baseScalaJsEventType}](key: String): ${keyKind}[F, Ev] = ${keyKindConstructor(keyKind)}(key)"
+ s"@inline private[calico] def ${keyImplName}[Ev <: ${baseScalaJsEventType}](key: String): ${keyKind}[F, Ev, Ev] = ${keyKind}(key)"
)
else {
Nil
diff --git a/project/src/main/scala/calico/html/codegen/DomDefsGenerator.scala b/project/src/main/scala/calico/html/codegen/DomDefsGenerator.scala
index fedb107d..56d28c92 100644
--- a/project/src/main/scala/calico/html/codegen/DomDefsGenerator.scala
+++ b/project/src/main/scala/calico/html/codegen/DomDefsGenerator.scala
@@ -278,7 +278,9 @@ object DomDefsGenerator {
case (key, vals) =>
(
key,
- vals.map(attr => attr.copy(scalaJsEventType = "F, " + attr.scalaJsEventType)))
+ vals.map(attr =>
+ attr.copy(scalaJsEventType =
+ s"F, ${attr.scalaJsEventType}, ${attr.scalaJsEventType}")))
},
printDefGroupComments = true,
traitCommentLines = Nil,
@@ -311,7 +313,8 @@ object DomDefsGenerator {
(
key,
vals.map(attr =>
- attr.copy(scalaJsEventType = "F, " + attr.scalaJsEventType)))
+ attr.copy(scalaJsEventType =
+ s"F, ${attr.scalaJsEventType}, ${attr.scalaJsEventType}")))
},
printDefGroupComments = true,
traitCommentLines = List(eventPropsDefGroups.head._1),
From e1585f8a23ed48ce2a84ce5dabd79710c0f1d7a4 Mon Sep 17 00:00:00 2001
From: Arman Bilge
Date: Thu, 26 Jan 2023 19:42:43 +0000
Subject: [PATCH 2/6] And also `FunctorFilter`
---
calico/src/main/scala/calico/html/Prop.scala | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/calico/src/main/scala/calico/html/Prop.scala b/calico/src/main/scala/calico/html/Prop.scala
index 76743036..b1f9adf6 100644
--- a/calico/src/main/scala/calico/html/Prop.scala
+++ b/calico/src/main/scala/calico/html/Prop.scala
@@ -19,6 +19,7 @@ package html
import calico.syntax.*
import cats.Functor
+import cats.FunctorFilter
import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.syntax.all.*
@@ -151,6 +152,12 @@ object EventProp:
def -->(sink: Pipe[F, B, Nothing]) =
fa --> (_.map(f).through(sink))
+ given [F[_], E]: FunctorFilter[EventProp[F, E, _]] = new:
+ def functor = summon
+ def mapFilter[A, B](fa: EventProp[F, E, A])(f: A => Option[B]): EventProp[F, E, B] = new:
+ def -->(sink: Pipe[F, B, Nothing]) =
+ fa --> (_.mapFilter(f).through(sink))
+
private trait EventPropModifiers[F[_]](using F: Async[F]):
import EventProp.*
inline given forPipeEventProp[T <: fs2.dom.Node[F], E]: Modifier[F, T, PipeModifier[F, E]] =
From 76f660200bdfd75acca4a3c940adbeac88306fd4 Mon Sep 17 00:00:00 2001
From: Arman Bilge
Date: Thu, 26 Jan 2023 19:52:41 +0000
Subject: [PATCH 3/6] Minimize allocations
---
calico/src/main/scala/calico/html/Prop.scala | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/calico/src/main/scala/calico/html/Prop.scala b/calico/src/main/scala/calico/html/Prop.scala
index b1f9adf6..59c9d3c4 100644
--- a/calico/src/main/scala/calico/html/Prop.scala
+++ b/calico/src/main/scala/calico/html/Prop.scala
@@ -20,6 +20,7 @@ package html
import calico.syntax.*
import cats.Functor
import cats.FunctorFilter
+import cats.Id
import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.syntax.all.*
@@ -147,15 +148,19 @@ object EventProp:
private[calico] val key: String,
private[calico] val sink: Pipe[F, E, Nothing])
- given [F[_], E]: Functor[EventProp[F, E, _]] = new:
- def map[A, B](fa: EventProp[F, E, A])(f: A => B): EventProp[F, E, B] = new:
- def -->(sink: Pipe[F, B, Nothing]) =
+ inline given [F[_], E]: Functor[EventProp[F, E, _]] =
+ _functor.asInstanceOf[Functor[EventProp[F, E, _]]]
+ private val _functor: Functor[EventProp[Id, Any, _]] = new:
+ def map[A, B](fa: EventProp[Id, Any, A])(f: A => B) = new:
+ def -->(sink: Pipe[Id, B, Nothing]) =
fa --> (_.map(f).through(sink))
- given [F[_], E]: FunctorFilter[EventProp[F, E, _]] = new:
- def functor = summon
- def mapFilter[A, B](fa: EventProp[F, E, A])(f: A => Option[B]): EventProp[F, E, B] = new:
- def -->(sink: Pipe[F, B, Nothing]) =
+ inline given [F[_], E]: FunctorFilter[EventProp[F, E, _]] =
+ _functorFilter.asInstanceOf[FunctorFilter[EventProp[F, E, _]]]
+ private val _functorFilter: FunctorFilter[EventProp[Id, Any, _]] = new:
+ def functor = _functor
+ def mapFilter[A, B](fa: EventProp[Id, Any, A])(f: A => Option[B]) = new:
+ def -->(sink: Pipe[Id, B, Nothing]) =
fa --> (_.mapFilter(f).through(sink))
private trait EventPropModifiers[F[_]](using F: Async[F]):
From 033738a4496b975f50190602ef518ad6c055ca15 Mon Sep 17 00:00:00 2001
From: Arman Bilge
Date: Thu, 26 Jan 2023 20:00:50 +0000
Subject: [PATCH 4/6] Aggregate instances
---
calico/src/main/scala/calico/html/Prop.scala | 25 +++++++++-----------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/calico/src/main/scala/calico/html/Prop.scala b/calico/src/main/scala/calico/html/Prop.scala
index 59c9d3c4..df92799b 100644
--- a/calico/src/main/scala/calico/html/Prop.scala
+++ b/calico/src/main/scala/calico/html/Prop.scala
@@ -148,20 +148,17 @@ object EventProp:
private[calico] val key: String,
private[calico] val sink: Pipe[F, E, Nothing])
- inline given [F[_], E]: Functor[EventProp[F, E, _]] =
- _functor.asInstanceOf[Functor[EventProp[F, E, _]]]
- private val _functor: Functor[EventProp[Id, Any, _]] = new:
- def map[A, B](fa: EventProp[Id, Any, A])(f: A => B) = new:
- def -->(sink: Pipe[Id, B, Nothing]) =
- fa --> (_.map(f).through(sink))
-
- inline given [F[_], E]: FunctorFilter[EventProp[F, E, _]] =
- _functorFilter.asInstanceOf[FunctorFilter[EventProp[F, E, _]]]
- private val _functorFilter: FunctorFilter[EventProp[Id, Any, _]] = new:
- def functor = _functor
- def mapFilter[A, B](fa: EventProp[Id, Any, A])(f: A => Option[B]) = new:
- def -->(sink: Pipe[Id, B, Nothing]) =
- fa --> (_.mapFilter(f).through(sink))
+ inline given [F[_], E]: (Functor[EventProp[F, E, _]] & FunctorFilter[EventProp[F, E, _]]) =
+ _functor.asInstanceOf[Functor[EventProp[F, E, _]] & FunctorFilter[EventProp[F, E, _]]]
+ private val _functor: Functor[EventProp[Id, Any, _]] & FunctorFilter[EventProp[Id, Any, _]] =
+ new Functor[EventProp[Id, Any, _]] with FunctorFilter[EventProp[Id, Any, _]]:
+ def map[A, B](fa: EventProp[Id, Any, A])(f: A => B) = new:
+ def -->(sink: Pipe[Id, B, Nothing]) =
+ fa --> (_.map(f).through(sink))
+ def functor = this
+ def mapFilter[A, B](fa: EventProp[Id, Any, A])(f: A => Option[B]) = new:
+ def -->(sink: Pipe[Id, B, Nothing]) =
+ fa --> (_.mapFilter(f).through(sink))
private trait EventPropModifiers[F[_]](using F: Async[F]):
import EventProp.*
From 2b690ff3b540a331b8ee01672f3010cd3bbc4a7a Mon Sep 17 00:00:00 2001
From: Arman Bilge
Date: Thu, 26 Jan 2023 23:46:17 +0000
Subject: [PATCH 5/6] Try a different encoding
---
calico/src/main/scala/calico/html/Prop.scala | 22 +++++++++++---------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/calico/src/main/scala/calico/html/Prop.scala b/calico/src/main/scala/calico/html/Prop.scala
index df92799b..d4e41496 100644
--- a/calico/src/main/scala/calico/html/Prop.scala
+++ b/calico/src/main/scala/calico/html/Prop.scala
@@ -136,13 +136,18 @@ private trait PropModifiers[F[_]](using F: Async[F]):
Modifier.forSignalResource[F, Any, OptionSignalResourceModifier[F, Any, Any], Option[Any]](
_.values) { (m, n) => setPropOption(n, m.name, m.codec) }
-sealed abstract class EventProp[F[_], E, A] private[calico]:
+final class EventProp[F[_], E, A] private[calico] (key: String, pipe: Pipe[F, E, A]):
import EventProp.*
- def -->(sink: Pipe[F, A, Nothing]): PipeModifier[F, E]
+
+ @inline def -->(sink: Pipe[F, A, Nothing]): PipeModifier[F, E] =
+ PipeModifier(key, pipe.andThen(sink))
+
+ private def through[B](pipe: Pipe[F, A, B]): EventProp[F, E, B] =
+ new EventProp(key, this.pipe.andThen(pipe))
object EventProp:
- def apply[F[_], E](key: String): EventProp[F, E, E] = new:
- def -->(sink: Pipe[F, E, Nothing]) = PipeModifier(key, sink)
+ def apply[F[_], E](key: String): EventProp[F, E, E] =
+ new EventProp(key, identity(_))
final class PipeModifier[F[_], E](
private[calico] val key: String,
@@ -152,13 +157,10 @@ object EventProp:
_functor.asInstanceOf[Functor[EventProp[F, E, _]] & FunctorFilter[EventProp[F, E, _]]]
private val _functor: Functor[EventProp[Id, Any, _]] & FunctorFilter[EventProp[Id, Any, _]] =
new Functor[EventProp[Id, Any, _]] with FunctorFilter[EventProp[Id, Any, _]]:
- def map[A, B](fa: EventProp[Id, Any, A])(f: A => B) = new:
- def -->(sink: Pipe[Id, B, Nothing]) =
- fa --> (_.map(f).through(sink))
+ def map[A, B](fa: EventProp[Id, Any, A])(f: A => B) = fa.through(_.map(f))
def functor = this
- def mapFilter[A, B](fa: EventProp[Id, Any, A])(f: A => Option[B]) = new:
- def -->(sink: Pipe[Id, B, Nothing]) =
- fa --> (_.mapFilter(f).through(sink))
+ def mapFilter[A, B](fa: EventProp[Id, Any, A])(f: A => Option[B]) =
+ fa.through(_.mapFilter(f))
private trait EventPropModifiers[F[_]](using F: Async[F]):
import EventProp.*
From 603483195b8fda9e8b51af612904b9bd6fa3e25d Mon Sep 17 00:00:00 2001
From: Arman Bilge
Date: Thu, 26 Jan 2023 23:48:00 +0000
Subject: [PATCH 6/6] Fix visibility, inline
---
calico/src/main/scala/calico/html/Prop.scala | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/calico/src/main/scala/calico/html/Prop.scala b/calico/src/main/scala/calico/html/Prop.scala
index d4e41496..04f3bd50 100644
--- a/calico/src/main/scala/calico/html/Prop.scala
+++ b/calico/src/main/scala/calico/html/Prop.scala
@@ -142,14 +142,14 @@ final class EventProp[F[_], E, A] private[calico] (key: String, pipe: Pipe[F, E,
@inline def -->(sink: Pipe[F, A, Nothing]): PipeModifier[F, E] =
PipeModifier(key, pipe.andThen(sink))
- private def through[B](pipe: Pipe[F, A, B]): EventProp[F, E, B] =
+ @inline private def through[B](pipe: Pipe[F, A, B]): EventProp[F, E, B] =
new EventProp(key, this.pipe.andThen(pipe))
object EventProp:
def apply[F[_], E](key: String): EventProp[F, E, E] =
new EventProp(key, identity(_))
- final class PipeModifier[F[_], E](
+ final class PipeModifier[F[_], E] private[calico] (
private[calico] val key: String,
private[calico] val sink: Pipe[F, E, Nothing])