Skip to content

Commit

Permalink
Revert "Defer serializing event args to JSON (#2218)" (#2239)
Browse files Browse the repository at this point in the history
This reverts commit 4010e12.
  • Loading branch information
dnagler authored Aug 7, 2024
1 parent c9830cc commit 5f8ca01
Show file tree
Hide file tree
Showing 15 changed files with 73 additions and 185 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ New:
- Introduce a `LoadingStrategy` interface to manage `LazyList` preloading.

Changed:
- In Treehouse, events from the UI are now serialized on a background thread. This means that there is both a delay and a thread change between when a UI binding sends an event and when that object is converted to JSON. All arguments to events must not be mutable and support property reads on any thread. Best practice is for all event arguments to be completely immutable.
- `ProtocolFactory` interface is now sealed as arbitrary subtypes were never supported. Only schema-generated subtypes should be used.

Fixed:
Expand Down
21 changes: 2 additions & 19 deletions redwood-protocol-host/api/redwood-protocol-host.api
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public abstract interface class app/cash/redwood/protocol/host/GeneratedProtocol
}

public final class app/cash/redwood/protocol/host/HostProtocolAdapter : app/cash/redwood/protocol/ChangesSink {
public synthetic fun <init> (Ljava/lang/String;Lapp/cash/redwood/widget/Widget$Children;Lapp/cash/redwood/protocol/host/ProtocolFactory;Lapp/cash/redwood/protocol/host/UiEventSink;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;Lapp/cash/redwood/widget/Widget$Children;Lapp/cash/redwood/protocol/host/ProtocolFactory;Lapp/cash/redwood/protocol/EventSink;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun close ()V
public fun sendChanges (Ljava/util/List;)V
}
Expand Down Expand Up @@ -35,7 +35,7 @@ public final class app/cash/redwood/protocol/host/ProtocolMismatchHandler$Compan

public abstract class app/cash/redwood/protocol/host/ProtocolNode {
public synthetic fun <init> (IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public abstract fun apply (Lapp/cash/redwood/protocol/PropertyChange;Lapp/cash/redwood/protocol/host/UiEventSink;)V
public abstract fun apply (Lapp/cash/redwood/protocol/PropertyChange;Lapp/cash/redwood/protocol/EventSink;)V
public abstract fun children-dBpC-2Y (I)Lapp/cash/redwood/protocol/host/ProtocolChildren;
public abstract fun detach ()V
public final fun getId-0HhLjSo ()I
Expand All @@ -45,23 +45,6 @@ public abstract class app/cash/redwood/protocol/host/ProtocolNode {
public abstract fun visitIds (Lkotlin/jvm/functions/Function1;)V
}

public final class app/cash/redwood/protocol/host/UiEvent {
public synthetic fun <init> (IILjava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (IILjava/util/List;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getArgs ()Ljava/util/List;
public final fun getId-0HhLjSo ()I
public final fun getSerializationStrategies ()Ljava/util/List;
public final fun getTag-RNF89mI ()I
public fun hashCode ()I
public final fun toProtocol (Lkotlinx/serialization/json/Json;)Lapp/cash/redwood/protocol/Event;
public fun toString ()Ljava/lang/String;
}

public abstract interface class app/cash/redwood/protocol/host/UiEventSink {
public abstract fun sendEvent (Lapp/cash/redwood/protocol/host/UiEvent;)V
}

public final class app/cash/redwood/protocol/host/VersionKt {
public static final fun getHostRedwoodVersion ()Ljava/lang/String;
}
Expand Down
26 changes: 2 additions & 24 deletions redwood-protocol-host/api/redwood-protocol-host.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
// - Show declarations: true

// Library unique name: <app.cash.redwood:redwood-protocol-host>
abstract fun interface app.cash.redwood.protocol.host/UiEventSink { // app.cash.redwood.protocol.host/UiEventSink|null[0]
abstract fun sendEvent(app.cash.redwood.protocol.host/UiEvent) // app.cash.redwood.protocol.host/UiEventSink.sendEvent|sendEvent(app.cash.redwood.protocol.host.UiEvent){}[0]
}

abstract interface <#A: kotlin/Any> app.cash.redwood.protocol.host/GeneratedProtocolFactory : app.cash.redwood.protocol.host/ProtocolFactory<#A> { // app.cash.redwood.protocol.host/GeneratedProtocolFactory|null[0]
abstract fun createModifier(app.cash.redwood.protocol/ModifierElement): app.cash.redwood/Modifier // app.cash.redwood.protocol.host/GeneratedProtocolFactory.createModifier|createModifier(app.cash.redwood.protocol.ModifierElement){}[0]
abstract fun createNode(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/WidgetTag): app.cash.redwood.protocol.host/ProtocolNode<#A>? // app.cash.redwood.protocol.host/GeneratedProtocolFactory.createNode|createNode(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.WidgetTag){}[0]
Expand Down Expand Up @@ -43,15 +39,15 @@ abstract class <#A: kotlin/Any> app.cash.redwood.protocol.host/ProtocolNode { //
final val widgetTag // app.cash.redwood.protocol.host/ProtocolNode.widgetTag|{}widgetTag[0]
final fun <get-widgetTag>(): app.cash.redwood.protocol/WidgetTag // app.cash.redwood.protocol.host/ProtocolNode.widgetTag.<get-widgetTag>|<get-widgetTag>(){}[0]

abstract fun apply(app.cash.redwood.protocol/PropertyChange, app.cash.redwood.protocol.host/UiEventSink) // app.cash.redwood.protocol.host/ProtocolNode.apply|apply(app.cash.redwood.protocol.PropertyChange;app.cash.redwood.protocol.host.UiEventSink){}[0]
abstract fun apply(app.cash.redwood.protocol/PropertyChange, app.cash.redwood.protocol/EventSink) // app.cash.redwood.protocol.host/ProtocolNode.apply|apply(app.cash.redwood.protocol.PropertyChange;app.cash.redwood.protocol.EventSink){}[0]
abstract fun children(app.cash.redwood.protocol/ChildrenTag): app.cash.redwood.protocol.host/ProtocolChildren<#A>? // app.cash.redwood.protocol.host/ProtocolNode.children|children(app.cash.redwood.protocol.ChildrenTag){}[0]
abstract fun detach() // app.cash.redwood.protocol.host/ProtocolNode.detach|detach(){}[0]
abstract fun visitIds(kotlin/Function1<app.cash.redwood.protocol/Id, kotlin/Unit>) // app.cash.redwood.protocol.host/ProtocolNode.visitIds|visitIds(kotlin.Function1<app.cash.redwood.protocol.Id,kotlin.Unit>){}[0]
final fun updateModifier(app.cash.redwood/Modifier) // app.cash.redwood.protocol.host/ProtocolNode.updateModifier|updateModifier(app.cash.redwood.Modifier){}[0]
}

final class <#A: kotlin/Any> app.cash.redwood.protocol.host/HostProtocolAdapter : app.cash.redwood.protocol/ChangesSink { // app.cash.redwood.protocol.host/HostProtocolAdapter|null[0]
constructor <init>(app.cash.redwood.protocol/RedwoodVersion, app.cash.redwood.widget/Widget.Children<#A>, app.cash.redwood.protocol.host/ProtocolFactory<#A>, app.cash.redwood.protocol.host/UiEventSink) // app.cash.redwood.protocol.host/HostProtocolAdapter.<init>|<init>(app.cash.redwood.protocol.RedwoodVersion;app.cash.redwood.widget.Widget.Children<1:0>;app.cash.redwood.protocol.host.ProtocolFactory<1:0>;app.cash.redwood.protocol.host.UiEventSink){}[0]
constructor <init>(app.cash.redwood.protocol/RedwoodVersion, app.cash.redwood.widget/Widget.Children<#A>, app.cash.redwood.protocol.host/ProtocolFactory<#A>, app.cash.redwood.protocol/EventSink) // app.cash.redwood.protocol.host/HostProtocolAdapter.<init>|<init>(app.cash.redwood.protocol.RedwoodVersion;app.cash.redwood.widget.Widget.Children<1:0>;app.cash.redwood.protocol.host.ProtocolFactory<1:0>;app.cash.redwood.protocol.EventSink){}[0]

final fun close() // app.cash.redwood.protocol.host/HostProtocolAdapter.close|close(){}[0]
final fun sendChanges(kotlin.collections/List<app.cash.redwood.protocol/Change>) // app.cash.redwood.protocol.host/HostProtocolAdapter.sendChanges|sendChanges(kotlin.collections.List<app.cash.redwood.protocol.Change>){}[0]
Expand All @@ -67,23 +63,5 @@ final class <#A: kotlin/Any> app.cash.redwood.protocol.host/ProtocolChildren { /
final fun visitIds(kotlin/Function1<app.cash.redwood.protocol/Id, kotlin/Unit>) // app.cash.redwood.protocol.host/ProtocolChildren.visitIds|visitIds(kotlin.Function1<app.cash.redwood.protocol.Id,kotlin.Unit>){}[0]
}

final class app.cash.redwood.protocol.host/UiEvent { // app.cash.redwood.protocol.host/UiEvent|null[0]
constructor <init>(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/EventTag, kotlin.collections/List<kotlin/Any?> = ..., kotlin.collections/List<kotlinx.serialization/SerializationStrategy<kotlin/Any?>> = ...) // app.cash.redwood.protocol.host/UiEvent.<init>|<init>(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.EventTag;kotlin.collections.List<kotlin.Any?>;kotlin.collections.List<kotlinx.serialization.SerializationStrategy<kotlin.Any?>>){}[0]

final val args // app.cash.redwood.protocol.host/UiEvent.args|{}args[0]
final fun <get-args>(): kotlin.collections/List<kotlin/Any?> // app.cash.redwood.protocol.host/UiEvent.args.<get-args>|<get-args>(){}[0]
final val id // app.cash.redwood.protocol.host/UiEvent.id|{}id[0]
final fun <get-id>(): app.cash.redwood.protocol/Id // app.cash.redwood.protocol.host/UiEvent.id.<get-id>|<get-id>(){}[0]
final val serializationStrategies // app.cash.redwood.protocol.host/UiEvent.serializationStrategies|{}serializationStrategies[0]
final fun <get-serializationStrategies>(): kotlin.collections/List<kotlinx.serialization/SerializationStrategy<kotlin/Any?>> // app.cash.redwood.protocol.host/UiEvent.serializationStrategies.<get-serializationStrategies>|<get-serializationStrategies>(){}[0]
final val tag // app.cash.redwood.protocol.host/UiEvent.tag|{}tag[0]
final fun <get-tag>(): app.cash.redwood.protocol/EventTag // app.cash.redwood.protocol.host/UiEvent.tag.<get-tag>|<get-tag>(){}[0]

final fun equals(kotlin/Any?): kotlin/Boolean // app.cash.redwood.protocol.host/UiEvent.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // app.cash.redwood.protocol.host/UiEvent.hashCode|hashCode(){}[0]
final fun toProtocol(kotlinx.serialization.json/Json): app.cash.redwood.protocol/Event // app.cash.redwood.protocol.host/UiEvent.toProtocol|toProtocol(kotlinx.serialization.json.Json){}[0]
final fun toString(): kotlin/String // app.cash.redwood.protocol.host/UiEvent.toString|toString(){}[0]
}

final val app.cash.redwood.protocol.host/hostRedwoodVersion // app.cash.redwood.protocol.host/hostRedwoodVersion|{}hostRedwoodVersion[0]
final fun <get-hostRedwoodVersion>(): app.cash.redwood.protocol/RedwoodVersion // app.cash.redwood.protocol.host/hostRedwoodVersion.<get-hostRedwoodVersion>|<get-hostRedwoodVersion>(){}[0]
1 change: 0 additions & 1 deletion redwood-protocol-host/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ redwoodBuild {
}

apply plugin: 'com.github.gmazzo.buildconfig'
apply plugin: 'dev.drewhamilton.poko'

kotlin {
sourceSets {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import app.cash.redwood.protocol.ChildrenChange.Move
import app.cash.redwood.protocol.ChildrenChange.Remove
import app.cash.redwood.protocol.ChildrenTag
import app.cash.redwood.protocol.Create
import app.cash.redwood.protocol.EventSink
import app.cash.redwood.protocol.Id
import app.cash.redwood.protocol.ModifierChange
import app.cash.redwood.protocol.PropertyChange
Expand All @@ -49,7 +50,7 @@ public class HostProtocolAdapter<W : Any>(
guestVersion: RedwoodVersion,
container: Widget.Children<W>,
factory: ProtocolFactory<W>,
private val eventSink: UiEventSink,
private val eventSink: EventSink,
) : ChangesSink {
private val factory = requireNotNull(factory as? GeneratedProtocolFactory<W>) {
"Factory ${factory::class} was not generated by Redwood or is out of date"
Expand Down Expand Up @@ -377,7 +378,7 @@ private class RootProtocolNode<W : Any>(
Widget<W> {
private val children = ProtocolChildren(children)

override fun apply(change: PropertyChange, eventSink: UiEventSink) {
override fun apply(change: PropertyChange, eventSink: EventSink) {
throw AssertionError("unexpected: $change")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package app.cash.redwood.protocol.host
import app.cash.redwood.Modifier
import app.cash.redwood.RedwoodCodegenApi
import app.cash.redwood.protocol.ChildrenTag
import app.cash.redwood.protocol.EventSink
import app.cash.redwood.protocol.Id
import app.cash.redwood.protocol.PropertyChange
import app.cash.redwood.protocol.WidgetTag
Expand Down Expand Up @@ -47,7 +48,7 @@ public abstract class ProtocolNode<W : Any>(
/** Assigned when the node is added to the pool. */
internal var shapeHash = 0L

public abstract fun apply(change: PropertyChange, eventSink: UiEventSink)
public abstract fun apply(change: PropertyChange, eventSink: EventSink)

public fun updateModifier(modifier: Modifier) {
widget.modifier = modifier
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package app.cash.redwood.protocol.host
import app.cash.redwood.Modifier
import app.cash.redwood.RedwoodCodegenApi
import app.cash.redwood.protocol.ChildrenTag
import app.cash.redwood.protocol.EventSink
import app.cash.redwood.protocol.Id
import app.cash.redwood.protocol.PropertyChange
import app.cash.redwood.protocol.WidgetTag
Expand Down Expand Up @@ -127,7 +128,7 @@ class ChildrenNodeIndexTest {

@OptIn(RedwoodCodegenApi::class)
private class WidgetNode(override val widget: StringWidget) : ProtocolNode<String>(Id(1), WidgetTag(1)) {
override fun apply(change: PropertyChange, eventSink: UiEventSink) {
override fun apply(change: PropertyChange, eventSink: EventSink) {
throw UnsupportedOperationException()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import app.cash.redwood.layout.testing.RedwoodLayoutTestingWidgetFactory
import app.cash.redwood.lazylayout.testing.RedwoodLazyLayoutTestingWidgetFactory
import app.cash.redwood.protocol.ChildrenTag
import app.cash.redwood.protocol.Event
import app.cash.redwood.protocol.EventSink
import app.cash.redwood.protocol.EventTag
import app.cash.redwood.protocol.Id
import app.cash.redwood.protocol.ModifierElement
Expand Down Expand Up @@ -257,7 +258,7 @@ class ProtocolFactoryTest {
)
val textInput = factory.createNode(Id(1), WidgetTag(5))!!

val throwingEventSink = UiEventSink { error(it) }
val throwingEventSink = EventSink { error(it) }
textInput.apply(PropertyChange(Id(1), PropertyTag(2), JsonPrimitive("PT10S")), throwingEventSink)

assertThat((textInput.widget.value as TextInputValue).customType).isEqualTo(10.seconds)
Expand All @@ -274,7 +275,7 @@ class ProtocolFactoryTest {
val button = factory.createNode(Id(1), WidgetTag(4))!!

val change = PropertyChange(Id(1), PropertyTag(345432))
val eventSink = UiEventSink { throw UnsupportedOperationException() }
val eventSink = EventSink { throw UnsupportedOperationException() }
val t = assertFailsWith<IllegalArgumentException> {
button.apply(change, eventSink)
}
Expand Down Expand Up @@ -314,12 +315,12 @@ class ProtocolFactoryTest {
)
val textInput = factory.createNode(Id(1), WidgetTag(5))!!

val eventSink = RecordingUiEventSink()
val eventSink = RecordingEventSink()
textInput.apply(PropertyChange(Id(1), PropertyTag(4), JsonPrimitive(true)), eventSink)

(textInput.widget.value as TextInputValue).onChangeCustomType!!.invoke(10.seconds)

assertThat(eventSink.events.single().toProtocol(json))
assertThat(eventSink.events.single())
.isEqualTo(Event(Id(1), EventTag(4), listOf(JsonPrimitive("PT10S"))))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
*/
package app.cash.redwood.protocol.host

class RecordingUiEventSink : UiEventSink {
val events = mutableListOf<UiEvent>()
import app.cash.redwood.protocol.Event
import app.cash.redwood.protocol.EventSink

override fun sendEvent(uiEvent: UiEvent) {
events += uiEvent
class RecordingEventSink : EventSink {
val events = mutableListOf<Event>()

override fun sendEvent(event: Event) {
events += event
}
}
Loading

0 comments on commit 5f8ca01

Please sign in to comment.