@zio.dev/zio-blocks 0.0.33 → 0.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/guides/compile-time-resource-safety-with-scope.md +16 -17
  2. package/guides/getting-started-with-mux.md +1507 -0
  3. package/guides/query-dsl-extending.md +161 -102
  4. package/guides/query-dsl-fluent-builder.md +217 -157
  5. package/guides/query-dsl-reified-optics.md +12 -10
  6. package/guides/query-dsl-sql.md +246 -165
  7. package/guides/telemetry-guide.md +1069 -0
  8. package/guides/zio-schema-migration.md +29 -22
  9. package/index.md +292 -50
  10. package/package.json +1 -1
  11. package/plans/config-follow-up-prs.md +188 -0
  12. package/plans/config-pr-assessment-roadmap.md +310 -0
  13. package/reference/MuxDataFlow.jsx +250 -0
  14. package/reference/async.md +651 -0
  15. package/reference/chunk.md +3533 -308
  16. package/reference/codegen/case-class.md +436 -0
  17. package/reference/codegen/emitter-config.md +383 -0
  18. package/reference/codegen/examples.md +664 -0
  19. package/reference/codegen/field.md +316 -0
  20. package/reference/codegen/index.md +317 -0
  21. package/reference/codegen/scala-emitter.md +392 -0
  22. package/reference/codegen/scala-file.md +276 -0
  23. package/reference/codegen/sealed-trait.md +408 -0
  24. package/reference/codegen/type-definition.md +340 -0
  25. package/reference/codegen/type-ref.md +201 -0
  26. package/reference/combinators.md +347 -117
  27. package/reference/config.md +158 -0
  28. package/reference/context.md +4 -4
  29. package/reference/datastar.md +346 -0
  30. package/reference/docs.md +1461 -345
  31. package/reference/endpoint/auth-type.md +146 -0
  32. package/reference/endpoint/endpoint.md +297 -0
  33. package/reference/endpoint/http-codec.md +249 -0
  34. package/reference/endpoint/index.md +825 -0
  35. package/reference/endpoint/path-codec.md +237 -0
  36. package/reference/endpoint/route-pattern.md +196 -0
  37. package/reference/endpoint/route-tree.md +111 -0
  38. package/reference/endpoint/segment-codec.md +212 -0
  39. package/reference/html.md +1120 -0
  40. package/reference/htmx/attribute-values.md +359 -0
  41. package/reference/htmx/hx-encoding.md +111 -0
  42. package/reference/htmx/hx-params.md +204 -0
  43. package/reference/htmx/hx-swap.md +276 -0
  44. package/reference/htmx/hx-sync.md +251 -0
  45. package/reference/htmx/hx-target.md +314 -0
  46. package/reference/htmx/hx-trigger.md +457 -0
  47. package/reference/htmx/hx-url-update.md +239 -0
  48. package/reference/htmx/index.md +855 -0
  49. package/reference/http-model/index.md +47 -0
  50. package/reference/http-model/model.md +1481 -0
  51. package/reference/http-model/schema.md +747 -0
  52. package/reference/maybe.md +826 -0
  53. package/reference/media-type.md +2 -2
  54. package/reference/mux.mdx +823 -0
  55. package/reference/openapi.md +1351 -0
  56. package/reference/resource-management/defer-handle.md +1 -1
  57. package/reference/resource-management/resource.md +31 -2
  58. package/reference/resource-management/scope.md +28 -12
  59. package/reference/resource-management/wire.md +3 -7
  60. package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
  61. package/reference/ringbuffer/MpscDiagram.jsx +618 -0
  62. package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
  63. package/reference/ringbuffer/SpscDiagram.jsx +677 -0
  64. package/reference/ringbuffer/advanced.mdx +109 -0
  65. package/reference/ringbuffer/index.mdx +145 -0
  66. package/reference/ringbuffer/mpmc.mdx +151 -0
  67. package/reference/ringbuffer/mpsc.mdx +132 -0
  68. package/reference/ringbuffer/spmc.mdx +108 -0
  69. package/reference/ringbuffer/spsc.mdx +344 -0
  70. package/reference/{allows.md → schema/allows.md} +4 -4
  71. package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
  72. package/reference/{binding.md → schema/binding.md} +2 -3
  73. package/reference/schema/built-in-codecs/avro.md +451 -0
  74. package/reference/schema/built-in-codecs/bson.md +480 -0
  75. package/reference/schema/built-in-codecs/csv.md +564 -0
  76. package/reference/schema/built-in-codecs/index.md +77 -0
  77. package/reference/schema/built-in-codecs/json/index.md +295 -0
  78. package/reference/schema/built-in-codecs/json/json-config.md +217 -0
  79. package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
  80. package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
  81. package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
  82. package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
  83. package/reference/schema/built-in-codecs/messagepack.md +508 -0
  84. package/reference/schema/built-in-codecs/thrift.md +433 -0
  85. package/reference/schema/built-in-codecs/toon.md +1078 -0
  86. package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
  87. package/reference/schema/built-in-codecs/yaml.md +552 -0
  88. package/reference/{codec.md → schema/codec.md} +10 -10
  89. package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +151 -5
  90. package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
  91. package/reference/schema/format.md +92 -0
  92. package/reference/schema/index.md +50 -0
  93. package/reference/schema/migration.md +297 -0
  94. package/reference/{modifier.md → schema/modifier.md} +58 -7
  95. package/reference/{optics.md → schema/optics.md} +2 -2
  96. package/reference/{patch.md → schema/patch.md} +1 -1
  97. package/{path-interpolator.md → reference/schema/path-interpolator.md} +165 -72
  98. package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
  99. package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
  100. package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
  101. package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
  102. package/reference/{schema.md → schema/schema.md} +12 -0
  103. package/reference/{structural-types.md → schema/structural-types.md} +1 -1
  104. package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
  105. package/reference/smithy.md +533 -0
  106. package/reference/sql/db-codec-deriver.md +71 -0
  107. package/reference/sql/db-codec.md +687 -0
  108. package/reference/sql/db-con.md +271 -0
  109. package/reference/sql/db-connection.md +153 -0
  110. package/reference/sql/db-param-writer.md +77 -0
  111. package/reference/sql/db-param.md +66 -0
  112. package/reference/sql/db-result-reader.md +146 -0
  113. package/reference/sql/db-tx.md +82 -0
  114. package/reference/sql/db-value.md +41 -0
  115. package/reference/sql/ddl.md +85 -0
  116. package/reference/sql/frag.md +254 -0
  117. package/reference/sql/index.md +341 -0
  118. package/reference/sql/repo.md +600 -0
  119. package/reference/sql/sql-dialect.md +73 -0
  120. package/reference/sql/sql-logger.md +62 -0
  121. package/reference/sql/sql-name-mapper.md +70 -0
  122. package/reference/sql/table-metadata.md +134 -0
  123. package/reference/sql/table.md +448 -0
  124. package/reference/sql/transactor-zio.md +399 -0
  125. package/reference/sql/transactor.md +353 -0
  126. package/reference/sql-zio.md +112 -0
  127. package/reference/streams/concurrent-operators.md +106 -0
  128. package/reference/streams/index.md +653 -0
  129. package/reference/streams/pipeline.md +718 -0
  130. package/reference/streams/reader.md +1284 -0
  131. package/reference/streams/scala-2-compatibility.md +55 -0
  132. package/reference/streams/sink.md +1426 -0
  133. package/reference/streams/stream.md +2526 -0
  134. package/reference/streams/writer.md +1045 -0
  135. package/reference/streams/zero-boxing.md +275 -0
  136. package/reference/telemetry.md +693 -0
  137. package/reference/typeid.md +5 -19
  138. package/sidebars.js +238 -43
  139. package/reference/formats.md +0 -694
  140. package/reference/http-model.md +0 -1716
  141. package/reference/streams.md +0 -989
  142. package/ringbuffer.md +0 -249
  143. /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
  144. /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
  145. /package/reference/{lazy.md → schema/lazy.md} +0 -0
  146. /package/reference/{reflect.md → schema/reflect.md} +0 -0
  147. /package/reference/{registers.md → schema/registers.md} +0 -0
  148. /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
  149. /package/reference/{syntax.md → schema/syntax.md} +0 -0
  150. /package/reference/{validation.md → schema/validation.md} +0 -0
