@zio.dev/zio-blocks 0.0.29 → 0.0.31

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 (36) hide show
  1. package/guides/compile-time-resource-safety-with-scope.md +997 -0
  2. package/guides/query-dsl-extending.md +1 -1
  3. package/guides/query-dsl-fluent-builder.md +203 -203
  4. package/guides/query-dsl-reified-optics.md +1 -1
  5. package/guides/query-dsl-sql.md +1 -1
  6. package/guides/zio-schema-migration.md +8 -8
  7. package/index.md +20 -14
  8. package/package.json +1 -1
  9. package/reference/codec.md +17 -17
  10. package/reference/context.md +49 -1
  11. package/reference/docs.md +1 -1
  12. package/reference/dynamic-schema.md +39 -42
  13. package/reference/formats.md +5 -11
  14. package/reference/json-schema.md +2 -2
  15. package/reference/json.md +34 -43
  16. package/reference/media-type.md +2 -2
  17. package/reference/modifier.md +4 -4
  18. package/reference/resource-management/defer-handle.md +246 -0
  19. package/reference/resource-management/finalization.md +286 -0
  20. package/reference/resource-management/finalizer.md +167 -0
  21. package/reference/{resource-management-di → resource-management}/index.md +3 -8
  22. package/reference/{resource-management-di → resource-management}/resource.md +532 -50
  23. package/reference/resource-management/scope.md +3026 -0
  24. package/reference/resource-management/unscoped.md +125 -0
  25. package/reference/{resource-management-di → resource-management}/wire.md +122 -28
  26. package/reference/schema-error.md +0 -1
  27. package/reference/schema-evolution/as.md +4 -4
  28. package/reference/schema-evolution/into.md +2 -2
  29. package/reference/schema-expr.md +2 -2
  30. package/reference/schema.md +9 -4
  31. package/reference/streams.md +989 -0
  32. package/reference/type-class-derivation.md +14 -15
  33. package/ringbuffer.md +1 -1
  34. package/sidebars.js +9 -4
  35. package/undocumented-report.md +1 -1
  36. package/reference/resource-management-di/scope.md +0 -1423
