or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdbuilt-ins.mdcore-serialization.mddescriptors.mdencoding.mdindex.mdmodules.md

encoding.mddocs/

0

# Encoding and Decoding

1

2

The encoding and decoding system provides the core interfaces that serialization formats use to read and write structured data. These interfaces abstract away format-specific details, allowing serializers to work with any format that implements the encoder/decoder contracts.

3

4

## Capabilities

5

6

### Core Encoding Interfaces

7

8

The fundamental interfaces for writing serialized data in a format-agnostic way.

9

10

```kotlin { .api }

11

/**

12

* Core serialization primitive that encapsulates format-specific knowledge for writing data.

13

* Provides methods for encoding primitive values and initiating structured encoding.

14

*/

15

interface Encoder {

16

/** The serializers module for resolving contextual and polymorphic serializers */

17

val serializersModule: SerializersModule

18

19

/** Begin encoding a structured value, returning a CompositeEncoder for the structure */

20

fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder

21

22

/** Encode a boolean value */

23

fun encodeBoolean(value: Boolean)

24

25

/** Encode a byte value */

26

fun encodeByte(value: Byte)

27

28

/** Encode a char value */

29

fun encodeChar(value: Char)

30

31

/** Encode a double value */

32

fun encodeDouble(value: Double)

33

34

/** Encode an enum value */

35

fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int)

36

37

/** Encode a float value */

38

fun encodeFloat(value: Float)

39

40

/** Encode an inline value (value class) */

41

fun encodeInline(descriptor: SerialDescriptor): Encoder

42

43

/** Encode an int value */

44

fun encodeInt(value: Int)

45

46

/** Encode a long value */

47

fun encodeLong(value: Long)

48

49

/** Encode a null value */

50

fun encodeNull()

51

52

/** Encode a short value */

53

fun encodeShort(value: Short)

54

55

/** Encode a string value */

56

fun encodeString(value: String)

57

}

58

59

/**

60

* Part of the encoding process that handles structured data like classes, lists, and maps.

61

* Bound to a specific structured part of the serialized form.

62

*/

63

interface CompositeEncoder {

64

/** The serializers module for resolving contextual and polymorphic serializers */

65

val serializersModule: SerializersModule

66

67

/** Finish encoding the structure */

68

fun endStructure(descriptor: SerialDescriptor)

69

70

/** Check if element at given index should be encoded */

71

fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean

72

73

/** Encode a boolean element at the specified index */

74

fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean)

75

76

/** Encode a byte element at the specified index */

77

fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte)

78

79

/** Encode a char element at the specified index */

80

fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char)

81

82

/** Encode a double element at the specified index */

83

fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double)

84

85

/** Encode a float element at the specified index */

86

fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float)

87

88

/** Encode an inline element at the specified index */

89

fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder

90

91

/** Encode an int element at the specified index */

92

fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int)

93

94

/** Encode a long element at the specified index */

95

fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long)

96

97

/** Encode a null element at the specified index */

98

fun encodeNullableSerializableElement(

99

descriptor: SerialDescriptor,

100

index: Int,

101

serializer: SerializationStrategy<T>,

102

value: T?

103

)

104

105

/** Encode a serializable element at the specified index */

106

fun encodeSerializableElement(

107

descriptor: SerialDescriptor,

108

index: Int,

109

serializer: SerializationStrategy<T>,

110

value: T

111

)

112

113

/** Encode a short element at the specified index */

114

fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short)

115

116

/** Encode a string element at the specified index */

117

fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String)

118

}

119

```

120

121

### Core Decoding Interfaces

122

123

The fundamental interfaces for reading serialized data in a format-agnostic way.

124

125

