Skip to content

Commit 62a6349

Browse files
authored
Rework nullability; separate map entry template (#48)
1 parent 45c78de commit 62a6349

19 files changed

+433
-263
lines changed

protokt-codegen/src/main/kotlin/com/toasttab/protokt/codegen/impl/AnnotatorUtils.kt

+18-5
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,30 @@ import com.toasttab.protokt.codegen.protoc.TypeDesc
2626
import com.toasttab.protokt.codegen.protoc.respectJavaPackage
2727
import com.toasttab.protokt.codegen.template.Renderers.ConcatWithScope
2828

29-
internal fun resolveMapEntry(m: Message, ctx: Context) =
30-
MapTypeParams(
31-
(m.fields[0] as StandardField).unqualifiedTypeName,
32-
(m.fields[1] as StandardField).typePClass.renderName(ctx.pkg)
29+
internal fun resolveMapEntry(m: Message) =
30+
MapEntryInfo(
31+
(m.fields[0] as StandardField),
32+
(m.fields[1] as StandardField)
3333
)
3434

35-
internal data class MapTypeParams(
35+
internal fun resolveMapEntryTypes(m: Message, ctx: Context) =
36+
resolveMapEntry(m).let {
37+
MapTypeParams(
38+
it.key.unqualifiedTypeName,
39+
it.value.typePClass.renderName(ctx.pkg)
40+
)
41+
}
42+
43+
internal class MapTypeParams(
3644
val kType: String,
3745
val vType: String
3846
)
3947

48+
internal class MapEntryInfo(
49+
val key: StandardField,
50+
val value: StandardField
51+
)
52+
4053
internal fun oneOfScope(f: Oneof, type: String, ctx: Context) =
4154
ctx.stripEnclosingMessageNamePrefix(
4255
ctx.stripRootMessageNamePrefix(

protokt-codegen/src/main/kotlin/com/toasttab/protokt/codegen/impl/DeserializerAnnotator.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,15 @@ private constructor(
130130
type = type,
131131
builder =
132132
when (type) {
133-
FieldType.ENUM, FieldType.MESSAGE -> stripQualification(ctx, this)
133+
FieldType.ENUM, FieldType.MESSAGE -> stripQualification(this)
134134
else -> ""
135135
}
136136
)
137137

138-
private fun stripQualification(ctx: Context, f: StandardField) =
139-
stripEnclosingMessageName(f.typePClass.renderName(ctx.pkg), ctx)
138+
private fun stripQualification(f: StandardField) =
139+
stripEnclosingMessageName(f.typePClass.renderName(ctx.pkg))
140140

141-
private fun stripEnclosingMessageName(s: String, ctx: Context): String {
141+
private fun stripEnclosingMessageName(s: String): String {
142142
var stripped = s
143143
for (enclosing in ctx.enclosingMessage.reversed()) {
144144
if (stripped.startsWith(enclosing.name)) {

protokt-codegen/src/main/kotlin/com/toasttab/protokt/codegen/impl/MapEntryAnnotator.kt

+82-11
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,88 @@
1515

1616
package com.toasttab.protokt.codegen.impl
1717

18+
import com.toasttab.protokt.codegen.impl.DeserializerAnnotator.Companion.annotateDeserializer
19+
import com.toasttab.protokt.codegen.impl.PropertyAnnotator.Companion.annotateProperties
1820
import com.toasttab.protokt.codegen.impl.STAnnotator.Context
21+
import com.toasttab.protokt.codegen.impl.SerializerAnnotator.Companion.annotateSerializer
22+
import com.toasttab.protokt.codegen.impl.SizeofAnnotator.Companion.annotateSizeof
1923
import com.toasttab.protokt.codegen.protoc.Message
20-
import com.toasttab.protokt.codegen.template.Message.Message.MapEntryInfo
21-
22-
internal object MapEntryAnnotator {
23-
fun annotateMapEntry(m: Message, ctx: Context) =
24-
if (m.mapEntry) {
25-
resolveMapEntry(m, ctx).let { (k, v) ->
26-
MapEntryInfo(true, k, v)
27-
}
28-
} else {
29-
MapEntryInfo(false, "", "")
30-
}
24+
import com.toasttab.protokt.codegen.protoc.StandardField
25+
import com.toasttab.protokt.codegen.template.Entry.Entry
26+
import com.toasttab.protokt.codegen.template.Entry.Entry.DeserializerInfo
27+
import com.toasttab.protokt.codegen.template.Message.Message as MessageTemplate
28+
29+
class MapEntryAnnotator
30+
private constructor(
31+
private val msg: Message,
32+
private val ctx: Context
33+
) {
34+
private fun annotateMapEntry(): String {
35+
val entryInfo = resolveMapEntry(msg)
36+
val desInfo = annotateDeserializer(msg, ctx)
37+
val sizeInfo = annotateSizeof(msg, ctx)
38+
val serInfo = annotateSerializer(msg, ctx)
39+
val propInfo = annotateProperties(msg, ctx)
40+
41+
return Entry.render(
42+
name = msg.name,
43+
key =
44+
prop(
45+
entryInfo.key,
46+
entryInfo.key.unqualifiedTypeName,
47+
sizeInfo,
48+
serInfo,
49+
desInfo,
50+
propInfo
51+
),
52+
value =
53+
prop(
54+
entryInfo.value,
55+
entryInfo.value.typePClass.renderName(ctx.pkg),
56+
sizeInfo,
57+
serInfo,
58+
desInfo,
59+
propInfo
60+
)
61+
)
62+
}
63+
64+
private fun prop(
65+
f: StandardField,
66+
type: String,
67+
sizeofInfo: List<MessageTemplate.SizeofInfo>,
68+
serializerInfo: List<MessageTemplate.SerializerInfo>,
69+
deserializerInfo: List<MessageTemplate.DeserializerInfo>,
70+
propInfo: List<MessageTemplate.PropertyInfo>
71+
) =
72+
Entry.PropertyInfo(
73+
propertyType = type,
74+
messageType = f.type.toString(),
75+
deserializeType = propInfo.single(f).deserializeType,
76+
sizeof = sizeofInfo.consequent(f),
77+
serialize = serializerInfo.consequent(f),
78+
defaultValue = propInfo.single(f).defaultValue,
79+
deserialize =
80+
deserializerInfo.single(f).let {
81+
DeserializerInfo(
82+
tag = it.tag,
83+
assignment = it.assignment.value
84+
)
85+
}
86+
)
87+
88+
private fun <T : MessageTemplate.FieldInfo> List<T>.single(
89+
f: StandardField
90+
) =
91+
single { it.name == f.fieldName }
92+
93+
private fun List<MessageTemplate.FieldWriteInfo>.consequent(
94+
f: StandardField
95+
) =
96+
single(f).conditionals.single().consequent
97+
98+
companion object {
99+
fun annotateMapEntry(msg: Message, ctx: Context) =
100+
MapEntryAnnotator(msg, ctx).annotateMapEntry()
101+
}
31102
}

protokt-codegen/src/main/kotlin/com/toasttab/protokt/codegen/impl/MessageAnnotator.kt

+22-19
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import com.toasttab.protokt.codegen.impl.Deprecation.renderOptions
2222
import com.toasttab.protokt.codegen.impl.DeserializerAnnotator.Companion.annotateDeserializer
2323
import com.toasttab.protokt.codegen.impl.Implements.doesImplement
2424
import com.toasttab.protokt.codegen.impl.Implements.implements
25-
import com.toasttab.protokt.codegen.impl.MapEntryAnnotator.annotateMapEntry
25+
import com.toasttab.protokt.codegen.impl.MapEntryAnnotator.Companion.annotateMapEntry
2626
import com.toasttab.protokt.codegen.impl.MessageDocumentationAnnotator.annotateMessageDocumentation
2727
import com.toasttab.protokt.codegen.impl.OneofAnnotator.Companion.annotateOneOfs
2828
import com.toasttab.protokt.codegen.impl.PropertyAnnotator.Companion.annotateProperties
@@ -43,17 +43,20 @@ internal object MessageAnnotator {
4343
msg: Message,
4444
ctx: Context
4545
) =
46-
MessageTemplate.render(
47-
message = messageInfo(msg, ctx),
48-
entry = annotateMapEntry(msg, ctx),
49-
properties = annotateProperties(msg, ctx),
50-
oneofs = annotateOneOfs(msg, ctx),
51-
sizeof = annotateSizeof(msg, ctx),
52-
serialize = annotateSerializer(msg, ctx),
53-
deserialize = annotateDeserializer(msg, ctx),
54-
nested = nestedTypes(msg, ctx),
55-
options = options(msg, ctx)
56-
)
46+
if (msg.mapEntry) {
47+
annotateMapEntry(msg, ctx)
48+
} else {
49+
MessageTemplate.render(
50+
message = messageInfo(msg, ctx),
51+
properties = annotateProperties(msg, ctx),
52+
oneofs = annotateOneOfs(msg, ctx),
53+
sizeof = annotateSizeof(msg, ctx),
54+
serialize = annotateSerializer(msg, ctx),
55+
deserialize = annotateDeserializer(msg, ctx),
56+
nested = nestedTypes(msg, ctx),
57+
options = options(msg, ctx)
58+
)
59+
}
5760

5861
private fun nestedTypes(msg: Message, ctx: Context) =
5962
msg.nestedTypes.map { annotate(it, ctx) }
@@ -65,13 +68,13 @@ internal object MessageAnnotator {
6568
implements = msg.implements,
6669
documentation = annotateMessageDocumentation(ctx),
6770
deprecation =
68-
if (msg.options.default.deprecated) {
69-
renderOptions(
70-
msg.options.protokt.deprecationMessage
71-
)
72-
} else {
73-
null
74-
},
71+
if (msg.options.default.deprecated) {
72+
renderOptions(
73+
msg.options.protokt.deprecationMessage
74+
)
75+
} else {
76+
null
77+
},
7578
suppressDeprecation = msg.hasDeprecation &&
7679
(!enclosingDeprecation(ctx) ||
7780
ctx.enclosingMessage.firstOption()

protokt-codegen/src/main/kotlin/com/toasttab/protokt/codegen/impl/NonNullable.kt

-41
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2020 Toast Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
package com.toasttab.protokt.codegen.impl
17+
18+
import com.toasttab.protokt.codegen.impl.Wrapper.wrapped
19+
import com.toasttab.protokt.codegen.model.FieldType
20+
import com.toasttab.protokt.codegen.protoc.Field
21+
import com.toasttab.protokt.codegen.protoc.Oneof
22+
import com.toasttab.protokt.codegen.protoc.StandardField
23+
24+
internal object Nullability {
25+
val Field.hasNonNullOption
26+
get() =
27+
when (this) {
28+
is StandardField -> options.protokt.nonNull
29+
is Oneof -> options.protokt.nonNull
30+
}
31+
32+
val Field.nullable
33+
get() =
34+
isKotlinRepresentationNullable && !hasNonNullOption
35+
36+
private val Field.isKotlinRepresentationNullable
37+
get() =
38+
when (this) {
39+
is StandardField -> type == FieldType.MESSAGE && !repeated
40+
is Oneof -> true
41+
}
42+
43+
private val StandardField.isWrappedNonRepeatedPrimitive
44+
get() =
45+
wrapped &&
46+
!repeated &&
47+
type !in setOf(FieldType.MESSAGE, FieldType.ENUM)
48+
49+
fun propertyType(o: Oneof) =
50+
if (o.hasNonNullOption) {
51+
o.name
52+
} else {
53+
o.renderNullableType()
54+
}
55+
56+
fun propertyType(f: StandardField, type: String) =
57+
if (f.nullable) {
58+
renderNullable(type)
59+
} else {
60+
type
61+
}
62+
63+
fun deserializeType(f: StandardField, type: String) =
64+
if (
65+
f.repeated ||
66+
f.nullable ||
67+
f.isKotlinRepresentationNullable ||
68+
f.isWrappedNonRepeatedPrimitive
69+
) {
70+
renderNullable(type)
71+
} else {
72+
type
73+
}
74+
75+
fun dslPropertyType(f: StandardField, type: String) =
76+
if (
77+
f.isKotlinRepresentationNullable ||
78+
f.isWrappedNonRepeatedPrimitive
79+
) {
80+
renderNullable(type)
81+
} else {
82+
type
83+
}
84+
85+
fun Oneof.renderNullableType() =
86+
renderNullable(name)
87+
88+
private fun renderNullable(s: String) =
89+
"$s?"
90+
}

0 commit comments

Comments
 (0)