@@ -0,0 +1,125 @@
1
+ ---
2
+ id: unscoped
3
+ title: "Unscoped"
4
+ ---
5
+
6
+ `Unscoped[A]` is a marker typeclass for types that can safely escape a scope without tracking. Types with an `Unscoped` instance are considered "safe data"—they don't hold resources and can be freely extracted from a scope. Here's the definition:
7
+
8
+ ```scala
9
+ trait Unscoped[A]
10
+ ```
11
+
12
+ The `Unscoped` typeclass distinguishes between two categories of types:
13
+
14
+ 1. **Unscoped types** (have an instance): Primitives, strings, collections, value types, and pure data. These can leave a scope without risk.
15
+ 2. **Scoped types** (no instance): Resources like streams, connections, handles. These must remain tracked within a scope.
16
+
17
+ When the `$` operator is used to access a scoped value, if the result type has an `Unscoped` instance, it returns the value directly (unwrapped). Otherwise, it returns the value still wrapped in `$`.
18
+
19
+ ## Motivation / Use Case
20
+
21
+ The exact problem: A `scoped` block automatically closes all resources when it exits. If you accidentally returned a resource (like a database connection or file handle) from the block, it would be closed—but you might try to use it later, causing a **use-after-close** crash. Here's an example (this would fail without `Unscoped`):
22
+
23
+ ```scala
24
+ import zio.blocks.scope.{Scope, Resource}
25
+
26
+ final class Database {
27
+ def query(sql: String) = s"result: $sql"
28
+ }
29
+
30
+ // Without Unscoped constraint, this compiles (BAD):
31
+ // val db: Database = Scope.global.scoped { scope =>
32
+ // val db = allocate(Resource(new Database()))
33
+ // db // BUG: returns the resource itself, not data extracted from it
34
+ // }
35
+ // db.query("SELECT 1") // CRASH: use-after-close (scope already closed it)
36
+ ```
37
+
38
+ The solution: `Unscoped` makes this a **compile error** instead of a runtime bug. When a `scoped` block returns a value, that value's type must have an `Unscoped` instance—meaning the type checker verifies you're only extracting *computed results* (like `Int`, `String`, or aggregate data), not resources themselves.
39
+
40
+ You can still extract computed results by using the `$` operator to unwrap scoped values *within* the scope:
41
+
42
+ ```scala
43
+ import zio.blocks.scope.{Scope, Resource}
44
+
45
+ Scope.global.scoped { scope =>
46
+ import scope._
47
+
48
+ val intValue = allocate(Resource(42))
49
+ // Extract the Int value (not the Resource), computed inside the scope
50
+ val n: Int = $(intValue)(x => x + 1)
51
+
52
+ val text = allocate(Resource("hello"))
53
+ // Extract the String value (not the Resource), computed inside the scope
54
+ val s: String = $(text)(x => x.toUpperCase)
55
+
56
+ (n, s) // Tuple of pure data: safe to return
57
+ }
58
+ ```
59
+
60
+ ## Returning Unscoped Data from Scopes
61
+
62
+ Extract computed results that don't hold resources:
63
+
64
+ ```scala
65
+ import zio.blocks.scope.{Scope, Resource, Unscoped}
66
+ import scala.concurrent.duration.{Duration, FiniteDuration}
67
+
68
+ case class ProcessingResult(count: Int, elapsed: FiniteDuration)
69
+
70
+ object ProcessingResult {
71
+ implicit val unscoped: Unscoped[ProcessingResult] = new Unscoped[ProcessingResult] {}
72
+ }
73
+
74
+ def processData(): ProcessingResult = Scope.global.scoped { scope =>
75
+ import scope._
76
+
77
+ val startTime = java.time.Instant.now()
78
+ val input = allocate(Resource(Seq(1, 2, 3, 4, 5)))
79
+ val count = $(input)(_.length)
80
+
81
+ val endTime = java.time.Instant.now()
82
+ val elapsed = java.time.Duration.between(startTime, endTime).toNanos
83
+
84
+ ProcessingResult(count, FiniteDuration(elapsed, java.util.concurrent.TimeUnit.NANOSECONDS))
85
+ }
86
+
87
+ val result = processData()
88
+ println(result)
89
+ ```
90
+
91
+ Only create instances for **pure data types** that don't hold resources. Never create instances for types that contain connections, streams, handles, or any resource-like fields.
92
+
93
+ ## Predefined Instances
94
+
95
+ All built-in instances follow a simple principle: **if a type cannot hold resources, it gets an `Unscoped` instance**. Collections inherit this property from their elements — `List[Int]` is unscoped because `Int` is unscoped.
96
+
97
+ **Primitive and atomic values** (cannot hold resources by nature):
98
+ - `Int`, `Long`, `Short`, `Byte`, `Char`, `Boolean`, `Float`, `Double`, `Unit`
99
+ - `String`, `BigInt`, `BigDecimal`
100
+ - `java.util.UUID`
101
+
102
+ **Collections with conditional instances** (safe when elements/entries are unscoped):
103
+ - Sequences: `Array[A]`, `List[A]`, `Vector[A]`, `Seq[A]`, `IndexedSeq[A]`, `Iterable[A]`
104
+ - Sets: `Set[A]`
105
+ - Maps: `Map[K, V]` (when both `K` and `V` are unscoped)
106
+ - Wrappers: `Option[A]`, `Either[A, B]`, `Tuple2[A, B]` through `Tuple4[A, B, C, D]`
107
+ - ZIO types: `zio.blocks.chunk.Chunk[A]`
108
+
109
+ **Standard library time types** (immutable, cannot hold resources):
110
+ - `java.time.Instant`, `LocalDate`, `LocalTime`, `LocalDateTime`, `ZonedDateTime`, `OffsetDateTime`
111
+ - `java.time.Duration`, `Period`, `ZoneId`, `ZoneOffset`
112
+ - `scala.concurrent.duration.Duration`, `FiniteDuration`
113
+
114
+ All other types (resources, handles, connections) must be manually defined if needed.
115
+
116
+
117
+ ## Thread Safety
118
+
119
+ `Unscoped` instances themselves are immutable and thread-safe. However, the types they mark must be truly immutable for safe concurrent use. For example, `Array[Int]` is mutable—if shared across threads without synchronization, it could cause data races.
120
+
121
+ ## Integration
122
+
123
+ - [`Scope.$`](./scope.md) — the operator that uses `Unscoped`
124
+ - [`Resource`](./resource.md) — types that provide `Unscoped` may be wrapped in resources
125
+ - [`Scope`](./scope.md) — manages the lifecycle of resources
@@ -3,7 +3,7 @@ id: wire
3
3
  title: "Wire"