```kotlin { .api }

126

/**

127

* Core deserialization primitive for format-agnostic decoding of structured data.

128

* Provides methods for decoding primitive values and initiating structured decoding.

129

*/

130

interface Decoder {

131

/** The serializers module for resolving contextual and polymorphic serializers */

132

val serializersModule: SerializersModule

133

134

/** Begin decoding a structured value, returning a CompositeDecoder for the structure */

135

fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder

136

137

/** Decode a boolean value */

138

fun decodeBoolean(): Boolean

139

140

/** Decode a byte value */

141

fun decodeByte(): Byte

142

143

/** Decode a char value */

144

fun decodeChar(): Char

145

146

/** Decode a double value */

147

fun decodeDouble(): Double

148

149

/** Decode an enum value, returning the index */

150

fun decodeEnum(enumDescriptor: SerialDescriptor): Int

151

152

/** Decode a float value */

153

fun decodeFloat(): Float

154

155

/** Decode an inline value (value class) */

156

fun decodeInline(descriptor: SerialDescriptor): Decoder

157

158

/** Decode an int value */

159

fun decodeInt(): Int

160

161

/** Decode a long value */

162

fun decodeLong(): Long

163

164

/** Decode a null value, returning false if null */

165

@ExperimentalSerializationApi

166

fun decodeNotNullMark(): Boolean

167

168

/** Decode a null value */

169

@ExperimentalSerializationApi

170

fun decodeNull(): Nothing?

171

172

/** Decode a short value */

173

fun decodeShort(): Short

174

175

/** Decode a string value */

176

fun decodeString(): String

177

}

178

179

/**

180

* Part of the decoding process that handles structured data like classes, lists, and maps.

181

* Bound to a specific structured part of the serialized form.

182

*/

183

interface CompositeDecoder {

184

/** The serializers module for resolving contextual and polymorphic serializers */

185

val serializersModule: SerializersModule

186

187

/** Finish decoding the structure */

188

fun endStructure(descriptor: SerialDescriptor)

189

190

/** Decode the next element index, returning CompositeDecoder.DECODE_DONE when finished */

191

fun decodeElementIndex(descriptor: SerialDescriptor): Int

192

193

/** Decode a boolean element at the specified index */

194

fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean

195

196

/** Decode a byte element at the specified index */

197

fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte

198

199

/** Decode a char element at the specified index */

200

fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char

201

202

/** Decode a double element at the specified index */

203

fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double

204

205

/** Decode a float element at the specified index */

206

fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float

207

208

/** Decode an inline element at the specified index */

209

fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder

210

211

/** Decode an int element at the specified index */

212

fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int

213

214

/** Decode a long element at the specified index */

215

fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long

216

217

/** Decode a nullable serializable element at the specified index */

218

fun decodeNullableSerializableElement(

219

descriptor: SerialDescriptor,

220

index: Int,

221

deserializer: DeserializationStrategy<T?>,

222

previousValue: T? = null

223

): T?

224

225

/** Decode a serializable element at the specified index */

226

fun decodeSerializableElement(

227

descriptor: SerialDescriptor,

228

index: Int,

229

deserializer: DeserializationStrategy<T>,

230

previousValue: T? = null

231

): T

232

233

/** Decode a short element at the specified index */

234

fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short

235

236

/** Decode a string element at the specified index */

237

fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String

238

239

companion object {

240

/** Constant indicating that decoding is complete */

241

const val DECODE_DONE: Int = -1

242

243

/** Constant indicating unknown element index */

244

const val UNKNOWN_NAME: Int = -3

245

}

246

}

247

```

248

249

### Abstract Base Classes

250

251

Skeleton implementations that provide common functionality for format implementations.

252

253

```kotlin { .api }

254

/**

255

* Skeleton implementation of both Encoder and CompositeEncoder.

256

* Provides default implementations for common encoding patterns.

257

*/

258

abstract class AbstractEncoder : Encoder, CompositeEncoder {

259

/** Default implementation delegates to CompositeEncoder methods */

260

final override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder = this

261

262

/** Default implementation calls endStructure */

263

override fun endStructure(descriptor: SerialDescriptor) {}

264

265

/** Default implementation returns true for required elements, false for optional */

266

override fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean =

267

!descriptor.isElementOptional(index)

268

}

269

270

/**

271

* Skeleton implementation of both Decoder and CompositeDecoder.

272

* Provides default implementations for common decoding patterns.

273

*/

274

abstract class AbstractDecoder : Decoder, CompositeDecoder {

275

/** Default implementation delegates to CompositeDecoder methods */

276

final override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder = this

277

278

/** Default implementation calls endStructure */

279

override fun endStructure(descriptor: SerialDescriptor) {}

280

}

281

```

282

283

### Specialized Interfaces

284

285

Additional interfaces for specific encoding/decoding scenarios.

286

287

```kotlin { .api }

288

/**

289

* Decoder interface that supports consuming large strings by chunks.

290

* Useful for streaming formats that need to process large text data efficiently.

291

*/

292

interface ChunkedDecoder {

293

/**

294

* Decodes a string value by chunks, calling the consumer for each chunk.

295

* @param consumeChunk Function to consume each string chunk

296

*/

297

fun decodeStringChunked(consumeChunk: (chunk: String) -> Unit)

298

}

299

```

300

301

### Encoding Extension Functions

302

303

Convenient extension functions that simplify common encoding patterns.

304

305

```kotlin { .api }

306

/**

307

* Encodes structured values using CompositeEncoder in a convenient DSL style.

308

* @param descriptor The descriptor for the structure being encoded

309

* @param block Lambda that performs the encoding using CompositeEncoder

310

*/

311

inline fun Encoder.encodeStructure(

312

descriptor: SerialDescriptor,

313

crossinline block: CompositeEncoder.() -> Unit

314

)

315

316

/**

317

* Convenience method for encoding collections with consistent element handling.

318

* @param descriptor The descriptor for the collection

319

* @param collection The collection to encode

320

* @param block Lambda to encode each collection element

321

*/

322

inline fun <T> Encoder.encodeCollection(

323

descriptor: SerialDescriptor,

324

collection: Collection<T>,

325

crossinline block: CompositeEncoder.(index: Int, element: T) -> Unit

326

)

327

```

