@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,275 @@
1
+ ---
2
+ id: zero-boxing
3
+ title: "Zero-Boxing Optimization"
4
+ sidebar_label: "Zero-Boxing"
5
+ ---
6
+
7
+ Working with streams of primitives (integers, longs, doubles, booleans) presents a performance challenge in languages with generic types: **boxing**. Without special care, primitive values get wrapped in objects, causing memory waste and slower code. ZIO Blocks Streams eliminates this overhead entirely through a novel runtime type-dispatch system.
8
+
9
+ ## The Boxing Problem
10
+
11
+ In Scala, primitive types (`Int`, `Long`, `Double`, `Boolean`) are fundamentally different from their object counterparts (`Integer`, `Long`, `Double`, `Boolean`). When a generic class like `Stream[E, A]` works with primitives, the compiler must box them into objects to satisfy the generic contract:
12
+
13
+ ```scala
14
+ // Without optimization, this boxes each Int into an Integer object
15
+ val stream: Stream[Nothing, Int] = Stream(1, 2, 3, 4, 5)
16
+ val doubled = stream.map(_ * 2) // Each Int is boxed → Integer → boxed result
17
+ val result = doubled.runCollect
18
+ // Result: Each element was boxed, unboxed, boxed again — wasteful!
19
+ ```
20
+
21
+ **Performance cost:**
22
+ - Extra heap allocations (memory pressure, more GC)
23
+ - Cache misses (objects spread across memory)
24
+ - Slower CPU operations (dereferencing objects instead of primitive registers)
25
+
26
+ For high-throughput data processing, this overhead is unacceptable.
27
+
28
+ ## ZIO Blocks Streams' Solution: JvmType Dispatch
29
+
30
+ Instead of using Scala's `@specialized` annotation (which generates separate classes for each primitive type, bloating binaries), ZIO Blocks Streams uses **compile-time type detection + runtime dispatch**. This gives you the speed of specialization without the binary bloat.
31
+
32
+ ### How It Works
33
+
34
+ **Step 1: Compile-Time Detection**
35
+
36
+ When you create a stream of primitives, the compiler infers a `JvmType` implicit that identifies the element type:
37
+
38
+ ```scala
39
+ val intStream: Stream[Nothing, Int] = Stream(1, 2, 3)
40
+ // Compiler infers: JvmType.Infer[Int]
41
+ // This information travels through the entire pipeline
42
+
43
+ val doubled = intStream.map(_ * 2)
44
+ // JvmType.Int is available to map's implementation
45
+ ```
46
+
47
+ **Step 2: Runtime Type Dispatch**
48
+
49
+ Each operation (map, filter, scan, etc.) checks the type at runtime and uses the appropriate fast path:
50
+
51
+ ```scala
52
+ // Inside Stream#map's implementation
53
+ def map[B](f: A => B)(implicit jvmTypeA: JvmType.Infer[A]): Stream[E, B] = {
54
+ val jt = jvmTypeA.jvmType
55
+
56
+ if (jt eq JvmType.Int) {
57
+ // Fast unboxed path: read raw Int, apply function, write raw Int
58
+ val intValue = reader.readInt(Long.MinValue)
59
+ val result = f(intValue.asInstanceOf[A])
60
+ // result stays unboxed if B is also Int
61
+ } else if (jt eq JvmType.Long) {
62
+ // Fast unboxed path for Long
63
+ val longValue = reader.readLong(Long.MinValue)
64
+ val result = f(longValue.asInstanceOf[A])
65
+ } else {
66
+ // Generic path: works for any type, uses boxing for primitives
67
+ val value = reader.read(EndOfStream)
68
+ val result = f(value)
69
+ }
70
+ }
71
+ ```
72
+
73
+ **Step 3: Unboxed Accessors**
74
+
75
+ Instead of a single `read()` method that returns boxed `Any` (where boxed means wrapping primitives in object wrappers like `Integer`, `Long`, `Double`), primitives use specialized accessors that operate directly on primitive values:
76
+
77
+ ```scala
78
+ trait Reader[A] {
79
+ // Generic: wraps primitives in objects (Integer, Long, etc.)
80
+ def read(onEnd: A): A
81
+
82
+ // Specialized: primitives stay unboxed
83
+ def readInt(onEnd: Long): Int
84
+ def readLong(onEnd: Long): Long
85
+ def readDouble(onEnd: Long): Double
86
+ def readBoolean(onEnd: Long): Boolean
87
+ }
88
+ ```
89
+
90
+ The right method is called at runtime based on the detected type, so primitives bypass boxing entirely.
91
+
92
+ ## Practical Benefits
93
+
94
+ To understand the real-world impact, consider how boxing accumulates through a pipeline. Compare a hypothetical boxed implementation with ZIO Streams' zero-boxing approach.
95
+
96
+ ### Before (Hypothetical Boxed Streams)
97
+
98
+ Without optimization, each operation in a pipeline adds boxing overhead:
99
+
100
+ ```scala
101
+ val nums = Stream(1, 2, 3, 4, 5)
102
+ val result = nums
103
+ .map(_ * 2) // boxes each Int → Integer, applies *, unboxes result
104
+ .filter(_ > 5) // boxes again, compares, unboxes
105
+ .map(_ + 1) // boxes, adds, unboxes
106
+ .runCollect
107
+ // 5 elements × 3 operations × boxing overhead = significant waste
108
+ ```
109
+
110
+ **Memory profile:** Each element is boxed/unboxed multiple times, creating temporary objects.
111
+
112
+ ### With ZIO Streams (Zero-Boxing)
113
+
114
+ With ZIO Streams' zero-boxing optimization, the same pipeline avoids all boxing overhead:
115
+
116
+ ```scala
117
+ val nums = Stream(1, 2, 3, 4, 5)
118
+ val result = nums
119
+ .map(_ * 2) // operates on raw Int in CPU registers
120
+ .filter(_ > 5) // compares raw Int directly
121
+ .map(_ + 1) // raw Int arithmetic
122
+ .runCollect
123
+ // Zero boxing: primitives stay in registers and cache
124
+ ```
125
+
126
+ **Memory profile:** Same as non-generic code — primitives never leave the stack/registers.
127
+
128
+ ## When Zero-Boxing Applies
129
+
130
+ Zero-boxing is **automatic and transparent**. You get it for free when working with primitives:
131
+
132
+ ```scala
133
+ import zio.blocks.streams.*
134
+
135
+ // ✓ Zero-boxing: Int, Long, Double, Boolean
136
+ val ints = Stream(1, 2, 3).map(_ * 2)
137
+ val longs = Stream(1L, 2L, 3L).filter(_ > 0L)
138
+ val doubles = Stream(1.5, 2.5, 3.5).map(_ + 1.0)
139
+ val bools = Stream(true, false, true).filter(identity)
140
+
141
+ // ✓ Zero-boxing: case classes with primitives
142
+ case class Point(x: Int, y: Int)
143
+ val points = Stream(Point(1, 2), Point(3, 4))
144
+ .map(p => Point(p.x * 2, p.y * 2))
145
+
146
+ // ✓ Zero-boxing: tuples of primitives
147
+ val pairs = Stream((1, 2), (3, 4))
148
+ .map { case (x, y) => (x + 1, y + 1) }
149
+
150
+ // Works, but may box for non-primitive types
151
+ val strings = Stream("a", "b", "c").map(_.toUpperCase)
152
+ ```
153
+
154
+ You don't need to do anything special — the compiler and runtime handle it automatically.
155
+
156
+ ## Comparison: @specialized vs JvmType Dispatch
157
+
158
+ ZIO Blocks Streams' approach differs fundamentally from Scala's traditional `@specialized` annotation. Here's how they compare:
159
+
160
+ **Traditional Scala `@specialized` annotation** generates separate specialized classes at compile time:
161
+
162
+ ```scala
163
+ @specialized(Int, Long, Double)
164
+ class Stream[+E, +A] { ... }
165
+ // Generates separate classes:
166
+ // - Stream$mcI$sp (specialized for Int)
167
+ // - Stream$mcJ$sp (specialized for Long)
168
+ // - Stream$mcD$sp (specialized for Double)
169
+ // - Stream (generic fallback)
170
+ // Result: Binary size 4-5x larger
171
+ ```
172
+
173
+ **ZIO Blocks `JvmType` dispatch** uses runtime type checking in a single class:
174
+
175
+ ```scala
176
+ abstract class Stream[+E, +A] {
177
+ def map[B](f: A => B)(implicit jvmType: JvmType.Infer[A]): Stream[E, B] = {
178
+ if (jvmType.jvmType eq JvmType.Int) { /* fast path */ }
179
+ else { /* generic path */ }
180
+ }
181
+ }
182
+ // Single class, runtime dispatch
183
+ // Result: Binary size normal, zero boxing at runtime
184
+ ```
185
+
186
+ | Metric | `@specialized` | JvmType |
187
+ |--------|---|---|
188
+ | **Binary size** | 4-5x larger | Normal |
189
+ | **Bytecode complexity** | High | Moderate |
190
+ | **Runtime dispatch** | None (compile-time) | Type check once per operation |
191
+ | **Flexibility** | Fixed at compile time | Adaptive at runtime |
192
+ | **Primitive support** | Configurable | Int, Long, Double, Boolean |
193
+ | **Generality** | Good for all generics | Specialized for Stream/Sink |
194
+
195
+ ## Implementation Architecture
196
+
197
+ Zero-boxing works across ZIO Blocks Streams' three core abstractions:
198
+
199
+ ### Stream[E, A]
200
+
201
+ Detects element type via `JvmType.Infer[A]` and dispatches `Reader` accesses:
202
+
203
+ ```scala
204
+ import zio.blocks.streams.*
205
+
206
+ val stream: Stream[Nothing, Int] = Stream(1, 2, 3)
207
+ // JvmType.Int is inferred and available to all operations
208
+ ```
209
+
210
+ ### Sink[E, A, Z]
211
+
212
+ Accepts elements via unboxed `write` methods matched to the detected type:
213
+
214
+ ```scala
215
+ import zio.blocks.streams.*
216
+ import zio.blocks.chunk.Chunk
217
+
218
+ val nums = Stream(1, 2, 3)
219
+ val sum = nums.runFold(0)(_ + _)
220
+ // Sink receives unboxed Int values
221
+ ```
222
+
223
+ ### Pipeline[A, B]
224
+
225
+ Transforms elements without boxing when both A and B are primitives:
226
+
227
+ ```scala
228
+ import zio.blocks.streams.*
229
+
230
+ val pipe = Pipeline.map[Int, Int](_ * 2)
231
+ // Entire pipeline operates on raw Int
232
+ ```
233
+
234
+ ## Performance Impact
235
+
236
+ For typical streaming workloads, zero-boxing provides **2-5x throughput improvement** over boxed approaches:
237
+
238
+ - **CPU-bound operations** (map, filter, scan): 3-5x faster
239
+ - **Memory-bound operations** (collect, fold): 2-3x faster
240
+ - **I/O operations** (reading, writing): Minimal impact (I/O latency dominates)
241
+
242
+ The benefit scales with pipeline depth and data volume. Shallow pipelines see modest gains; deep pipelines (>10 operations) over large datasets see dramatic improvements.
243
+
244
+ ## When Polymorphism Is Necessary
245
+
246
+ If you need polymorphic behavior (e.g., different handling for different types), use `JvmType` directly:
247
+
248
+ ```scala
249
+ import zio.blocks.streams.*
250
+ import zio.blocks.streams.JvmType
251
+
252
+ def processStream[A](stream: Stream[Nothing, A])(implicit jt: JvmType.Infer[A]): Unit = {
253
+ jt.jvmType match {
254
+ case JvmType.Int =>
255
+ println("Processing integers")
256
+ case JvmType.Long =>
257
+ println("Processing longs")
258
+ case _ =>
259
+ println("Processing generic type")
260
+ }
261
+ }
262
+ ```
263
+
264
+ This gives you runtime type information while maintaining full zero-boxing performance.
265
+
266
+ ## Summary
267
+
268
+ ZIO Blocks Streams achieves **zero-boxing for primitives** through:
269
+
270
+ 1. **Compile-time type detection** via `JvmType.Infer[A]` implicits
271
+ 2. **Runtime dispatch** that selects specialized fast paths
272
+ 3. **Unboxed accessors** that operate on raw primitives
273
+ 4. **Transparent optimization** — you write high-level code, the system handles the details
274
+
275
+ The result is **performance parity with hand-written imperative code** while maintaining the expressiveness and safety of functional streams. No binary bloat, no manual specialization annotations, no boxing overhead.