or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

any-message.mdenum-support.mdfield-annotations.mdindex.mdmessage-framework.mdproto-adapters.mdprotobuf-io.mdtime-types.md

proto-adapters.mddocs/

0

# Proto Adapters

1

2

Type-safe encoding and decoding adapters for all protocol buffer types. ProtoAdapter provides a unified interface for serializing and deserializing protobuf values, with built-in adapters for all scalar types, collections, and Google Well-Known Types.

3

4

## Capabilities

5

6

### ProtoAdapter Base Class

7

8

Abstract base class that defines the interface for encoding and decoding protocol buffer values with type safety and metadata.

9

10

```kotlin { .api }

11

/**

12

* Abstract adapter for encoding and decoding protocol buffer values

13

* @param E The type this adapter handles

14

* @param fieldEncoding The wire encoding used for this type

15

* @param type The Kotlin class of the type

16

* @param typeUrl Type URL for google.protobuf.Any (null for non-messages)

17

* @param syntax Proto syntax version (proto2 or proto3)

18

* @param identity Identity value for proto3 (omitted when encoding)

19

* @param sourceFile Source .proto file path

20

*/

21

expect abstract class ProtoAdapter<E>(

22

fieldEncoding: FieldEncoding,

23

type: KClass<*>?,

24

typeUrl: String?,

25

syntax: Syntax,

26

identity: E? = null,

27

sourceFile: String? = null

28

) {

29

internal val fieldEncoding: FieldEncoding

30

val type: KClass<*>?

31

val typeUrl: String?

32

val syntax: Syntax

33

val identity: E?

34

val sourceFile: String?

35

36

/** Returns redacted form of value */

37

abstract fun redact(value: E): E

38

39

/** Size of non-null data value (excluding length prefix) */

40

abstract fun encodedSize(value: E): Int

41

42

/** Size of tag and value in wire format */

43

open fun encodedSizeWithTag(tag: Int, value: E?): Int

44

45

/** Write non-null value to writer */

46

@Throws(IOException::class)

47

abstract fun encode(writer: ProtoWriter, value: E)

48

49

/** Write non-null value to reverse writer */

50

@Throws(IOException::class)

51

open fun encode(writer: ReverseProtoWriter, value: E)

52

53

/** Write tag and value to writer */

54

@Throws(IOException::class)

55

open fun encodeWithTag(writer: ProtoWriter, tag: Int, value: E?)

56

57

/** Write tag and value to reverse writer */

58

@Throws(IOException::class)

59

open fun encodeWithTag(writer: ReverseProtoWriter, tag: Int, value: E?)

60

61

/** Encode value and write to sink */

62

@Throws(IOException::class)

63

fun encode(sink: BufferedSink, value: E)

64

65

/** Encode value as byte array */

66

fun encode(value: E): ByteArray

67

68

/** Encode value as ByteString */

69

fun encodeByteString(value: E): ByteString

70

71

/** Read non-null value from reader */

72

@Throws(IOException::class)

73

abstract fun decode(reader: ProtoReader): E

74

75

/** Read encoded message from bytes */

76

@Throws(IOException::class)

77

fun decode(bytes: ByteArray): E

78

79

/** Read encoded message from ByteString */

80

@Throws(IOException::class)

81

fun decode(bytes: ByteString): E

82

83

/** Read encoded message from source */

84

@Throws(IOException::class)

85

fun decode(source: BufferedSource): E

86

87

/** Try to decode value, append to destination if successful */

88

@Throws(IOException::class)

89

fun tryDecode(reader: ProtoReader, destination: MutableList<E>)

90

91

/** Human-readable version of value */

92

open fun toString(value: E): String

93

94

/** Create adapter with specified label */

95

internal fun withLabel(label: WireField.Label): ProtoAdapter<*>

96

97

/** Return adapter for packed repeated values */

98

fun asPacked(): ProtoAdapter<List<E>>

99

100

/** Return adapter for repeated values */

101

fun asRepeated(): ProtoAdapter<List<E>>

102

}

103

```

104

105

**Usage Examples:**

106

107