328

329

### Decoding Extension Functions

330

331

Convenient extension functions that simplify common decoding patterns.

332

333

```kotlin { .api }

334

/**

335

* Decodes structured values using CompositeDecoder in a convenient DSL style.

336

* @param descriptor The descriptor for the structure being decoded

337

* @param block Lambda that performs the decoding using CompositeDecoder

338

* @return The decoded value

339

*/

340

inline fun <T> Decoder.decodeStructure(

341

descriptor: SerialDescriptor,

342

crossinline block: CompositeDecoder.() -> T

343

): T

344

```

345

346

**Usage Examples:**

347

348

```kotlin

349

import kotlinx.serialization.*

350

import kotlinx.serialization.descriptors.*

351

import kotlinx.serialization.encoding.*

352

353

// Custom serializer using encoding interfaces

354

object PointSerializer : KSerializer<Point> {

355

override val descriptor = buildClassSerialDescriptor("Point") {

356

element("x", PrimitiveSerialDescriptor("kotlin.Int", PrimitiveKind.INT))

357

element("y", PrimitiveSerialDescriptor("kotlin.Int", PrimitiveKind.INT))

358

}

359

360

override fun serialize(encoder: Encoder, value: Point) {

361

encoder.encodeStructure(descriptor) {

362

encodeIntElement(descriptor, 0, value.x)

363

encodeIntElement(descriptor, 1, value.y)

364

}

365

}

366

367

override fun deserialize(decoder: Decoder): Point {

368

return decoder.decodeStructure(descriptor) {

369

var x = 0

370

var y = 0

371

372

while (true) {

373

when (val index = decodeElementIndex(descriptor)) {

374

0 -> x = decodeIntElement(descriptor, index)

375

1 -> y = decodeIntElement(descriptor, index)

376

CompositeDecoder.DECODE_DONE -> break

377

else -> error("Unexpected index: $index")

378

}

379

}

380

381

Point(x, y)

382

}

383

}

384

}

385

```

386

387

## Implementation Patterns

388

389

### Format Implementation

390

391

When implementing a new format, you typically extend the abstract base classes:

392

393

```kotlin

394

import kotlinx.serialization.encoding.*

395

import kotlinx.serialization.modules.*

396

397

class MyFormatEncoder : AbstractEncoder() {

398

override val serializersModule: SerializersModule = EmptySerializersModule

399

400

override fun encodeString(value: String) {

401

// Format-specific string encoding

402

}

403

404

override fun encodeInt(value: Int) {

405

// Format-specific int encoding

406

}

407

408

// Implement other encoding methods...

409

}

410

411

class MyFormatDecoder : AbstractDecoder() {

412

override val serializersModule: SerializersModule = EmptySerializersModule

413

414

override fun decodeString(): String {

415

// Format-specific string decoding

416

}

417

418

override fun decodeInt(): Int {

419

// Format-specific int decoding

420

}

421

422

// Implement other decoding methods...

423

}

424

```

425

426

### Sequential vs Random Access

427

428

Different formats may require different decoding approaches:

429

430

```kotlin

431

// Sequential decoding (streaming formats)

432

override fun deserialize(decoder: Decoder): MyClass {

433

return decoder.decodeStructure(descriptor) {

434

var field1: String? = null

435

var field2: Int? = null

436

437

while (true) {

438

when (val index = decodeElementIndex(descriptor)) {

439

0 -> field1 = decodeStringElement(descriptor, index)

440

1 -> field2 = decodeIntElement(descriptor, index)

441

CompositeDecoder.DECODE_DONE -> break

442

else -> error("Unexpected index: $index")

443

}

444

}

445

446

MyClass(field1!!, field2!!)

447

}

448

}

449

450

// Random access decoding (structured formats like JSON objects)

451

override fun deserialize(decoder: Decoder): MyClass {

452

return decoder.decodeStructure(descriptor) {

453

MyClass(

454

decodeStringElement(descriptor, 0),

455

decodeIntElement(descriptor, 1)

456

)

457

}

458

}

459

```

460

461

## Error Handling

462

463

Common encoding/decoding errors and their causes:

464

465

- **SerializationException**: General encoding/decoding failures

466

- **IllegalStateException**: Invalid encoder/decoder state transitions

467

- **IndexOutOfBoundsException**: Invalid element index access

468

- **ClassCastException**: Type mismatches during decoding