@@ -0,0 +1,1078 @@
1
+ ---
2
+ id: toon
3
+ title: "TOON Codec Module"
4
+ ---
5
+
6
+ `zio-blocks-schema-toon` is a **schema-driven TOON codec module** for serializing and deserializing Scala types to and from TOON format. It provides comprehensive encoding and decoding with support for 27 primitive types, records, variants, sequences, maps, and recursive types. Core types: `ToonCodec`, `ToonCodecDeriver`, `ToonFormat`, `ToonReader`, `ToonWriter`.
7
+
8
+ The module integrates with a pure-Scala TOON parser and writer to provide line-oriented, indentation-based serialization that is 30-60% more compact than JSON. TOON (Token-Oriented Object Notation) appears widely across LLM prompts, configuration files, and data exchange where compactness and human readability matter equally.
9
+
10
+ ## Motivation
11
+
12
+ TOON is a compact, line-oriented text format that encodes the JSON data model with explicit structure and minimal quoting. It appears widely in modern LLM applications, configuration management, and streaming data scenarios where bandwidth and readability are both critical. Manually writing TOON encoders and decoders is error-prone and repetitive, especially for complex types with records, nested structures, and recursive definitions. `zio-blocks-schema-toon` eliminates this friction by deriving codec instances directly from your Scala types using ZIO Schema. You describe your data shape once, and the module handles:
13
+ - Full TOON type support (records, sequences, primitives, null)
14
+ - Three array formats: inline (`tags[3]: a,b,c`), tabular (`users[2]{id,name}:`), and list (`- item`)
15
+ - Automatic schema generation from Scala types
16
+ - Customizable field/case name mapping (identity, snake_case, kebab-case, etc.)
17
+ - Configurable discriminator strategies for algebraic data types
18
+ - Precise error reporting with location traces showing the path to errors
19
+ - Recursive type support with automatic cycle detection
20
+ - Multiple encoding paths: byte arrays, streams, ByteBuffers, and strings
21
+ - Multiple decoding paths: byte arrays, streams, ByteBuffers, and strings
22
+ - Cross-platform compatibility (JVM and Scala.js)
23
+
24
+ Rather than hand-writing TOON parsing logic or relying on external libraries with limited Scala support, you work with strongly-typed schemas that the compiler validates.
25
+
26
+ ## Installation
27
+
28
+ Add the module to your `build.sbt`:
29
+
30
+ ```sbt
31
+ libraryDependencies += "dev.zio" %% "zio-blocks-schema-toon" % "0.0.51"
32
+ ```
33
+
34
+ For Scala.js, use `%%%` instead of `%%`:
35
+
36
+ ```sbt
37
+ libraryDependencies += "dev.zio" %%% "zio-blocks-schema-toon" % "0.0.51"
38
+ ```
39
+
40
+ Supported Scala versions: 2.13.x and 3.x
41
+
42
+ ## Introduction
43
+
44
+ The module provides a complete pipeline for TOON codec derivation and usage:
45
+
46
+ 1. **Define your type** — Any Scala type with a `Schema` instance
47
+ 2. **Derive a codec** — Use `Schema[A].derive(ToonFormat)` to obtain a `ToonCodec[A]`
48
+ 3. **Encode or decode** — Call `codec.encode(value)` or `codec.decode(toonBytes)`
49
+ 4. **Handle errors** — Catch `SchemaError` with location traces showing where the error occurred
50
+ 5. **Customize output** — Use `WriterConfig` for indentation and formatting, `ReaderConfig` for parsing behavior
51
+
52
+ The derivation process is automatic for all supported types (all 27 primitives, records, variants, sequences, maps). The module automatically generates TOON-compatible formats and handles encoding/decoding without manual configuration.
53
+
54
+ ## How They Work Together
55
+
56
+ The TOON codec pipeline flows through these layers:
57
+
58
+ ```
59
+ 1. User defines Schema[A] for their type
60
+ ↓
61
+ 2. Schema[A].derive(ToonFormat) creates ToonCodec[A]
62
+ ↓
63
+ 3. ToonCodecDeriver derives Encoder and Decoder implementations
64
+ - For primitives: type-specific TOON scalar encoders/decoders
65
+ - For records: field-by-field composition with indented nesting
66
+ - For variants: union encoding with optional discriminators
67
+ - For sequences: one of three formats (inline, tabular, list)
68
+ - For maps: record-like encoding with key-value pairs
69
+ ↓
70
+ 4. ToonCodec provides multiple encoding paths
71
+ - encode(value) → Array[Byte]
72
+ - encode(value, output: OutputStream) → Unit
73
+ - encode(value, buffer: ByteBuffer) → Unit
74
+ - encodeToString(value) → String
75
+ ↓
76
+ 5. ToonCodec provides multiple decoding paths
77
+ - decode(bytes: Array[Byte]) → Either[SchemaError, A]
78
+ - decode(input: InputStream) → Either[SchemaError, A]
79
+ - decode(buffer: ByteBuffer) → Either[SchemaError, A]
80
+ - decode(toon: String) → Either[SchemaError, A]
81
+ ↓
82
+ 6. WriterConfig controls output formatting
83
+ - Indentation (default: 2 spaces per level)
84
+ - Key folding strategy (flatten nested keys or expand)
85
+ - Discriminator field for variants
86
+ - Array format selection
87
+ ↓
88
+ 7. ReaderConfig controls parsing behavior
89
+ - Path expansion (parse dot-separated keys as nested)
90
+ - Delimiter selection for inline arrays
91
+ - Strict parsing mode (enforce TOON compliance)
92
+ - Discriminator field recognition
93
+ ↓
94
+ 8. Errors include location traces
95
+ Shows path (.field[index].nested) to error location
96
+ ```
97
+
98
+ A user type flows through the derivation and encoding pipeline as follows:
99
+
100
+ ```
101
+ User type (e.g., case class Person)
102
+ ↓
103
+ Schema.derived (automatic via macro)
104
+ ↓
105
+ Schema[Person].derive(ToonFormat) → ToonCodec[Person]
106
+ ↓
107
+ Use codec.encode(person) to serialize → Array[Byte]
108
+ Use codec.decode(toonBytes) to deserialize → Either[SchemaError, Person]
109
+ ↓
110
+ Handle SchemaError with location trace on failure
111
+ ```
112
+
113
+ ### Type Relationships
114
+
115
+ - **`ToonCodec[A]`** — Main public API; contains encoder and decoder for bidirectional serialization
116
+ - **`ToonCodecDeriver`** — Configuration and derivation system; generates codecs from Schema
117
+ - **`ToonFormat`** — Integration with ZIO Schema format system; enables `Schema[A].derive(ToonFormat)`
118
+ - **`WriterConfig`** — Output formatting configuration (indentation, delimiters, discriminators)
119
+ - **`ReaderConfig`** — Input parsing configuration (path expansion, strict mode, delimiters)
120
+ - **`ToonReader`, `ToonWriter`** — Low-level TOON parsing and serialization
121
+ - **`NameMapper`** — Field and case name transformation strategies
122
+ - **`ArrayFormat`** — Controls sequence encoding (Inline, Tabular, List, Auto)
123
+ - **`Delimiter`** — Specifies separator for inline arrays (Comma, Tab, Pipe)
124
+
125
+ ## Common Patterns
126
+
127
+ This section shows practical patterns for working with TOON codecs in real-world scenarios.
128
+
129
+ ### Pattern 1: Derive and Encode a Configuration Record
130
+
131
+ For a case class with primitive fields, derive a codec and encode to TOON string.
132
+
133
+ To derive a TOON codec for a record type and encode a value:
134
+
135
+ ```scala
136
+ import zio.blocks.schema._
137
+ import zio.blocks.schema.toon._
138
+
139
+ case class AppConfig(name: String, port: Int, debug: Boolean)
140
+
141
+ object AppConfig {
142
+ implicit val schema: Schema[AppConfig] = Schema.derived[AppConfig]
143
+ }
144
+
145
+ val codec = AppConfig.schema.derive(ToonFormat)
146
+ val config = AppConfig("MyApp", 8080, true)
147
+ val toonBytes = codec.encode(config)
148
+ // Output:
149
+ // name: MyApp
150
+ // port: 8080
151
+ // debug: true
152
+ ```
153
+
154
+ ### Pattern 2: Decode TOON with Error Handling
155
+
156
+ When decoding TOON data, errors include location traces showing where the problem occurred.
157
+
158
+ To decode TOON and handle errors with location information:
159
+
160
+ ```scala
161
+ import zio.blocks.schema._
162
+ import zio.blocks.schema.toon._
163
+
164
+ case class DatabaseConfig(host: String, port: Int, username: String)
165
+
166
+ object DatabaseConfig {
167
+ implicit val schema: Schema[DatabaseConfig] = Schema.derived
168
+ }
169
+
170
+ val codec = DatabaseConfig.schema.derive(ToonFormat)
171
+ val toon = """
172
+ host: localhost
173
+ port: invalid
174
+ username: admin
175
+ """
176
+
177
+ val result = codec.decode(toon)
178
+
179
+ result match {
180
+ case Right(config) => println(s"Loaded: $config")
181
+ case Left(error) =>
182
+ println(s"Error: ${error.getMessage}")
183
+ // Error: Expected int, got: invalid at: .port
184
+ }
185
+ ```
186
+
187
+ ### Pattern 3: Work with Arrays in Different Formats
188
+
189
+ TOON supports three formats for encoding sequences, selectable via `ArrayFormat`.
190
+
191
+ To encode arrays using inline format (compact representation):
192
+
193
+ ```scala
194
+ import zio.blocks.schema._
195
+ import zio.blocks.schema.toon._
196
+
197
+ case class Tags(items: List[String])
198
+
199
+ object Tags {
200
+ implicit val schema: Schema[Tags] = Schema.derived
201
+ }
202
+
203
+ // Default format: auto (inline for primitives)
204
+ val codec = Tags.schema.derive(ToonFormat)
205
+ val tags = Tags(List("scala", "zio", "functional"))
206
+
207
+ val toonBytes = codec.encodeToString(tags)
208
+ // Output:
209
+ // items[3]: scala,zio,functional
210
+ ```
211
+
212
+ To encode objects using tabular format for compact representation:
213
+
214
+ ```scala
215
+ import zio.blocks.schema._
216
+ import zio.blocks.schema.toon._
217
+
218
+ case class User(id: Int, name: String)
219
+ case class Team(members: List[User])
220
+
221
+ object User {
222
+ implicit val schema: Schema[User] = Schema.derived
223
+ }
224
+
225
+ object Team {
226
+ implicit val schema: Schema[Team] = Schema.derived
227
+ }
228
+
229
+ // Tabular format for uniform object arrays
230
+ val tabularDeriver = ToonCodecDeriver.withArrayFormat(ArrayFormat.Tabular)
231
+ val codec = Team.schema.derive(tabularDeriver)
232
+ val team = Team(List(User(1, "Alice"), User(2, "Bob")))
233
+
234
+ val toonBytes = codec.encodeToString(team)
235
+ // Output:
236
+ // members[2]{id,name}:
237
+ // 1,Alice
238
+ // 2,Bob
239
+ ```
240
+
241
+ ### Pattern 4: Customize Field Names and Discriminators
242
+
243
+ Configure the deriver to map field names and control variant encoding.
244
+
245
+ To derive a codec with custom field name transformation:
246
+
247
+ ```scala
248
+ import zio.blocks.schema._
249
+ import zio.blocks.schema.toon._
250
+
251
+ case class Person(firstName: String, lastName: String, emailAddress: String)
252
+
253
+ object Person {
254
+ implicit val schema: Schema[Person] = Schema.derived
255
+ }
256
+
257
+ // Use snake_case for field names
258
+ val customDeriver = ToonCodecDeriver.withFieldNameMapper(NameMapper.SnakeCase)
259
+ val codec = Person.schema.derive(customDeriver)
260
+
261
+ val person = Person("Alice", "Smith", "alice@example.com")
262
+ val toonBytes = codec.encodeToString(person)
263
+ // Output:
264
+ // first_name: Alice
265
+ // last_name: Smith
266
+ // email_address: alice@example.com
267
+ ```
268
+
269
+ ### Pattern 5: Handle Recursive Types
270
+
271
+ Recursive types (types that reference themselves) are fully supported with automatic cycle detection.
272
+
273
+ To define and encode a recursive data structure:
274
+
275
+ ```scala
276
+ import zio.blocks.schema._
277
+ import zio.blocks.schema.toon._
278
+
279
+ sealed trait TreeNode
280
+ case class Leaf(value: String) extends TreeNode
281
+ case class Branch(label: String, children: List[TreeNode]) extends TreeNode
282
+
283
+ object TreeNode {
284
+ implicit val schema: Schema[TreeNode] = Schema.derived
285
+ }
286
+
287
+ val codec = TreeNode.schema.derive(ToonFormat)
288
+ val tree: TreeNode = Branch("root", List(Leaf("a"), Branch("b", List(Leaf("c")))))
289
+ val toonBytes = codec.encodeToString(tree)
290
+ // Output:
291
+ // Branch:
292
+ // label: root
293
+ // children[2]:
294
+ // - Leaf:
295
+ // value: a
296
+ // - Branch:
297
+ // label: b
298
+ // children[1]:
299
+ // - Leaf:
300
+ // value: c
301
+ ```
302
+
303
+ ---
304
+
305
+ ## ToonCodec[A]
306
+
307
+ Main codec type for encoding and decoding values to and from TOON format. Contains encoder and decoder for bidirectional serialization.
308
+
309
+ ### Overview
310
+
311
+ `ToonCodec[A]` holds both an encoder and decoder, providing a complete solution for serializing and deserializing values in TOON format. The codec is derived automatically from a `Schema[A]` using `ToonFormat`.
312
+
313
+ ### Encoding Values to Byte Array
314
+
315
+ Use the codec to convert values to byte arrays:
316
+
317
+ ```scala
318
+ import zio.blocks.schema._
319
+ import zio.blocks.schema.toon._
320
+
321
+ case class Person(name: String, email: String)
322
+
323
+ object Person {
324
+ implicit val schema: Schema[Person] = Schema.derived
325
+ }
326
+
327
+ val codec = Person.schema.derive(ToonFormat)
328
+ // codec: ToonCodec[Person] = zio.blocks.schema.toon.ToonCodecDeriver$$anon$5@3163694a
329
+ val person = Person("Alice", "alice@example.com")
330
+ // person: Person = Person(name = "Alice", email = "alice@example.com")
331
+ val bytes = codec.encode(person)
332
+ // bytes: Array[Byte] = Array(
333
+ // 110,
334
+ // 97,
335
+ // 109,
336
+ // 101,
337
+ // 58,
338
+ // 32,
339
+ // 65,
340
+ // 108,
341
+ // 105,
342
+ // 99,
343
+ // 101,
344
+ // 10,
345
+ // 101,
346
+ // 109,
347
+ // 97,
348
+ // 105,
349
+ // 108,
350
+ // 58,
351
+ // 32,
352
+ // 97,
353
+ // 108,
354
+ // 105,
355
+ // 99,
356
+ // 101,
357
+ // 64,
358
+ // 101,
359
+ // 120,
360
+ // 97,
361
+ // 109,
362
+ // 112,
363
+ // 108,
364
+ // 101,
365
+ // 46,
366
+ // 99,
367
+ // 111,
368
+ // 109
369
+ // )
370
+ ```
371
+
372
+ ### Encoding Values to String
373
+
374
+ Convert values to human-readable TOON strings:
375
+
376
+ ```scala
377
+ import zio.blocks.schema._
378
+ import zio.blocks.schema.toon._
379
+
380
+ case class Config(host: String, port: Int)
381
+
382
+ object Config {
383
+ implicit val schema: Schema[Config] = Schema.derived
384
+ }
385
+
386
+ val codec = Config.schema.derive(ToonFormat)
387
+ val config = Config("localhost", 8080)
388
+ val toonString = codec.encodeToString(config)
389
+ ```
390
+
391
+ ### Encoding Values to Stream
392
+
393
+ Write encoded values directly to an output stream:
394
+
395
+ ```scala
396
+ import zio.blocks.schema._
397
+ import zio.blocks.schema.toon._
398
+ import java.io.ByteArrayOutputStream
399
+
400
+ case class Data(timestamp: Long, value: String)
401
+
402
+ object Data {
403
+ implicit val schema: Schema[Data] = Schema.derived
404
+ }
405
+
406
+ val codec = Data.schema.derive(ToonFormat)
407
+ val data = Data(System.currentTimeMillis(), "sample")
408
+ val output = new ByteArrayOutputStream()
409
+ codec.encode(data, output)
410
+ val bytes = output.toByteArray
411
+ ```
412
+
413
+ ### Decoding Values from Byte Array
414
+
415
+ Use the codec to convert byte arrays back to values:
416
+
417
+ ```scala
418
+ import zio.blocks.schema._
419
+ import zio.blocks.schema.toon._
420
+
421
+ case class Settings(debug: Boolean, timeout: Int)
422
+
423
+ object Settings {
424
+ implicit val schema: Schema[Settings] = Schema.derived
425
+ }
426
+
427
+ val codec = Settings.schema.derive(ToonFormat)
428
+ // Create bytes from a previous encoding
429
+ val settings = Settings(debug = true, timeout = 30)
430
+ val bytes = codec.encode(settings)
431
+
432
+ val result: Either[zio.blocks.schema.SchemaError, Settings] = codec.decode(bytes)
433
+ ```
434
+
435
+ ### Decoding Values from String
436
+
437
+ Parse and decode values from TOON strings:
438
+
439
+ ```scala
440
+ import zio.blocks.schema._
441
+ import zio.blocks.schema.toon._
442
+
443
+ case class ServerConfig(name: String, port: Int)
444
+
445
+ object ServerConfig {
446
+ implicit val schema: Schema[ServerConfig] = Schema.derived
447
+ }
448
+
449
+ val codec = ServerConfig.schema.derive(ToonFormat)
450
+ val toon = """
451
+ name: api-server
452
+ port: 8080
453
+ """
454
+
455
+ val result = codec.decode(toon)
456
+ ```
457
+
458
+ ### Decoding Values from Stream
459
+
460
+ Read and decode values from bytes:
461
+
462
+ ```scala
463
+ import zio.blocks.schema._
464
+ import zio.blocks.schema.toon._
465
+
466
+ case class Message(id: Long, text: String)
467
+
468
+ object Message {
469
+ implicit val schema: Schema[Message] = Schema.derived
470
+ }
471
+
472
+ val codec = Message.schema.derive(ToonFormat)
473
+ val message = Message(42, "Hello TOON")
474
+ val encoded = codec.encode(message)
475
+ val result = codec.decode(encoded)
476
+ ```
477
+
478
+ ---
479
+
480
+ ## ToonCodecDeriver
481
+
482
+ Configuration and derivation system for creating `ToonCodec[A]` instances from `Schema[A]`.
483
+
484
+ ### Overview
485
+
486
+ `ToonCodecDeriver` implements the schema-driven derivation of TOON codecs. It automatically handles 27 primitive types and complex types (records, variants, sequences, maps), generating appropriate TOON encoders and decoders with comprehensive customization options.
487
+
488
+ ### How Derivation Works
489
+
490
+ To create a codec from a schema:
491
+
492
+ ```scala
493
+ import zio.blocks.schema._
494
+ import zio.blocks.schema.toon._
495
+
496
+ case class User(id: Int, name: String, active: Boolean)
497
+
498
+ object User {
499
+ implicit val schema: Schema[User] = Schema.derived
500
+ }
501
+
502
+ val codec = User.schema.derive(ToonFormat)
503
+ ```
504
+
505
+ ### Primitive Type Support
506
+
507
+ All 27 ZIO Schema primitives are supported:
508
+ - Numeric: `Byte`, `Short`, `Int`, `Long`, `Float`, `Double`, `BigInt`, `BigDecimal`
509
+ - Logical: `Boolean`, `Char`, `String`
510
+ - Temporal: `Instant`, `LocalDate`, `LocalDateTime`, `LocalTime`, `Duration`, `Period`, `Year`, `YearMonth`, `MonthDay`, `Month`, `DayOfWeek`, `ZonedDateTime`, `OffsetDateTime`, `OffsetTime`, `ZoneId`, `ZoneOffset`
511
+ - Special: `UUID`, `Currency`, `Unit`
512
+
513
+ ### Record Type Support
514
+
515
+ Case classes (records) are fully supported. Each field becomes an indented key-value pair in the TOON output:
516
+
517
+ ```scala
518
+ import zio.blocks.schema._
519
+ import zio.blocks.schema.toon._
520
+
521
+ case class Address(street: String, city: String, zipCode: String)
522
+
523
+ object Address {
524
+ implicit val schema: Schema[Address] = Schema.derived
525
+ }
526
+
527
+ val codec = Address.schema.derive(ToonFormat)
528
+ ```
529
+
530
+ ### Variant Type Support
531
+
532
+ Sealed traits and sum types are encoded as discriminated variants, with customizable discriminator strategies:
533
+
534
+ ```scala
535
+ import zio.blocks.schema._
536
+ import zio.blocks.schema.toon._
537
+
538
+ sealed trait Status
539
+ case class Running(pid: Int) extends Status
540
+ case class Stopped(exitCode: Int) extends Status
541
+
542
+ object Status {
543
+ implicit val schema: Schema[Status] = Schema.derived
544
+ }
545
+
546
+ val codec = Status.schema.derive(ToonFormat)
547
+ ```
548
+
549
+ ### Configuration Methods
550
+
551
+ To customize derivation behavior, chain configuration methods on `ToonCodecDeriver`:
552
+
553
+ To apply field name transformation:
554
+
555
+ ```scala
556
+ import zio.blocks.schema._
557
+ import zio.blocks.schema.toon._
558
+
559
+ val snakeCaseDeriver = ToonCodecDeriver.withFieldNameMapper(NameMapper.SnakeCase)
560
+ ```
561
+
562
+ To select array format:
563
+
564
+ ```scala
565
+ import zio.blocks.schema._
566
+ import zio.blocks.schema.toon._
567
+
568
+ val tabularDeriver = ToonCodecDeriver.withArrayFormat(ArrayFormat.Tabular)
569
+ ```
570
+
571
+ To customize variant discriminators:
572
+
573
+ ```scala
574
+ import zio.blocks.schema._
575
+ import zio.blocks.schema.toon._
576
+
577
+ val fieldDeriver = ToonCodecDeriver.withDiscriminatorKind(DiscriminatorKind.Field("type"))
578
+ ```
579
+
580
+ ---
581
+
582
+ ## ToonFormat
583
+
584
+ Integration point with ZIO Schema's format system. Provides `BinaryFormat[ToonCodec]` to enable `Schema[A].derive(ToonFormat)` for any supported type.
585
+
586
+ ### Using ToonFormat
587
+
588
+ To derive a TOON codec using the standard format:
589
+
590
+ ```scala
591
+ import zio.blocks.schema._
592
+ import zio.blocks.schema.toon._
593
+
594
+ case class Sensor(id: Long, temperature: Double, humidity: Float)
595
+
596
+ object Sensor {
597
+ implicit val schema: Schema[Sensor] = Schema.derived
598
+ }
599
+
600
+ val codec = Sensor.schema.derive(ToonFormat)
601
+ ```
602
+
603
+ `ToonFormat` is a singleton object extending `BinaryFormat[ToonCodec]` with the MIME type `"text/toon"` and the `ToonCodecDeriver` as its derivation strategy.
604
+
605
+ ---
606
+
607
+ ## WriterConfig
608
+
609
+ Configuration for TOON output formatting. Controls indentation, key folding, and discriminator field naming.
610
+
611
+ ### Overview
612
+
613
+ `WriterConfig` provides predefined configurations and factory methods for customizing TOON serialization output. It controls how records are nested, whether keys are flattened, and how variant discriminators are named.
614
+
615
+ ### Indentation Configuration
616
+
617
+ Control spacing for nested indentation:
618
+
619
+ ```scala
620
+ import zio.blocks.schema.toon._
621
+
622
+ val config = WriterConfig.withIndent(4)
623
+ // Uses 4 spaces per indentation level (default: 2)
624
+ ```
625
+
626
+ ### Key Folding Strategy
627
+
628
+ Flatten nested keys for shallow records or keep them separate:
629
+
630
+ ```scala
631
+ import zio.blocks.schema.toon._
632
+
633
+ val config = WriterConfig.withKeyFolding(KeyFolding.Safe)
634
+ // Converts nested keys to dot-separated paths for shallow nesting
635
+ ```
636
+
637
+ ### Discriminator Field Configuration
638
+
639
+ Configure how variant discriminators appear in output:
640
+
641
+ ```scala
642
+ import zio.blocks.schema.toon._
643
+
644
+ val config = WriterConfig.withDiscriminatorField(Some("_type"))
645
+ // Variants use "_type" field instead of default key discriminator
646
+ ```
647
+
648
+ ---
649
+
650
+ ## ReaderConfig
651
+
652
+ Configuration for TOON input parsing. Controls path expansion, delimiter selection, and strict parsing mode.
653
+
654
+ ### Overview
655
+
656
+ `ReaderConfig` provides factory methods for customizing TOON deserialization behavior. It controls whether dot-separated keys expand to nested records, which delimiters separate inline array elements, and whether parsing is strict.
657
+
658
+ ### Path Expansion Configuration
659
+
660
+ Parse dot-separated keys as nested records:
661
+
662
+ ```scala
663
+ import zio.blocks.schema.toon._
664
+
665
+ val config = ReaderConfig.withExpandPaths(PathExpansion.Safe)
666
+ // Interprets "user.name" as nested {user: {name: value}}
667
+ ```
668
+
669
+ ### Delimiter Configuration
670
+
671
+ Specify separator for inline arrays:
672
+
673
+ ```scala
674
+ import zio.blocks.schema.toon._
675
+
676
+ val config = ReaderConfig.withDelimiter(Delimiter.Tab)
677
+ // Expects tab characters instead of commas in inline arrays
678
+ ```
679
+
680
+ ### Strict Parsing Mode
681
+
682
+ Enable or disable strict TOON parsing:
683
+
684
+ ```scala
685
+ import zio.blocks.schema.toon._
686
+
687
+ val config = ReaderConfig.withStrict(false)
688
+ // Allows lenient parsing (default: true for strict compliance)
689
+ ```
690
+
691
+ ---
692
+
693
+ ## ArrayFormat
694
+
695
+ Controls how sequences are encoded in TOON output.
696
+
697
+ ### Overview
698
+
699
+ `ArrayFormat` selects from three distinct strategies for representing sequences in TOON format: compact inline representation, tabular grid format, or list-style items.
700
+
701
+ ### Inline Format
702
+
703
+ Encode arrays as comma-separated values on a single line:
704
+
705
+ ```scala
706
+ import zio.blocks.schema.toon._
707
+
708
+ val deriver = ToonCodecDeriver.withArrayFormat(ArrayFormat.Inline)
709
+ // tags[3]: scala,zio,functional
710
+ ```
711
+
712
+ ### Tabular Format
713
+
714
+ Encode uniform object arrays as compact tables with headers:
715
+
716
+ ```scala
717
+ import zio.blocks.schema.toon._
718
+
719
+ val deriver = ToonCodecDeriver.withArrayFormat(ArrayFormat.Tabular)
720
+ // users[2]{id,name}:
721
+ // 1,Alice
722
+ // 2,Bob
723
+ ```
724
+
725
+ ### List Format
726
+
727
+ Encode arrays using list-style items with dashes:
728
+
729
+ ```scala
730
+ import zio.blocks.schema.toon._
731
+
732
+ val deriver = ToonCodecDeriver.withArrayFormat(ArrayFormat.List)
733
+ // items:
734
+ // - item1
735
+ // - item2
736
+ ```
737
+
738
+ ### Auto Format
739
+
740
+ Let the encoder select the best format based on content:
741
+
742
+ ```scala
743
+ import zio.blocks.schema.toon._
744
+
745
+ val deriver = ToonCodecDeriver.withArrayFormat(ArrayFormat.Auto)
746
+ // Inline for primitives, tabular for uniform objects, list for mixed
747
+ ```
748
+
749
+ ---
750
+
751
+ ## Delimiter
752
+
753
+ Specifies the separator character for inline array elements.
754
+
755
+ ### Overview
756
+
757
+ `Delimiter` controls which character separates elements in inline array format.
758
+
759
+ ### Available Delimiters
760
+
761
+ Use comma as the default separator:
762
+
763
+ ```scala
764
+ import zio.blocks.schema.toon._
765
+
766
+ val deriver = ToonCodecDeriver.withDelimiter(Delimiter.Comma)
767
+ // tags[3]: scala,zio,functional
768
+ ```
769
+
770
+ Use tab for wider compatibility with tab-separated values:
771
+
772
+ ```scala
773
+ import zio.blocks.schema.toon._
774
+
775
+ val deriver = ToonCodecDeriver.withDelimiter(Delimiter.Tab)
776
+ // tags[3]: scala zio functional
777
+ ```
778
+
779
+ Use pipe for visibility in complex inline arrays:
780
+
781
+ ```scala
782
+ import zio.blocks.schema.toon._
783
+
784
+ val deriver = ToonCodecDeriver.withDelimiter(Delimiter.Pipe)
785
+ // tags[3]: scala|zio|functional
786
+ ```
787
+
788
+ ---
789
+
790
+ ## ToonReader
791
+
792
+ Low-level binary parser implementing TOON format with state management and efficient token scanning.
793
+
794
+ ### Overview
795
+
796
+ `ToonReader` provides stateful reading of TOON-encoded data with automatic token recognition and error reporting at the byte level. It handles indentation tracking, quoted string parsing, and numeric value extraction.
797
+
798
+ ### Reading from Byte Array
799
+
800
+ To parse TOON data from a byte array:
801
+
802
+ ```scala
803
+ import zio.blocks.schema._
804
+ import zio.blocks.schema.toon._
805
+
806
+ case class Person(name: String, age: Int)
807
+ object Person { implicit val schema: Schema[Person] = Schema.derived }
808
+
809
+ val toonBytes = "name: Alice\nage: 30".getBytes("UTF-8")
810
+ // Use the codec API for reading (ToonReader is an internal implementation detail)
811
+ val codec = Person.schema.derive(ToonFormat)
812
+ val result = codec.decode(toonBytes)
813
+ ```
814
+
815
+ ### Low-Level Parsing
816
+
817
+ Direct token-by-token parsing for custom scenarios:
818
+
819
+ ```scala
820
+ import zio.blocks.schema._
821
+ import zio.blocks.schema.toon._
822
+
823
+ // ToonReader is an internal implementation detail of the codec
824
+ // Use the public codec API instead:
825
+ case class Data(id: Int, name: String)
826
+ object Data { implicit val schema: Schema[Data] = Schema.derived }
827
+
828
+ val codec = Data.schema.derive(ToonFormat)
829
+ // Codec provides token-aware parsing and composition for reading
830
+ val toonString = "id: 1\nname: test"
831
+ val result = codec.decode(toonString)
832
+ ```
833
+
834
+ ---
835
+
836
+ ## ToonWriter
837
+
838
+ Low-level binary encoder implementing TOON format with optimization for compact representation.
839
+
840
+ ### Overview
841
+
842
+ `ToonWriter` provides efficient writing of Scala values into TOON binary format with automatic formatting, indentation, and type-specific encoding.
843
+
844
+ ### Writing to Byte Array
845
+
846
+ To encode values to TOON format:
847
+
848
+ ```scala
849
+ import zio.blocks.schema.toon._
850
+ ```
851
+
852
+ ### Custom Encoding Strategies
853
+
854
+ The writer selects encoding strategies based on value type and configuration:
855
+
856
+ ```scala
857
+ import zio.blocks.schema.toon._
858
+ ```
859
+
860
+ ---
861
+
862
+ ## NameMapper
863
+
864
+ Transformation strategies for field and case names during encoding and decoding.
865
+
866
+ ### Overview
867
+
868
+ `NameMapper` provides predefined transformation functions for converting between Scala naming conventions and TOON field names. This enables encoding data with different naming styles without changing your Scala types.
869
+
870
+ ### Identity Mapping
871
+
872
+ Use Scala field names as-is without transformation:
873
+
874
+ ```scala
875
+ import zio.blocks.schema.toon._
876
+
877
+ val deriver = ToonCodecDeriver.withFieldNameMapper(NameMapper.Identity)
878
+ // firstName → firstName
879
+ ```
880
+
881
+ ### Snake Case Mapping
882
+
883
+ Convert camelCase field names to snake_case:
884
+
885
+ ```scala
886
+ import zio.blocks.schema.toon._
887
+
888
+ val deriver = ToonCodecDeriver.withFieldNameMapper(NameMapper.SnakeCase)
889
+ // firstName → first_name
890
+ // emailAddress → email_address
891
+ ```
892
+
893
+ ### Kebab Case Mapping
894
+
895
+ Convert camelCase field names to kebab-case:
896
+
897
+ ```scala
898
+ import zio.blocks.schema.toon._
899
+
900
+ val deriver = ToonCodecDeriver.withFieldNameMapper(NameMapper.KebabCase)
901
+ // firstName → first-name
902
+ // emailAddress → email-address
903
+ ```
904
+
905
+ ---
906
+
907
+ ## DiscriminatorKind
908
+
909
+ Controls how variant (sealed trait) discriminators appear in TOON output.
910
+
911
+ ### Overview
912
+
913
+ `DiscriminatorKind` determines whether variant types are identified by a key discriminator, a field discriminator, or no discriminator at all.
914
+
915
+ ### Key Discriminator
916
+
917
+ Use the variant case name as the TOON key (default):
918
+
919
+ ```scala
920
+ import zio.blocks.schema.toon._
921
+
922
+ val deriver = ToonCodecDeriver.withDiscriminatorKind(DiscriminatorKind.Key)
923
+ // Running:
924
+ // pid: 42
925
+ ```
926
+
927
+ ### Field Discriminator
928
+
929
+ Include a dedicated field for the variant type:
930
+
931
+ ```scala
932
+ import zio.blocks.schema.toon._
933
+
934
+ val deriver = ToonCodecDeriver.withDiscriminatorKind(DiscriminatorKind.Field("type"))
935
+ // type: Running
936
+ // pid: 42
937
+ ```
938
+
939
+ ### No Discriminator
940
+
941
+ Omit discriminators entirely (for unambiguous contexts):
942
+
943
+ ```scala
944
+ import zio.blocks.schema.toon._
945
+
946
+ val deriver = ToonCodecDeriver.withDiscriminatorKind(DiscriminatorKind.None)
947
+ // pid: 42
948
+ ```
949
+
950
+ ---
951
+
952
+ ## KeyFolding
953
+
954
+ Strategy for flattening nested record keys into dot-separated paths during encoding.
955
+
956
+ ### Overview
957
+
958
+ `KeyFolding` controls whether deeply nested fields are flattened using dot notation or kept as indented structures. This is useful when generating TOON for consumption by systems expecting flat key-value pairs.
959
+
960
+ ### Off (No Flattening)
961
+
962
+ Keep nested structure as indented records:
963
+
964
+ ```scala
965
+ import zio.blocks.schema.toon._
966
+
967
+ val config = WriterConfig.withKeyFolding(KeyFolding.Off)
968
+ // address:
969
+ // street: Main St
970
+ // city: Springfield
971
+ ```
972
+
973
+ ### Safe Flattening
974
+
975
+ Flatten shallow nesting with dot-separated keys:
976
+
977
+ ```scala
978
+ import zio.blocks.schema.toon._
979
+
980
+ val config = WriterConfig.withKeyFolding(KeyFolding.Safe)
981
+ // address.street: Main St
982
+ // address.city: Springfield
983
+ ```
984
+
985
+ ---
986
+
987
+ ## PathExpansion
988
+
989
+ Strategy for parsing dot-separated keys as nested records during decoding.
990
+
991
+ ### Overview
992
+
993
+ `PathExpansion` controls whether TOON keys like `user.name` are interpreted as nested structures or literal key names. This enables reading flat TOON data as deeply nested types.
994
+
995
+ ### Off (No Expansion)
996
+
997
+ Treat dots in keys as literal characters:
998
+
999
+ ```scala
1000
+ import zio.blocks.schema.toon._
1001
+
1002
+ val config = ReaderConfig.withExpandPaths(PathExpansion.Off)
1003
+ // Literal key "user.name" stays flat
1004
+ ```
1005
+
1006
+ ### Safe Expansion
1007
+
1008
+ Expand dot-separated keys to nested records:
1009
+
1010
+ ```scala
1011
+ import zio.blocks.schema.toon._
1012
+
1013
+ val config = ReaderConfig.withExpandPaths(PathExpansion.Safe)
1014
+ // Key "user.name" expands to {user: {name: value}}
1015
+ ```
1016
+
1017
+ ---
1018
+
1019
+ ## Integration Points
1020
+
1021
+ The TOON codec module integrates seamlessly with ZIO Schema and other ZIO Blocks modules:
1022
+
1023
+ **With ZIO Schema:**
1024
+ - The module uses `Schema[A]` to derive codecs automatically
1025
+ - Supports all schema types: primitives, records, variants, sequences, maps, options
1026
+ - Integrates through the standard `BinaryFormat` mechanism
1027
+
1028
+ **Internal Type Relationships:**
1029
+ - `ToonCodecDeriver` drives all codec derivation via `ToonCodecDeriver.derive(schema)`
1030
+ - `WriterConfig` controls `ToonWriter` behavior during encoding
1031
+ - `ReaderConfig` controls `ToonReader` behavior during decoding
1032
+ - `NameMapper`, `ArrayFormat`, `Delimiter`, `DiscriminatorKind` all flow through `ToonCodecDeriver` configuration
1033
+ - `KeyFolding` and `PathExpansion` affect how nested structures are serialized/deserialized
1034
+
1035
+ **With Other Modules:**
1036
+ - TOON codecs work alongside other codec modules (JSON, Thrift, YAML, MessagePack) via the format system
1037
+ - Can be combined with `Schema` evolution utilities for schema versioning
1038
+ - Integrates with `DynamicValue` for generic data handling
1039
+
1040
+ ---
1041
+
1042
+ ## Error Handling
1043
+
1044
+ TOON decoding errors include location traces showing the path through nested structures where the error occurred.
1045
+
1046
+ ### Understanding Error Traces
1047
+
1048
+ Errors render as paths like `.field[0].nested.value` showing exactly where decoding failed:
1049
+
1050
+ ```scala
1051
+ import zio.blocks.schema._
1052
+ import zio.blocks.schema.toon._
1053
+
1054
+ case class Team(name: String, members: List[String])
1055
+
1056
+ object Team {
1057
+ implicit val schema: Schema[Team] = Schema.derived
1058
+ }
1059
+
1060
+ val codec = Team.schema.derive(ToonFormat)
1061
+ val invalidToon = """
1062
+ name: Engineering
1063
+ members: invalid
1064
+ """
1065
+
1066
+ val result = codec.decode(invalidToon)
1067
+
1068
+ result match {
1069
+ case Right(team) => println(s"Loaded: $team")
1070
+ case Left(error) =>
1071
+ println(s"Error: ${error.getMessage}")
1072
+ // Error: Expected sequence, got: invalid at: .members
1073
+ }
1074
+ ```
1075
+
1076
+ ### Zero-Overhead Error Handling
1077
+
1078
+ Errors use zero-overhead exceptions (no stack traces) for efficient error reporting in scenarios where errors are expected and handled inline.