```kotlin

108

import com.squareup.wire.*

109

import okio.Buffer

110

111

// Using built-in adapters

112

val stringValue = "Hello, Wire!"

113

val encoded = ProtoAdapter.STRING.encode(stringValue)

114

val decoded = ProtoAdapter.STRING.decode(encoded)

115

116

// Working with tags

117

val buffer = Buffer()

118

val writer = ProtoWriter(buffer)

119

ProtoAdapter.STRING.encodeWithTag(writer, 1, stringValue)

120

ProtoAdapter.INT32.encodeWithTag(writer, 2, 42)

121

122

val reader = ProtoReader(buffer)

123

reader.forEachTag { tag ->

124

when (tag) {

125

1 -> {

126

val str = ProtoAdapter.STRING.decode(reader)

127

println("String field: $str")

128

}

129

2 -> {

130

val num = ProtoAdapter.INT32.decode(reader)

131

println("Number field: $num")

132

}

133

}

134

}

135

136

// Size calculation

137

val size = ProtoAdapter.STRING.encodedSize("test")

138

val sizeWithTag = ProtoAdapter.STRING.encodedSizeWithTag(1, "test")

139

140

// Repeated fields

141

val numbers = listOf(1, 2, 3, 4, 5)

142

val packedAdapter = ProtoAdapter.INT32.asPacked()

143

val encodedList = packedAdapter.encode(numbers)

144

val decodedList = packedAdapter.decode(encodedList)

145

```

146

147

### Built-in Scalar Adapters

148

149

Predefined adapters for all protocol buffer scalar types with proper wire encoding.

150

151

```kotlin { .api }

152

companion object {

153

/** Boolean adapter (varint encoding: 0/1) */

154

@JvmField val BOOL: ProtoAdapter<Boolean>

155

156

/** 32-bit signed integer adapter */

157

@JvmField val INT32: ProtoAdapter<Int>

158

159

/** 32-bit unsigned integer adapter */

160

@JvmField val UINT32: ProtoAdapter<Int>

161

162

/** 32-bit signed integer with ZigZag encoding */

163

@JvmField val SINT32: ProtoAdapter<Int>

164

165

/** 32-bit fixed-length integer */

166

@JvmField val FIXED32: ProtoAdapter<Int>

167

168

/** 32-bit signed fixed-length integer */

169

@JvmField val SFIXED32: ProtoAdapter<Int>

170

171

/** 64-bit signed integer adapter */

172

@JvmField val INT64: ProtoAdapter<Long>

173

174

/** 64-bit unsigned integer adapter */

175

@JvmField val UINT64: ProtoAdapter<Long>

176

177

/** 64-bit signed integer with ZigZag encoding */

178

@JvmField val SINT64: ProtoAdapter<Long>

179

180

/** 64-bit fixed-length integer */

181

@JvmField val FIXED64: ProtoAdapter<Long>

182

183

/** 64-bit signed fixed-length integer */

184

@JvmField val SFIXED64: ProtoAdapter<Long>

185

186

/** 32-bit floating point adapter */

187

@JvmField val FLOAT: ProtoAdapter<Float>

188

189

/** 64-bit floating point adapter */

190

@JvmField val DOUBLE: ProtoAdapter<Double>

191

192

/** Binary data adapter */

193

@JvmField val BYTES: ProtoAdapter<ByteString>

194

195

/** UTF-8 string adapter */

196

@JvmField val STRING: ProtoAdapter<String>

197

}

198

```

199

200

### Array Adapters

201

202

Specialized adapters for primitive arrays providing more efficient encoding than repeated fields.

203

204

```kotlin { .api }

205

companion object {

206

/** 32-bit integer array adapter (packed encoding) */

207

@JvmField val INT32_ARRAY: ProtoAdapter<IntArray>

208

@JvmField val UINT32_ARRAY: ProtoAdapter<IntArray>

209

@JvmField val SINT32_ARRAY: ProtoAdapter<IntArray>

210

@JvmField val FIXED32_ARRAY: ProtoAdapter<IntArray>

211

@JvmField val SFIXED32_ARRAY: ProtoAdapter<IntArray>

212

213

/** 64-bit integer array adapter (packed encoding) */

214

@JvmField val INT64_ARRAY: ProtoAdapter<LongArray>

215

@JvmField val UINT64_ARRAY: ProtoAdapter<LongArray>

216

@JvmField val SINT64_ARRAY: ProtoAdapter<LongArray>

217

@JvmField val FIXED64_ARRAY: ProtoAdapter<LongArray>

218

@JvmField val SFIXED64_ARRAY: ProtoAdapter<LongArray>

219

220

/** Floating point array adapters (packed encoding) */

221

@JvmField val FLOAT_ARRAY: ProtoAdapter<FloatArray>

222

@JvmField val DOUBLE_ARRAY: ProtoAdapter<DoubleArray>

223

}

224

```

