0
# DSL Infrastructure
1
2
Core infrastructure for generated protobuf DSL including collection wrappers, proxy types, and annotations for type-safe message building.
3
4
## Capabilities
5
6
### DSL Marker Annotation
7
8
Provides DSL scoping for protocol buffer message generation APIs to prevent accidental access to outer DSL scopes.
9
10
```kotlin { .api }
11
/**
12
* Indicates an API that is part of a DSL to generate protocol buffer messages
13
* Prevents accidental access to receivers from outer scopes in DSL contexts
14
*/
15
@DslMarker
16
@Target(AnnotationTarget.CLASS)
17
@Retention(AnnotationRetention.BINARY)
18
@OnlyForUseByGeneratedProtoCode
19
annotation class ProtoDslMarker
20
```
21
22
**Usage Example:**
23
24
```kotlin
25
// Applied to generated DSL builder classes
26
@ProtoDslMarker
27
class MessageDslBuilder {
28
// DSL methods here
29
}
30
```
31
32
### Generated Code Restriction Annotation
33
34
Restricts API usage to generated protocol buffer code, preventing misuse of internal APIs.
35
36
```kotlin { .api }
37
/**
38
* Opt-in annotation to make it difficult to accidentally use APIs only intended
39
* for use by proto generated code
40
* @param message Error message shown when API is used incorrectly
41
* @param level RequiresOptIn level - ERROR prevents compilation
42
*/
43
@RequiresOptIn(
44
message = "This API is only intended for use by generated protobuf code, the code generator, and their own tests. If this does not describe your code, you should not be using this API.",
45
level = RequiresOptIn.Level.ERROR
46
)
47
@Retention(AnnotationRetention.BINARY)
48
@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.ANNOTATION_CLASS)
49
annotation class OnlyForUseByGeneratedProtoCode
50
```
51
52
### DSL List Wrapper
53
54
Immutable List wrapper with type disambiguation for DSL contexts.
55
56
```kotlin { .api }
57
/**
58
* A simple wrapper around a List with an extra generic parameter that can be used
59
* to disambiguate extension methods for different DSL contexts
60
* @param E the element type
61
* @param P the proxy type for disambiguation
62
*/
63
class DslList<E, P : DslProxy> @OnlyForUseByGeneratedProtoCode constructor(
64
private val delegate: List<E>
65
) : List<E> by delegate {
66
67
override fun iterator(): Iterator<E>
68
override fun listIterator(): ListIterator<E>
69
override fun listIterator(index: Int): ListIterator<E>
70
override fun equals(other: Any?): Boolean
71
override fun hashCode(): Int
72
override fun toString(): String
73
}
74
```
75
76
**Usage Example:**
77
78
```kotlin
79
// Used internally by generated code
80
val dslList: DslList<String, MyMessageProxy> = // ... created by generated code
81
// Standard List operations work
82
val size = dslList.size
83
val firstItem = dslList[0]
84
val isEmpty = dslList.isEmpty()
85
```
86
87
### DSL Map Wrapper
88
89
Immutable Map wrapper with type disambiguation for DSL contexts.
90
91
```kotlin { .api }
92
/**
93
* A simple wrapper around a Map with an extra generic parameter that can be used
94
* to disambiguate extension methods for different DSL contexts
95
* @param K the key type
96
* @param V the value type
97
* @param P the proxy type for disambiguation
98
*/
99
class DslMap<K, V, P : DslProxy> @OnlyForUseByGeneratedProtoCode constructor(
100
private val delegate: Map<K, V>
101
) : Map<K, V> by delegate {
102
103
override val entries: Set<Map.Entry<K, V>>
104
override val keys: Set<K>
105
override val values: Collection<V>
106
override fun equals(other: Any?): Boolean
107
override fun hashCode(): Int
108
override fun toString(): String
109
}
110
```
111
112
**Usage Example:**
113
114
```kotlin
115
// Used internally by generated code
116
val dslMap: DslMap<String, Int, MyMessageProxy> = // ... created by generated code
117
// Standard Map operations work
118
val value = dslMap["key"]
119
val containsKey = dslMap.containsKey("key")
120
val allKeys = dslMap.keys
121
```
122
123
### DSL Proxy Type
124
125
Abstract marker class used for type disambiguation in DSL contexts.
126
127
```kotlin { .api }
128
/**
129
* A type meaningful only for its existence, never intended to be instantiated
130
* Used to provide different extension methods for DslList<Int, FooProxy> vs DslList<Int, BarProxy>
131
*/
132
abstract class DslProxy @OnlyForUseByGeneratedProtoCode protected constructor() {
133
init {
134
throw UnsupportedOperationException("A DslProxy should never be instantiated")
135
}
136
}
137
```
138
139
**Usage Example:**
140
141
```kotlin
142
// Generated proxy types extend DslProxy
143
abstract class MyMessageProxy : DslProxy()
144
145
// Used as type parameter for disambiguation
146
val list1: DslList<Int, MyMessageProxy> = // ...
147
val list2: DslList<Int, OtherMessageProxy> = // ...
148
// These can have different extension methods despite same element type
149
```
150
151
### Extension List
152
153
Specialized List wrapper for protocol buffer extension fields.
154
155
```kotlin { .api }
156
/**
157
* Represents an unmodifiable view of a repeated proto extension field
158
* Like DslList but supports querying the extension field it represents
159
* @param E the element type
160
* @param M the message type that owns this extension
161
*/
162
class ExtensionList<E, M : MessageLite> @OnlyForUseByGeneratedProtoCode constructor(
163
val extension: ExtensionLite<M, List<E>>,
164
private val delegate: List<E>
165
) : List<E> by delegate {
166
167
override fun iterator(): Iterator<E>
168
override fun listIterator(): ListIterator<E>
169
override fun listIterator(index: Int): ListIterator<E>
170
override fun equals(other: Any?): Boolean
171
override fun hashCode(): Int
172
override fun toString(): String
173
}
174
```
175
176
**Usage Example:**
177
178
```kotlin
179
// Used internally by generated code for extension lists
180
val extensionList: ExtensionList<String, MyMessage> = // ... created by generated code
181
// Access the extension definition
182
val extensionDef = extensionList.extension
183
val extensionName = extensionDef.descriptor.name
184
185
// Standard List operations
186
val items = extensionList.toList()
187
val firstItem = extensionList.firstOrNull()
188
```
189
190
## Internal Collection Utilities
191
192
### Unmodifiable Iterator Wrappers
193
194
Internal classes that ensure collections remain unmodifiable even from Java code.
195
196
```kotlin { .api }
197
// Internal utility classes for Java interop safety
198
internal class UnmodifiableIterator<E>(delegate: Iterator<E>) : Iterator<E> by delegate
199
200
internal class UnmodifiableListIterator<E>(delegate: ListIterator<E>) : ListIterator<E> by delegate
201
202
internal open class UnmodifiableCollection<E>(private val delegate: Collection<E>) : Collection<E> by delegate {
203
override fun iterator(): Iterator<E>
204
}
205
206
internal class UnmodifiableSet<E>(delegate: Collection<E>) : UnmodifiableCollection<E>(delegate), Set<E>
207
208
internal class UnmodifiableMapEntry<K, V>(delegate: Map.Entry<K, V>) : Map.Entry<K, V> by delegate
209
210
internal class UnmodifiableMapEntries<K, V>(private val delegate: Set<Map.Entry<K, V>>) :
211
UnmodifiableCollection<Map.Entry<K, V>>(delegate), Set<Map.Entry<K, V>> {
212
override fun iterator(): Iterator<Map.Entry<K, V>>
213
}
214
```
215
216
## Usage Patterns
217
218
### Generated DSL Example
219
220
```kotlin
221
// Example of how these components work together in generated code
222
223
@ProtoDslMarker
224
class PersonDslBuilder @OnlyForUseByGeneratedProtoCode constructor() {
225
private val builder = Person.newBuilder()
226
227
var name: String
228
get() = builder.name
229
set(value) { builder.name = value }
230
231
// DSL collections
232
val hobbies: DslList<String, PersonDslProxy>
233
get() = DslList(builder.hobbiesList)
234
235
val scores: DslMap<String, Int, PersonDslProxy>
236
get() = DslMap(builder.scoresMap)
237
238
@OnlyForUseByGeneratedProtoCode
239
fun build(): Person = builder.build()
240
}
241
242
abstract class PersonDslProxy : DslProxy()
243
244
// DSL usage
245
fun person(init: PersonDslBuilder.() -> Unit): Person {
246
return PersonDslBuilder().apply(init).build()
247
}
248
249
val myPerson = person {
250
name = "John"
251
// hobbies and scores are accessible as read-only collections
252
println("Current hobbies: ${hobbies.size}")
253
}
254
```
255
256
## Types
257
258
```kotlin { .api }
259
// Imported from Java protobuf library
260
import com.google.protobuf.ExtensionLite
261
import com.google.protobuf.MessageLite
262
```
263
264
## Notes
265
266
- All DSL infrastructure components are marked with `@OnlyForUseByGeneratedProtoCode` to prevent misuse
267
- The `DslProxy` class provides type-level disambiguation for extension methods on generic collection types
268
- `DslList` and `DslMap` ensure immutability and provide safe iteration even from Java code
269
- `ExtensionList` combines the functionality of `DslList` with access to the underlying extension definition
270
- The `@ProtoDslMarker` annotation prevents accidental receiver access in nested DSL scopes
271
- All collection wrappers delegate to underlying Java collections while ensuring safety guarantees
272
- These components work together to provide a type-safe, scoped DSL experience for protocol buffer message construction