or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

any-message-operations.mdbytestring-extensions.mddsl-infrastructure.mdextension-field-access.mdindex.md

dsl-infrastructure.mddocs/

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