225

226

### Well-Known Type Adapters

227

228

Adapters for Google Well-Known Types with proper proto3 semantics.

229

230

```kotlin { .api }

231

companion object {

232

/** Duration adapter (google.protobuf.Duration) */

233

@JvmField val DURATION: ProtoAdapter<Duration>

234

235

/** Timestamp adapter (google.protobuf.Timestamp) */

236

@JvmField val INSTANT: ProtoAdapter<Instant>

237

238

/** Empty message adapter (google.protobuf.Empty) */

239

@JvmField val EMPTY: ProtoAdapter<Unit>

240

241

/** Struct map adapter (google.protobuf.Struct) */

242

@JvmField val STRUCT_MAP: ProtoAdapter<Map<String, *>?>

243

244

/** List value adapter (google.protobuf.ListValue) */

245

@JvmField val STRUCT_LIST: ProtoAdapter<List<*>?>

246

247

/** Null value adapter (google.protobuf.NullValue) */

248

@JvmField val STRUCT_NULL: ProtoAdapter<Nothing?>

249

250

/** Value adapter (google.protobuf.Value) */

251

@JvmField val STRUCT_VALUE: ProtoAdapter<Any?>

252

}

253

```

254

255

### Wrapper Type Adapters

256

257

Adapters for protocol buffer wrapper types that handle null values and identity omission in proto3.

258

259

```kotlin { .api }

260

companion object {

261

/** Double wrapper adapter (google.protobuf.DoubleValue) */

262

@JvmField val DOUBLE_VALUE: ProtoAdapter<Double?>

263

264

/** Float wrapper adapter (google.protobuf.FloatValue) */

265

@JvmField val FLOAT_VALUE: ProtoAdapter<Float?>

266

267

/** Int64 wrapper adapter (google.protobuf.Int64Value) */

268

@JvmField val INT64_VALUE: ProtoAdapter<Long?>

269

270

/** UInt64 wrapper adapter (google.protobuf.UInt64Value) */

271

@JvmField val UINT64_VALUE: ProtoAdapter<Long?>

272

273

/** Int32 wrapper adapter (google.protobuf.Int32Value) */

274

@JvmField val INT32_VALUE: ProtoAdapter<Int?>

275

276

/** UInt32 wrapper adapter (google.protobuf.UInt32Value) */

277

@JvmField val UINT32_VALUE: ProtoAdapter<Int?>

278

279

/** Bool wrapper adapter (google.protobuf.BoolValue) */

280

@JvmField val BOOL_VALUE: ProtoAdapter<Boolean?>

281

282

/** String wrapper adapter (google.protobuf.StringValue) */

283

@JvmField val STRING_VALUE: ProtoAdapter<String?>

284

285

/** Bytes wrapper adapter (google.protobuf.BytesValue) */

286

@JvmField val BYTES_VALUE: ProtoAdapter<ByteString?>

287

}

288

```

289

290

### Map Adapter Factory

291

292

Factory method for creating type-safe map adapters for proto map fields.

293

294

```kotlin { .api }

295

companion object {

296

/**

297

* Creates adapter for map fields

298

* @param keyAdapter Adapter for map keys

299

* @param valueAdapter Adapter for map values

300

* @return Map adapter with proper encoding

301

*/

302

@JvmStatic

303

fun <K, V> newMapAdapter(

304

keyAdapter: ProtoAdapter<K>,

305

valueAdapter: ProtoAdapter<V>

306

): ProtoAdapter<Map<K, V>>

307

}

308

```

309

310

**Usage Examples:**

311

312