4
4
  ---
5
5
 
6
- `Wire[-In, +Out]` is a **compile-time safe recipe for constructing a service and its dependencies**. Wires describe how to construct an `Out` value given access to its dependencies via a `Context[In]` and a `Scope` for finalization.
6
+ `Wire[-In, +Out]` is a **compile-time safe recipe for constructing a service and its dependencies**. Wires describe how to construct an `Out` value given access to its dependencies via a `Context[In]` and a `Scope` for finalization:
7
7
 
8
8
  ```scala
9
9
  sealed trait Wire[-In, +Out] {
@@ -60,7 +60,7 @@ final class App(service: UserService) {
60
60
 
61
61
  // Manual wiring:
62
62
  Scope.global.scoped { scope =>
63
- import scope.*
63
+ import scope._
64
64
  val config = Config("jdbc:postgres://localhost/db")
65
65
  val db = Resource.fromAutoCloseable(new Database(config)).allocate
66
66
  val service = new UserService($(db)(identity))
@@ -73,7 +73,7 @@ With `Wire` + `Resource.from`, the macro handles the dependency graph:
73
73
 
74
74
  ```scala
75
75
  Scope.global.scoped { scope =>
76
- import scope.*
76
+ import scope._
77
77
  val app = Resource.from[App](
78
78
  Wire(Config("jdbc:postgres://localhost/db"))
79
79
  ).allocate
@@ -89,23 +89,27 @@ Scope.global.scoped { scope =>
89
89
 
90
90
  ## Installation
91
91
 
92
+ Add the following dependency to your `build.sbt`:
93
+
92
94
  ```scala
93
- libraryDependencies += "dev.zio" %% "zio-blocks-scope" % "<version>"
95
+ libraryDependencies += "dev.zio" %% "zio-blocks-scope" % "0.0.31"
94
96
  ```
95
97
 
96
98
  For cross-platform (Scala.js):
97
99
 
98
100
  ```scala
99
- libraryDependencies += "dev.zio" %%% "zio-blocks-scope" % "<version>"
101
+ libraryDependencies += "dev.zio" %%% "zio-blocks-scope" % "0.0.31"
100
102
  ```
101
103
 
102
104
  Supported Scala versions: 2.13.x and 3.x.
103
105
 
104
106
  ## Construction
105
107
 
108
+ `Wire` provides multiple ways to create instances, ranging from automatic macro-based derivation to manual construction for custom logic. Here are the main construction methods:
109
+
106
110
  ### Wire.shared[T] — derive a shared wire
107
111
 
108
- The `Wire.shared[T]` macro inspects `T`'s primary constructor and generates a shared wire that reuses the same instance across dependents.
112
+ The `Wire.shared[T]` macro inspects `T`'s primary constructor and generates a shared wire that reuses the same instance across dependents:
109
113
 
110
114
  ```scala
111
115
  import zio.blocks.scope._
@@ -121,7 +125,7 @@ final class Database(config: Config) extends AutoCloseable {
121
125
  val wire: Wire.Shared[Config, Database] = Wire.shared[Database]
122
126
 
123
127
  Scope.global.scoped { scope =>
124
- import scope.*
128
+ import scope._
125
129
  val config = Config(debug = true)
126
130
  val deps = Context[Config](config)
127
131
  val db = allocate(wire.toResource(deps))
@@ -131,7 +135,7 @@ Scope.global.scoped { scope =>
131
135
 
132
136
  ### Wire.unique[T] — derive a unique wire
133
137
 
134
- Like `shared[T]`, but creates a fresh instance each time the wire is used. Use for request-scoped or per-call services.
138
+ Like `Wire.shared[T]`, but creates a fresh instance each time the wire is used. Use for request-scoped or per-call services:
135
139
 
136
140
  ```scala
137
141
  import zio.blocks.scope._
@@ -144,7 +148,7 @@ final class RequestHandler {
144
148
  val wire: Wire.Unique[Any, RequestHandler] = Wire.unique[RequestHandler]
145
149
 
146
150
  Scope.global.scoped { scope =>
147
- import scope.*
151
+ import scope._
148
152
  val deps = Context.empty[Any]
149
153
  val resource = wire.toResource(deps)
150
154
 
@@ -161,7 +165,7 @@ Scope.global.scoped { scope =>
161
165
 
162
166
  ### Wire.apply[T] — lift a pre-existing value
163
167
 
164
- Creates a shared wire that injects a value you already have. If the value is `AutoCloseable`, its `close()` method is automatically registered as a finalizer.
168
+ Creates a shared wire that injects a value you already have. If the value is `AutoCloseable`, its `close()` method is automatically registered as a finalizer:
165
169
 
166
170
  ```scala
167
171
  import zio.blocks.scope._
@@ -172,7 +176,7 @@ val config = Config("jdbc:postgres://localhost/db")
172
176
  val wire: Wire.Shared[Any, Config] = Wire(config)
173
177
 
174
178
  Scope.global.scoped { scope =>
175
- import scope.*
179
+ import scope._
176
180
  val cfg = allocate(wire.toResource(Context.empty[Any]))
177
181
  $(cfg)(_.dbUrl)
178
182
  }
@@ -180,7 +184,7 @@ Scope.global.scoped { scope =>
180
184
 
181
185
  ### Wire.Shared.fromFunction — manual shared wire construction
182
186
 
183
- Use this for custom construction logic when macro derivation doesn't fit.
187
+ Use this for custom construction logic when macro derivation doesn't fit:
184
188
 
185
189
  ```scala
186
190
  import zio.blocks.scope._
@@ -199,7 +203,7 @@ val wire: Wire.Shared[Config, Client] =
199
203
  }
200
204
 
201
205
  Scope.global.scoped { scope =>
202
- import scope.*
206
+ import scope._
203
207
  val config = Config(30)
204
208
  val deps = Context[Config](config)
205
209
  val client = allocate(wire.toResource(deps))
@@ -209,7 +213,7 @@ Scope.global.scoped { scope =>
209
213
 
210
214
  ### Wire.Unique.fromFunction — manual unique wire construction
211
215
 
212
- Like `fromFunction`, but for unique wires.
216
+ Like `Wire.Shared.fromFunction`, but for unique wires:
213
217
 
214
218
  ```scala
215
219
  import zio.blocks.scope._
@@ -225,7 +229,7 @@ val wire: Wire.Unique[Any, RequestContext] =
225
229
  }
226
230
 
227
231
  Scope.global.scoped { scope =>
228
- import scope.*
232
+ import scope._
229
233
  val deps = Context.empty[Any]
230
234
  val resource = wire.toResource(deps)
231
235
 
@@ -249,7 +253,7 @@ The fundamental difference is **reuse semantics**:
249
253
  | **Instance reuse** | Same instance across entire dependency graph | New instance per allocation |
250
254
  | **Finalization** | Runs when last referencing scope closes | Runs when each scope closes |
251
255
 
252
- In the diamond pattern (where `App` depends on both `UserService` and `OrderService`, both of which depend on `Database`), a shared wire ensures `Database` is constructed once and both services receive the same instance.
256
+ In the diamond pattern (where `App` depends on both `UserService` and `OrderService`, both of which depend on `Database`), a shared wire ensures `Database` is constructed once and both services receive the same instance:
253
257
 
254
258
  ```scala
255
259
  import zio.blocks.scope._
@@ -281,7 +285,7 @@ val resource = Resource.from[App](
281
285
  )
282
286
 
283
287
  Scope.global.scoped { scope =>
284
- import scope.*
288
+ import scope._
285
289
  val app = resource.allocate
286
290
  $(app)(_.check()) // true: Database is shared
287
291
  }
@@ -289,10 +293,21 @@ Scope.global.scoped { scope =>
289
293
 
290
294
  ## Core Operations
291
295
 
296
+ The `Wire` interface provides a set of operations for inspecting and transforming wires:
297
+
292
298
  ### `Wire#isShared` and `Wire#isUnique`
293
299
 
294
300
  Check the sharing strategy of a wire:
295
301
 
302
+ ```scala
303
+ trait Wire[-In, +Out] {
304
+ def isShared: Boolean
305
+ def isUnique: Boolean = !isShared
306
+ }
307
+ ```
308
+
309
+ Here's how to use these methods:
310
+
296
311
  ```scala
297
312
  import zio.blocks.scope._
298
313
 
@@ -309,6 +324,15 @@ println(s"uniqueWire.isUnique: ${uniqueWire.isUnique}") // true
309
324
 
310
325
  Convert a wire to the opposite strategy:
311
326
 
327
+ ```scala
328
+ trait Wire[-In, +Out] {
329
+ def shared: Wire.Shared[In, Out]
330
+ def unique: Wire.Unique[In, Out]
331
+ }
332
+ ```
333
+
334
+ Here's how to convert between sharing strategies:
335
+
312
336
  ```scala
313
337
  import zio.blocks.scope._
314
338
 
@@ -329,6 +353,14 @@ Calling `shared` on an already-shared wire returns `this` (identity); likewise `
329
353
 
330
354
  Converts the wire to a lazy `Resource` by providing the dependency context:
331
355
 
356
+ ```scala
357
+ trait Wire[-In, +Out] {
358
+ def toResource(deps: Context[In]): Resource[Out]
359
+ }
360
+ ```
361
+
362
+ Here's how to use this method:
363
+
332
364
  ```scala
333
365
  import zio.blocks.scope._
334
366
  import zio.blocks.context.Context
@@ -341,7 +373,7 @@ val deps = Context[Config](Config("hello"))
341
373
  val resource: Resource[Config] = wire.toResource(deps)
342
374
 
343
375
  Scope.global.scoped { scope =>
344
- import scope.*
376
+ import scope._
345
377
  val cfg = allocate(resource)
346
378
  $(cfg)(_.value)
347
379
  }
@@ -349,7 +381,15 @@ Scope.global.scoped { scope =>
349
381
 
350
382
  ### `Wire#make` — construct directly from a wire
351
383
 
352
- Directly construct a value without going through `Resource.toResource`. This is a low-level operation; prefer `allocate(wire.toResource(...))` for safety.
384
+ Directly construct a value without going through `Resource.toResource`. This is a low-level operation; prefer `allocate(wire.toResource(...))` for safety:
385
+
386
+ ```scala
387
+ trait Wire.Shared[-In, +Out] {
388
+ def make(scope: Scope, context: Context[In]): Out
389
+ }
390
+ ```
391
+
392
+ Here's how to use this method:
353
393
 
354
394
  ```scala
355
395
  import zio.blocks.scope._
@@ -362,7 +402,7 @@ final class Service {
362
402
  val wire = Wire.shared[Service]
363
403
 
364
404
  Scope.global.scoped { scope =>
365
- import scope.*
405
+ import scope._
366
406
  val service = wire.asInstanceOf[Wire.Shared[Any, Service]].make(scope, Context.empty[Any])
367
407
  println(service.getName)
368
408
  }
@@ -384,11 +424,11 @@ import zio.blocks.scope._
384
424
 
385
425
  final case class Config(dbUrl: String)
386
426
 
387
- final class Logger(using Finalizer) {
427
+ final class Logger(implicit finalizer: Finalizer) {
388
428
  def log(msg: String): Unit = println(msg)
389
429
  }
390
430
 
391
- final class Database(config: Config)(using scope: Scope) extends AutoCloseable {
431
+ final class Database(config: Config)(implicit scope: Scope) extends AutoCloseable {
392
432
  def connect(): Unit = {
393
433
  scope.defer(println("database connection closed"))
394
434
  println(s"connecting to ${config.dbUrl}")
@@ -492,9 +532,25 @@ cd zio-blocks
492
532
 
493
533
  **2. Run individual examples with sbt:**
494
534
 
495
- **Basic wire construction: deriving shared wires, lifting values, and converting to resources**
535
+ Basic wire construction demonstrates how to create and use `Wire` for dependency injection. View the example source code:
496
536
 
497
537
  ```scala title="scope-examples/src/main/scala/wire/WireBasicExample.scala"
538
+ /*
539
+ * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
540
+ *
541
+ * Licensed under the Apache License, Version 2.0 (the "License");
542
+ * you may not use this file except in compliance with the License.
543
+ * You may obtain a copy of the License at
544
+ *
545
+ * http://www.apache.org/licenses/LICENSE-2.0
546
+ *
547
+ * Unless required by applicable law or agreed to in writing, software
548
+ * distributed under the License is distributed on an "AS IS" BASIS,
549
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
550
+ * See the License for the specific language governing permissions and
551
+ * limitations under the License.
552
+ */
553
+
498
554
  package wire
499
555
 
500
556
  import zio.blocks.scope._
@@ -589,13 +645,31 @@ final class BasicApp(service: UserService) {
589
645
 
590
646
  ([source](https://github.com/zio/zio-blocks/blob/main/scope-examples/src/main/scala/wire/WireBasicExample.scala))
591
647
 
648
+ Run this example with:
649
+
592
650
  ```bash
593
- sbt "scope-examples/runMain wire.WireBasicExample"
651
+ sbt "scope-examples/runMain wire.wireBasicExample"
594
652
  ```
595
653
 
596
- **Comparing shared vs unique semantics: shared wires reuse the same instance across dependents, while unique wires create fresh instances**
654
+ Comparing shared vs unique semantics shows how shared wires reuse the same instance across dependents, while unique wires create fresh instances. View the example:
597
655
 
598
656
  ```scala title="scope-examples/src/main/scala/wire/WireSharedUniqueExample.scala"
657
+ /*
658
+ * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
659
+ *
660
+ * Licensed under the Apache License, Version 2.0 (the "License");
661
+ * you may not use this file except in compliance with the License.
662
+ * You may obtain a copy of the License at
663
+ *
664
+ * http://www.apache.org/licenses/LICENSE-2.0
665
+ *
666
+ * Unless required by applicable law or agreed to in writing, software
667
+ * distributed under the License is distributed on an "AS IS" BASIS,
668
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
669
+ * See the License for the specific language governing permissions and
670
+ * limitations under the License.
671
+ */
672
+
599
673
  package wire
600
674
 
601
675
  import zio.blocks.scope._
@@ -692,13 +766,31 @@ final class UniqueDependencyApp(a: ServiceA, b: ServiceB) {
692
766
 
693
767
  ([source](https://github.com/zio/zio-blocks/blob/main/scope-examples/src/main/scala/wire/WireSharedUniqueExample.scala))
694
768
 
769
+ Run this example with:
770
+
695
771
  ```bash
696
- sbt "scope-examples/runMain wire.WireSharedUniqueExample"
772
+ sbt "scope-examples/runMain wire.wireSharedUniqueExample"
697
773
  ```
698
774
 
699
- **Manual wire construction: using fromFunction for custom construction logic**
775
+ Manual wire construction demonstrates how to use `fromFunction` for custom construction logic. View the example:
700
776
 
701
777
  ```scala title="scope-examples/src/main/scala/wire/WireFromFunctionExample.scala"
778
+ /*
779
+ * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
780
+ *
781
+ * Licensed under the Apache License, Version 2.0 (the "License");
782
+ * you may not use this file except in compliance with the License.
783
+ * You may obtain a copy of the License at
784
+ *
785
+ * http://www.apache.org/licenses/LICENSE-2.0
786
+ *
787
+ * Unless required by applicable law or agreed to in writing, software
788
+ * distributed under the License is distributed on an "AS IS" BASIS,
789
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
790
+ * See the License for the specific language governing permissions and
791
+ * limitations under the License.
792
+ */
793
+
702
794
  package wire
703
795
 
704
796
  import zio.blocks.scope._
@@ -827,6 +919,8 @@ final class ManualWireApp(client: HttpClient, auth: Authenticator) {
827
919
 
828
920
  ([source](https://github.com/zio/zio-blocks/blob/main/scope-examples/src/main/scala/wire/WireFromFunctionExample.scala))
829
921
 
922
+ Run this example with:
923
+
830
924
  ```bash
831
- sbt "scope-examples/runMain wire.WireFromFunctionExample"
925
+ sbt "scope-examples/runMain wire.wireFromFunctionExample"
832
926
  ```
@@ -539,7 +539,6 @@ Path annotation (`atField`, `atIndex`, `atKey`, `atCase`) builds a [`DynamicOpti
539
539
  ```scala
540
540
  import zio.blocks.schema.{DynamicOptic, DynamicValue, Schema, SchemaError}
541
541
 
542
- implicit val intSchema: Schema[Int] = Schema[Int]
543
542
  val data = DynamicValue.Sequence(DynamicValue.int(1), DynamicValue.int(2))
544
543
  val optic = DynamicOptic.root.at(10)
545
544
 
@@ -39,13 +39,13 @@ The bidirectional data flow looks like this:
39
39
  `As` is part of `zio-blocks-schema`:
40
40
 
41
41
  ```scala
42
- libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.29"
42
+ libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.31"
43
43
  ```
44
44
 
45
45
  For Scala.js and Scala Native, use `%%%`:
46
46
 
47
47
  ```scala
48
- libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.29"
48
+ libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.31"
49
49
  ```
50
50
 
51
51
  Supported Scala versions: 2.13.x and 3.x.
@@ -240,7 +240,7 @@ trait As[A, B] {
240
240
 
241
241
  ```scala
242
242
  val revAs: As[LongBox, IntBox] = boxAs.reverse
243
- // revAs: As[LongBox, IntBox] = zio.blocks.schema.As$$anon$1@29407f04
243
+ // revAs: As[LongBox, IntBox] = zio.blocks.schema.As$$anon$1@70332401
244
244
 
245
245
  revAs.into(LongBox(5L))
246
246
  // res11: Either[SchemaError, IntBox] = Right(IntBox(5))
@@ -302,7 +302,7 @@ We import `As.reverseInto` and use it to obtain the reverse `Into[Int, String]`:
302
302
  import As.reverseInto
303
303
 
304
304
  val intToStr: Into[Int, String] = reverseInto[String, Int]
305
- // intToStr: Into[Int, String] = zio.blocks.schema.AsLowPriorityImplicits$$Lambda$16771/0x00007f092a81f330@1cdf3706
305
+ // intToStr: Into[Int, String] = zio.blocks.schema.AsLowPriorityImplicits$$Lambda$17467/0x00007f7456961130@3a9535e3
306
306
  intToStr.into(42)
307
307
  // res14: Either[SchemaError, String] = Right("42")
308
308
  ```
@@ -69,13 +69,13 @@ Compare this to a manual implementation:
69
69
  `Into` is part of the `zio-blocks-schema` module:
70
70
 
71
71
  ```scala
72
- libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.29"
72
+ libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.31"
73
73
  ```
74
74
 
75
75
  For Scala.js:
76
76
 
77
77
  ```scala
78
- libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.29"
78
+ libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.31"
79
79
  ```
80
80
 
81
81
  Supported Scala versions: 2.13.x and 3.x.
@@ -70,13 +70,13 @@ val result: Either[OpticCheck, Seq[Boolean]] = combined.eval(alice)
70
70
  ## Installation
71
71
 
72
72
  ```scala
73
- libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.29"
73
+ libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.31"
74
74
  ```
75
75
 
76
76
  For cross-platform (Scala.js):
77
77
 
78
78
  ```scala
79
- libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.29"
79
+ libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.31"
80
80
  ```
81
81
 
82
82
  Supported Scala versions: 2.13.x and 3.x.
@@ -173,8 +173,6 @@ ZIO Blocks provides specialized `Option` schemas optimized for primitive types.
173
173
  ```scala
174
174
  import zio.blocks.schema.Schema
175
175
 
176
- import zio.blocks.schema.Schema
177
-
178
176
  // Specialized primitive options (no boxing overhead)
179
177
  Schema[Option[Boolean]] // Also: Byte, Short, Int, Long, Float, Double, Char, Unit
180
178
  ```
@@ -193,12 +191,19 @@ Schema[Option[A]] // Generic option for reference types
193
191
  ZIO Blocks also provides polymorphic schemas for standard Scala collections. You can summon schemas for collections of any element type `A` (and key/value types `K`/`V` for maps):
194
192
 
195
193
  ```scala
194
+ import zio.blocks.schema.Schema
195
+
196
+ // Built-in Scala collections
196
197
  Schema[List[A]] // Immutable singly-linked list
197
198
  Schema[Vector[A]] // Immutable indexed sequence (efficient random access)
198
199
  Schema[Set[A]] // Immutable set (unique elements)
199
200
  Schema[Seq[A]] // General immutable sequence
200
201
  Schema[IndexedSeq[A]] // Indexed sequence
201
202
  Schema[Map[K, V]] // Immutable key-value mapping
203
+
204
+ // ZIO Blocks collections (the chunk module)
205
+ Schema[zio.blocks.chunk.Chunk[A]] // Chunk sequence
206
+ Schema[zio.blocks.chunk.ChunkMap[K, V]] // ChunkMap key-value mapping
202
207
  ```
203
208
 
204
209
  To learn how to create custom collection schemas, check out the [`Sequence`](./reflect.md#3-sequence) and [`Map`](./reflect.md#4-map) nodes on the documentation of [`Reflect`](./reflect.md) data type.
@@ -358,13 +363,13 @@ In the following example, we derive a JSON codec for the `Person` case class usi
358
363
 
359
364
  ```scala
360
365
  import zio.blocks.schema.Schema
361
- import zio.blocks.schema.json.{JsonFormat, JsonBinaryCodec}
366
+ import zio.blocks.schema.json.{JsonFormat, JsonCodec}
362
367
 
363
368
  case class Person(name: String, age: Int)
364
369
 
365
370
  object Person {
366
371
  implicit val schema: Schema[Person] = Schema.derived
367
- val codec: JsonBinaryCodec[Person] = schema.derive(JsonFormat)
372
+ val codec: JsonCodec[Person] = schema.derive(JsonFormat)
368
373
  }
369
374
 
370
375
  val person = Person("John", 42)