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

Optimize Modifier serialization in guest code #2253

Merged
merged 8 commits into from
Aug 26, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
New:
- Source-based schema parser is now the default. The `useFir` Gradle property has been removed.
- Introduce a `LoadingStrategy` interface to manage `LazyList` preloading.
- Optimize encoding modifiers in Kotlin/JS.

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.
Expand Down
5 changes: 3 additions & 2 deletions redwood-protocol-guest/api/redwood-protocol-guest.api
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public final class app/cash/redwood/protocol/guest/DefaultGuestProtocolAdapter :
public synthetic fun <init> (Lkotlinx/serialization/json/Json;Ljava/lang/String;Lapp/cash/redwood/protocol/guest/ProtocolWidgetSystemFactory;Lapp/cash/redwood/protocol/guest/ProtocolMismatchHandler;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun appendAdd-ARs5Qwk (IIILapp/cash/redwood/protocol/guest/ProtocolWidget;)V
public fun appendCreate-kyz2zXs (II)V
public fun appendModifierChange-z3jyS0k (ILjava/util/List;)V
public fun appendModifierChange-z3jyS0k (ILapp/cash/redwood/Modifier;)V
public fun appendMove-HpxY78w (IIIII)V
public fun appendPropertyChange-DxQz5cw (IILkotlinx/serialization/KSerializer;Ljava/lang/Object;)V
public fun appendPropertyChange-M7EZMwg (III)V
Expand All @@ -25,7 +25,7 @@ public final class app/cash/redwood/protocol/guest/DefaultGuestProtocolAdapter :
public abstract interface class app/cash/redwood/protocol/guest/GuestProtocolAdapter : app/cash/redwood/protocol/EventSink {
public abstract fun appendAdd-ARs5Qwk (IIILapp/cash/redwood/protocol/guest/ProtocolWidget;)V
public abstract fun appendCreate-kyz2zXs (II)V
public abstract fun appendModifierChange-z3jyS0k (ILjava/util/List;)V
public abstract fun appendModifierChange-z3jyS0k (ILapp/cash/redwood/Modifier;)V
public abstract fun appendMove-HpxY78w (IIIII)V
public abstract fun appendPropertyChange-DxQz5cw (IILkotlinx/serialization/KSerializer;Ljava/lang/Object;)V
public abstract fun appendPropertyChange-M7EZMwg (III)V
Expand Down Expand Up @@ -81,6 +81,7 @@ public final class app/cash/redwood/protocol/guest/ProtocolWidgetChildren : app/
public abstract interface class app/cash/redwood/protocol/guest/ProtocolWidgetSystemFactory {
public abstract fun create (Lapp/cash/redwood/protocol/guest/GuestProtocolAdapter;Lapp/cash/redwood/protocol/guest/ProtocolMismatchHandler;)Lapp/cash/redwood/widget/WidgetSystem;
public static synthetic fun create$default (Lapp/cash/redwood/protocol/guest/ProtocolWidgetSystemFactory;Lapp/cash/redwood/protocol/guest/GuestProtocolAdapter;Lapp/cash/redwood/protocol/guest/ProtocolMismatchHandler;ILjava/lang/Object;)Lapp/cash/redwood/widget/WidgetSystem;
public abstract fun modifierTagAndSerializationStrategy (Lapp/cash/redwood/Modifier$Element;)Lkotlin/Pair;
}

public final class app/cash/redwood/protocol/guest/VersionKt {
Expand Down
5 changes: 3 additions & 2 deletions redwood-protocol-guest/api/redwood-protocol-guest.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ abstract interface app.cash.redwood.protocol.guest/GuestProtocolAdapter : app.ca
abstract fun <#A1: kotlin/Any?> appendPropertyChange(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/PropertyTag, kotlinx.serialization/KSerializer<#A1>, #A1) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendPropertyChange|appendPropertyChange(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.PropertyTag;kotlinx.serialization.KSerializer<0:0>;0:0){0§<kotlin.Any?>}[0]
abstract fun appendAdd(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/ChildrenTag, kotlin/Int, app.cash.redwood.protocol.guest/ProtocolWidget) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendAdd|appendAdd(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.ChildrenTag;kotlin.Int;app.cash.redwood.protocol.guest.ProtocolWidget){}[0]
abstract fun appendCreate(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/WidgetTag) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendCreate|appendCreate(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.WidgetTag){}[0]
abstract fun appendModifierChange(app.cash.redwood.protocol/Id, kotlin.collections/List<app.cash.redwood.protocol/ModifierElement>) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendModifierChange|appendModifierChange(app.cash.redwood.protocol.Id;kotlin.collections.List<app.cash.redwood.protocol.ModifierElement>){}[0]
abstract fun appendModifierChange(app.cash.redwood.protocol/Id, app.cash.redwood/Modifier) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendModifierChange|appendModifierChange(app.cash.redwood.protocol.Id;app.cash.redwood.Modifier){}[0]
abstract fun appendMove(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/ChildrenTag, kotlin/Int, kotlin/Int, kotlin/Int) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendMove|appendMove(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.ChildrenTag;kotlin.Int;kotlin.Int;kotlin.Int){}[0]
abstract fun appendPropertyChange(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/PropertyTag, kotlin/Boolean) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendPropertyChange|appendPropertyChange(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.PropertyTag;kotlin.Boolean){}[0]
abstract fun appendPropertyChange(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/PropertyTag, kotlin/UInt) // app.cash.redwood.protocol.guest/GuestProtocolAdapter.appendPropertyChange|appendPropertyChange(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.PropertyTag;kotlin.UInt){}[0]
Expand Down Expand Up @@ -53,6 +53,7 @@ abstract interface app.cash.redwood.protocol.guest/ProtocolWidget : app.cash.red
}

abstract interface app.cash.redwood.protocol.guest/ProtocolWidgetSystemFactory { // app.cash.redwood.protocol.guest/ProtocolWidgetSystemFactory|null[0]
abstract fun <#A1: app.cash.redwood/Modifier.Element> modifierTagAndSerializationStrategy(#A1): kotlin/Pair<app.cash.redwood.protocol/ModifierTag, kotlinx.serialization/SerializationStrategy<#A1>?> // app.cash.redwood.protocol.guest/ProtocolWidgetSystemFactory.modifierTagAndSerializationStrategy|modifierTagAndSerializationStrategy(0:0){0§<app.cash.redwood.Modifier.Element>}[0]
abstract fun create(app.cash.redwood.protocol.guest/GuestProtocolAdapter, app.cash.redwood.protocol.guest/ProtocolMismatchHandler = ...): app.cash.redwood.widget/WidgetSystem<kotlin/Unit> // app.cash.redwood.protocol.guest/ProtocolWidgetSystemFactory.create|create(app.cash.redwood.protocol.guest.GuestProtocolAdapter;app.cash.redwood.protocol.guest.ProtocolMismatchHandler){}[0]
}

Expand All @@ -71,7 +72,7 @@ final class app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter : app.ca
final fun <#A1: kotlin/Any?> appendPropertyChange(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/PropertyTag, kotlinx.serialization/KSerializer<#A1>, #A1) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendPropertyChange|appendPropertyChange(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.PropertyTag;kotlinx.serialization.KSerializer<0:0>;0:0){0§<kotlin.Any?>}[0]
final fun appendAdd(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/ChildrenTag, kotlin/Int, app.cash.redwood.protocol.guest/ProtocolWidget) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendAdd|appendAdd(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.ChildrenTag;kotlin.Int;app.cash.redwood.protocol.guest.ProtocolWidget){}[0]
final fun appendCreate(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/WidgetTag) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendCreate|appendCreate(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.WidgetTag){}[0]
final fun appendModifierChange(app.cash.redwood.protocol/Id, kotlin.collections/List<app.cash.redwood.protocol/ModifierElement>) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendModifierChange|appendModifierChange(app.cash.redwood.protocol.Id;kotlin.collections.List<app.cash.redwood.protocol.ModifierElement>){}[0]
final fun appendModifierChange(app.cash.redwood.protocol/Id, app.cash.redwood/Modifier) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendModifierChange|appendModifierChange(app.cash.redwood.protocol.Id;app.cash.redwood.Modifier){}[0]
final fun appendMove(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/ChildrenTag, kotlin/Int, kotlin/Int, kotlin/Int) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendMove|appendMove(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.ChildrenTag;kotlin.Int;kotlin.Int;kotlin.Int){}[0]
final fun appendPropertyChange(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/PropertyTag, kotlin/Boolean) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendPropertyChange|appendPropertyChange(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.PropertyTag;kotlin.Boolean){}[0]
final fun appendPropertyChange(app.cash.redwood.protocol/Id, app.cash.redwood.protocol/PropertyTag, kotlin/UInt) // app.cash.redwood.protocol.guest/DefaultGuestProtocolAdapter.appendPropertyChange|appendPropertyChange(app.cash.redwood.protocol.Id;app.cash.redwood.protocol.PropertyTag;kotlin.UInt){}[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package app.cash.redwood.protocol.guest

import app.cash.redwood.Modifier
import app.cash.redwood.RedwoodCodegenApi
import app.cash.redwood.protocol.Change
import app.cash.redwood.protocol.ChangesSink
Expand All @@ -41,7 +42,7 @@ import kotlinx.serialization.json.JsonPrimitive
public class DefaultGuestProtocolAdapter(
public override val json: Json = Json.Default,
hostVersion: RedwoodVersion,
widgetSystemFactory: ProtocolWidgetSystemFactory,
private val widgetSystemFactory: ProtocolWidgetSystemFactory,
private val mismatchHandler: ProtocolMismatchHandler = ProtocolMismatchHandler.Throwing,
) : GuestProtocolAdapter {
private var nextValue = Id.Root.value + 1
Expand Down Expand Up @@ -111,13 +112,22 @@ public class DefaultGuestProtocolAdapter(
changes.add(PropertyChange(id, tag, JsonPrimitive(value)))
}

public override fun appendModifierChange(
id: Id,
elements: List<ModifierElement>,
) {
override fun appendModifierChange(id: Id, value: Modifier) {
val elements = mutableListOf<ModifierElement>()

value.forEach { element ->
elements += modifierElement(element)
}

changes.add(ModifierChange(id, elements))
}

private fun <T : Modifier.Element> modifierElement(element: T): ModifierElement {
val (tag, serializer) = widgetSystemFactory.modifierTagAndSerializationStrategy(element)
if (serializer == null) return ModifierElement(tag)
return ModifierElement(tag, json.encodeToJsonElement(serializer, element))
}

public override fun appendAdd(
id: Id,
tag: ChildrenTag,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
*/
package app.cash.redwood.protocol.guest

import app.cash.redwood.Modifier
import app.cash.redwood.RedwoodCodegenApi
import app.cash.redwood.protocol.ChangesSink
import app.cash.redwood.protocol.ChildrenTag
import app.cash.redwood.protocol.EventSink
import app.cash.redwood.protocol.Id
import app.cash.redwood.protocol.ModifierElement
import app.cash.redwood.protocol.PropertyTag
import app.cash.redwood.protocol.WidgetTag
import app.cash.redwood.widget.Widget
Expand Down Expand Up @@ -106,7 +106,7 @@ public interface GuestProtocolAdapter : EventSink {
@RedwoodCodegenApi
public fun appendModifierChange(
id: Id,
elements: List<ModifierElement>,
value: Modifier,
)

@RedwoodCodegenApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@
*/
package app.cash.redwood.protocol.guest

import app.cash.redwood.Modifier
import app.cash.redwood.RedwoodCodegenApi
import app.cash.redwood.protocol.ModifierTag
import app.cash.redwood.widget.WidgetSystem
import kotlinx.serialization.SerializationStrategy

public interface ProtocolWidgetSystemFactory {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With these two new APIs I don’t think the Factory name fit as well as it did previously.

/** Create a new [WidgetSystem] connected to a host via [guestAdapter]. */
public fun create(
guestAdapter: GuestProtocolAdapter,
mismatchHandler: ProtocolMismatchHandler = ProtocolMismatchHandler.Throwing,
): WidgetSystem<Unit>

/** The serialization strategy is null if the modifier is stateless. */
@RedwoodCodegenApi
public fun <T : Modifier.Element> modifierTagAndSerializationStrategy(
element: T,
): Pair<ModifierTag, SerializationStrategy<T>?>
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ internal fun ProtocolSchemaSet.generateFileSpecs(type: ProtocolCodegenType): Lis
when (type) {
Guest -> {
add(generateProtocolWidgetSystemFactory(this@generateFileSpecs))
add(generateComposeProtocolModifierSerialization(this@generateFileSpecs))
for (dependency in all) {
add(generateProtocolWidgetFactory(dependency, host = schema))
generateProtocolModifierSerializers(dependency, host = schema)?.let { add(it) }
Expand Down
Loading