Skip to content

Commit 3d0f2d1

Browse files
authored
Shuffle where schema tag offsetting occurs (#2586)
The old mechanism was based on our now deleted reflection-based parser.
1 parent 6d22974 commit 3d0f2d1

File tree

5 files changed

+42
-42
lines changed

5 files changed

+42
-42
lines changed

redwood-tooling-schema/api/redwood-tooling-schema.api

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public abstract interface class app/cash/redwood/tooling/schema/ProtocolSchema :
9999
public abstract fun getTaggedDependencies ()Ljava/util/Map;
100100
public abstract fun getWidgets ()Ljava/util/List;
101101
public abstract fun toEmbeddedSchema ()Lapp/cash/redwood/tooling/schema/EmbeddedSchema;
102+
public abstract fun withTagOffset (I)Lapp/cash/redwood/tooling/schema/ProtocolSchema;
102103
}
103104

104105
public abstract interface class app/cash/redwood/tooling/schema/ProtocolSchemaSet : app/cash/redwood/tooling/schema/SchemaSet {

redwood-tooling-schema/src/main/kotlin/app/cash/redwood/tooling/schema/schemaApi.kt

+3
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ public interface ProtocolSchema : Schema {
154154
* This JSON will be read when the schema is used as a dependency.
155155
*/
156156
public fun toEmbeddedSchema(): EmbeddedSchema
157+
158+
/** Return a copy of this schema with all widget and modifier tags adjusted by [offset]. */
159+
public fun withTagOffset(offset: Int): ProtocolSchema
157160
}
158161

159162
public interface ProtocolWidget : Widget {

redwood-tooling-schema/src/main/kotlin/app/cash/redwood/tooling/schema/schemaImpls.kt

+13-16
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,24 @@ internal data class ParsedProtocolSchema(
6464
)
6565
}
6666

67+
override fun withTagOffset(offset: Int): ParsedProtocolSchema {
68+
return copy(
69+
widgets = widgets.map { widget ->
70+
widget.copy(tag = offset + widget.tag)
71+
},
72+
modifiers = modifiers.map { modifier ->
73+
modifier.copy(tag = offset + modifier.tag)
74+
},
75+
)
76+
}
77+
6778
companion object {
6879
fun toEmbeddedPath(type: FqType): String {
6980
return type.names[0].replace('.', '/') + "/" + type.names.drop(1).joinToString(".") + ".json"
7081
}
7182

72-
fun parseEmbeddedJson(json: String, tagOffset: Int = 0): ProtocolSchema {
73-
val schema = jsonFormat.decodeFromString(serializer(), json)
74-
if (tagOffset == 0) {
75-
return schema
76-
}
77-
// The schema JSON was generated locally from at its source with its normal tag numbers.
78-
// If we are consuming it as a tagged dependency, offset the widget and modifier tag numbers
79-
// to simplify usage downstream.
80-
return schema.copy(
81-
widgets = schema.widgets.map { widget ->
82-
widget.copy(tag = tagOffset + widget.tag)
83-
},
84-
modifiers = schema.modifiers.map { modifier ->
85-
modifier.copy(tag = tagOffset + modifier.tag)
86-
},
87-
)
83+
fun parseEmbeddedJson(json: String): ProtocolSchema {
84+
return jsonFormat.decodeFromString(serializer(), json)
8885
}
8986

9087
@OptIn(ExperimentalSerializationApi::class) // For custom indent, which is only a nice-to-have.

redwood-tooling-schema/src/main/kotlin/app/cash/redwood/tooling/schema/schemaParser.kt

+14-17
Original file line numberDiff line numberDiff line change
@@ -34,36 +34,33 @@ internal fun loadProtocolSchemaDependencies(
3434
): ParsedProtocolSchemaSet {
3535
val dependencies = schema.taggedDependencies.entries
3636
.associate { (tag, type) ->
37-
require(tag != 0) { "Dependency $type tag must be non-zero" }
38-
type to loadProtocolSchema(type, classLoader, tag)
37+
require(tag in 1..MAX_SCHEMA_TAG) {
38+
"Dependency $type tag must be in range (0, $MAX_SCHEMA_TAG]: $tag"
39+
}
40+
val dependency = loadProtocolSchema(type, classLoader)
41+
.withTagOffset(tag * MAX_MEMBER_TAG)
42+
43+
require(dependency.dependencies.isEmpty()) {
44+
"Schema dependency $type also has its own dependencies. " +
45+
"For now, only a single level of dependencies is supported."
46+
}
47+
48+
type to dependency
3949
}
4050
return ParsedProtocolSchemaSet(schema, dependencies)
4151
}
4252

4353
internal fun loadProtocolSchema(
4454
type: FqType,
4555
classLoader: ClassLoader,
46-
tag: Int = 0,
4756
): ProtocolSchema {
48-
require(tag in 0..MAX_SCHEMA_TAG) {
49-
"$type tag must be 0 for the root or in range (0, $MAX_SCHEMA_TAG] as a dependency: $tag"
50-
}
51-
val tagOffset = tag * MAX_MEMBER_TAG
52-
5357
val path = ParsedProtocolSchema.toEmbeddedPath(type)
54-
val schema = classLoader
58+
return classLoader
5559
.getResourceAsStream(path)
5660
?.use(InputStream::readBytes)
5761
?.decodeToString()
58-
?.let { json -> ParsedProtocolSchema.parseEmbeddedJson(json, tagOffset) }
62+
?.let { json -> ParsedProtocolSchema.parseEmbeddedJson(json) }
5963
?: throw IllegalArgumentException("Unable to locate JSON for $type at $path")
60-
61-
require(tag == 0 || schema.dependencies.isEmpty()) {
62-
"Schema dependency $type also has its own dependencies. " +
63-
"For now, only a single level of dependencies is supported."
64-
}
65-
66-
return schema
6764
}
6865

6966
/** Returns true if [memberType] is a known special modifier tag and name. */

redwood-tooling-schema/src/test/kotlin/app/cash/redwood/tooling/schema/SchemaParserTest.kt

+11-9
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,14 @@ class SchemaParserTest {
11001100
)
11011101
object SchemaDependencyTagTooHigh
11021102

1103+
@Test fun dependencyTagTooHighThrows() {
1104+
assertFailure { parseTestSchema(SchemaDependencyTagTooHigh::class) }
1105+
.isInstanceOf<IllegalArgumentException>()
1106+
.hasMessage(
1107+
"Dependency app.cash.redwood.layout.RedwoodLayout tag must be in range (0, 2000]: 2001",
1108+
)
1109+
}
1110+
11031111
@Schema(
11041112
members = [],
11051113
dependencies = [
@@ -1108,17 +1116,11 @@ class SchemaParserTest {
11081116
)
11091117
object SchemaDependencyTagTooLow
11101118

1111-
@Test fun dependencyTagTooHighThrows() {
1112-
assertFailure { parseTestSchema(SchemaDependencyTagTooHigh::class) }
1113-
.isInstanceOf<IllegalArgumentException>()
1114-
.hasMessage(
1115-
"app.cash.redwood.layout.RedwoodLayout tag must be 0 for the root or in range (0, 2000] as a dependency: 2001",
1116-
)
1117-
1119+
@Test fun dependencyTagTooLowThrows() {
11181120
assertFailure { parseTestSchema(SchemaDependencyTagTooLow::class) }
11191121
.isInstanceOf<IllegalArgumentException>()
11201122
.hasMessage(
1121-
"app.cash.redwood.layout.RedwoodLayout tag must be 0 for the root or in range (0, 2000] as a dependency: -1",
1123+
"Dependency app.cash.redwood.layout.RedwoodLayout tag must be in range (0, 2000]: -1",
11221124
)
11231125
}
11241126

@@ -1134,7 +1136,7 @@ class SchemaParserTest {
11341136
assertFailure { parseTestSchema(SchemaDependencyTagZero::class) }
11351137
.isInstanceOf<IllegalArgumentException>()
11361138
.hasMessage(
1137-
"Dependency app.cash.redwood.layout.RedwoodLayout tag must be non-zero",
1139+
"Dependency app.cash.redwood.layout.RedwoodLayout tag must be in range (0, 2000]: 0",
11381140
)
11391141
}
11401142

0 commit comments

Comments
 (0)