```kotlin

313

// Create map adapter

314

val stringToIntMap = ProtoAdapter.newMapAdapter(

315

ProtoAdapter.STRING,

316

ProtoAdapter.INT32

317

)

318

319

val map = mapOf(

320

"one" to 1,

321

"two" to 2,

322

"three" to 3

323

)

324

325

val encoded = stringToIntMap.encode(map)

326

val decoded = stringToIntMap.decode(encoded)

327

328

// Maps are encoded as repeated entries with key=1, value=2

329

val buffer = Buffer()

330

val writer = ProtoWriter(buffer)

331

stringToIntMap.encodeWithTag(writer, 1, map)

332

```

333

334

### Repeated and Packed Adapters

335

336

Adapters for repeated fields with support for packed encoding (more efficient for primitive types).

337

338

```kotlin { .api }

339

// Convert adapter to handle repeated values

340

val stringListAdapter = ProtoAdapter.STRING.asRepeated()

341

val stringList = listOf("a", "b", "c")

342

val encodedList = stringListAdapter.encodeWithTag(writer, 1, stringList)

343

344

// Convert adapter to handle packed repeated values (primitives only)

345

val intPackedAdapter = ProtoAdapter.INT32.asPacked()

346

val intList = listOf(1, 2, 3, 4, 5)

347

val encodedPacked = intPackedAdapter.encodeWithTag(writer, 2, intList)

348

349

// Packed encoding is more efficient for repeated primitives:

350

// Regular: tag+value, tag+value, tag+value, ...

351

// Packed: tag+length, value, value, value, ...

352

```

353

354

### Custom Adapter Implementation

355

356

Creating custom adapters for user-defined types:

357

358

```kotlin

359

// Example custom adapter for a simple data class

360

data class Point(val x: Int, val y: Int)

361

362

object PointAdapter : ProtoAdapter<Point>(

363

FieldEncoding.LENGTH_DELIMITED,

364

Point::class,

365

null,

366

Syntax.PROTO_2

367

) {

368

override fun encodedSize(value: Point): Int {

369

return ProtoAdapter.INT32.encodedSizeWithTag(1, value.x) +

370

ProtoAdapter.INT32.encodedSizeWithTag(2, value.y)

371

}

372

373

override fun encode(writer: ProtoWriter, value: Point) {

374

ProtoAdapter.INT32.encodeWithTag(writer, 1, value.x)

375

ProtoAdapter.INT32.encodeWithTag(writer, 2, value.y)

376

}

377

378

override fun decode(reader: ProtoReader): Point {

379

var x = 0

380

var y = 0

381

382

reader.forEachTag { tag ->

383

when (tag) {

384

1 -> x = ProtoAdapter.INT32.decode(reader)

385

2 -> y = ProtoAdapter.INT32.decode(reader)

386

else -> reader.readUnknownField(tag)

387

}

388

}

389

390

return Point(x, y)

391

}

392

393

override fun redact(value: Point): Point = Point(0, 0)

394

}

395

396

// Usage

397

val point = Point(10, 20)

398

val encoded = PointAdapter.encode(point)

399

val decoded = PointAdapter.decode(encoded)

400

```

401

402

### EnumConstantNotFoundException

403

404

Exception thrown when decoding encounters an unknown enum value.

405

406

```kotlin { .api }

407

class EnumConstantNotFoundException(

408

value: Int,

409

type: KClass<*>?

410

) : IllegalArgumentException {

411

@JvmField

412

val value: Int

413

}

414

```

415

416

## Adapter Features

417

418

### Type Safety

419

- Generic type parameters ensure compile-time type checking

420

- No casting required when using built-in adapters

421

- KClass metadata preserves runtime type information

422

423

### Proto3 Identity Handling

424

- Identity values (0, false, "", empty collections) can be omitted in proto3

425

- Wrapper adapters handle nullable types properly

426

- Proto2 vs Proto3 semantics handled automatically

427

428

### Performance Optimization

429

- Lazy evaluation where possible

430

- Packed encoding for repeated primitive types

431

- Efficient varint and ZigZag encoding for integers

432

- Stream-based processing to minimize memory usage

433

434

### Unknown Field Preservation

435

- All adapters preserve unknown fields during decode/encode cycles

436

- Forward compatibility maintained automatically

437

- Unknown fields stored as ByteString for efficient handling