@zio.dev/zio-blocks 0.0.27 → 0.0.29
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.
- package/guides/query-dsl-extending.md +1 -1
- package/guides/query-dsl-fluent-builder.md +1 -1
- package/guides/query-dsl-reified-optics.md +1 -1
- package/guides/query-dsl-sql.md +1 -1
- package/guides/zio-schema-migration.md +6 -6
- package/index.md +69 -17
- package/package.json +1 -1
- package/path-interpolator.md +70 -9
- package/reference/allows.md +1155 -34
- package/reference/binding-resolver.md +469 -0
- package/reference/binding.md +1 -1
- package/reference/codec.md +8 -8
- package/reference/combinators.md +345 -0
- package/reference/context.md +639 -67
- package/reference/docs.md +1 -1
- package/reference/dynamic-optic.md +5 -0
- package/reference/dynamic-schema.md +602 -0
- package/reference/dynamic-value.md +5 -0
- package/reference/http-model.md +1716 -0
- package/reference/json-differ.md +320 -0
- package/reference/json-patch.md +803 -0
- package/reference/json.md +1 -1
- package/reference/media-type.md +2 -2
- package/reference/patch.md +4 -0
- package/reference/resource-management-di/index.md +49 -0
- package/reference/resource-management-di/resource.md +1125 -0
- package/{scope.md → reference/resource-management-di/scope.md} +92 -10
- package/reference/resource-management-di/wire.md +832 -0
- package/reference/schema-evolution/as.md +587 -0
- package/reference/schema-evolution/index.md +50 -0
- package/reference/schema-evolution/into.md +1027 -0
- package/reference/schema-expr.md +2 -2
- package/reference/structural-types.md +369 -0
- package/reference/type-class-derivation.md +31 -31
- package/reference/xml.md +606 -45
- package/ringbuffer.md +249 -0
- package/sidebars.js +31 -1
- package/reference/schema-evolution.md +0 -540
package/reference/schema-expr.md
CHANGED
|
@@ -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.
|
|
73
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.29"
|
|
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.
|
|
79
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.29"
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
Supported Scala versions: 2.13.x and 3.x.
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: structural-types
|
|
3
|
+
title: "Structural Types"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!--
|
|
7
|
+
BLOCKING ISSUE: Scala 3.7.4 Compiler Crash
|
|
8
|
+
============================================
|
|
9
|
+
|
|
10
|
+
This file uses structural type syntax ({ def field: Type }) which triggers a compiler
|
|
11
|
+
crash in Scala 3.7.4 during the erasure phase. Therefore, code blocks here are marked
|
|
12
|
+
as plain `scala` instead of `mdoc:compile-only` to allow the documentation build to pass.
|
|
13
|
+
|
|
14
|
+
WORKAROUND: Code examples are NOT compiled/type-checked until Scala 3.8.x is adopted.
|
|
15
|
+
|
|
16
|
+
TODO (When Scala 3.8.x is adopted):
|
|
17
|
+
1. Change all `\`\`\`scala` blocks back to `\`\`\`scala mdoc:compile-only`
|
|
18
|
+
2. Run `sbt docs/mdoc` to verify compilation succeeds
|
|
19
|
+
3. Delete this comment
|
|
20
|
+
|
|
21
|
+
Reference:
|
|
22
|
+
- Scala 3.7.4 compiler issue: https://github.com/scala/scala3/issues/24598 (or similar)
|
|
23
|
+
- Scala 3.8.x migration: PR #1169 "Preparing to migration on Scala 3.8.x"
|
|
24
|
+
- This PR: Addresses structural-types.md CI failures
|
|
25
|
+
-->
|
|
26
|
+
|
|
27
|
+
Structural types enable **duck typing** with ZIO Blocks schemas. Instead of requiring a nominal type name (like `class Person`), a structural schema validates based on the **shape** of an object — the fields it provides, regardless of how it was defined.
|
|
28
|
+
|
|
29
|
+
## Motivation
|
|
30
|
+
|
|
31
|
+
Consider a common integration scenario:
|
|
32
|
+
|
|
33
|
+
```scala
|
|
34
|
+
// Your system
|
|
35
|
+
case class Person(name: String, age: Int)
|
|
36
|
+
|
|
37
|
+
// External system (same data, different class)
|
|
38
|
+
case class User(name: String, age: Int)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Without structural types, converting between `Person` and `User` requires manual translation. With structural types, they both have the same structural schema:
|
|
42
|
+
|
|
43
|
+
```scala
|
|
44
|
+
import scala.language.reflectiveCalls
|
|
45
|
+
import zio.blocks.schema.Schema
|
|
46
|
+
|
|
47
|
+
case class Person(name: String, age: Int)
|
|
48
|
+
case class User(name: String, age: Int)
|
|
49
|
+
|
|
50
|
+
val personSchema = Schema.derived[Person]
|
|
51
|
+
val personStructural = personSchema.structural
|
|
52
|
+
// Schema[{ def name: String; def age: Int }]
|
|
53
|
+
|
|
54
|
+
val userSchema = Schema.derived[User]
|
|
55
|
+
val userStructural = userSchema.structural
|
|
56
|
+
// Schema[{ def name: String; def age: Int }]
|
|
57
|
+
|
|
58
|
+
// Both schemas accept the same data shape
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Construction: `Schema#structural`
|
|
62
|
+
|
|
63
|
+
Use the `Schema#structural` method on any schema to get the corresponding structural schema.
|
|
64
|
+
|
|
65
|
+
**Scala 3:** Using transparent inline — the return type is inferred to the full refinement type:
|
|
66
|
+
|
|
67
|
+
```scala
|
|
68
|
+
import zio.blocks.schema.Schema
|
|
69
|
+
|
|
70
|
+
case class Person(name: String, age: Int)
|
|
71
|
+
object Person {
|
|
72
|
+
implicit val schema: Schema[Person] = Schema.derived[Person]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
val personSchema: Schema[Person] = Schema.derived[Person]
|
|
76
|
+
val structuralSchema: Schema[{ def name: String; def age: Int }] = personSchema.structural
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Scala 2:** Implicit derivation — returns `Schema[ts.StructuralType]` (path-dependent type):
|
|
80
|
+
|
|
81
|
+
```scala
|
|
82
|
+
import zio.blocks.schema.Schema
|
|
83
|
+
|
|
84
|
+
case class Person(name: String, age: Int)
|
|
85
|
+
object Person {
|
|
86
|
+
implicit val schema: Schema[Person] = Schema.derived[Person]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
val personSchema: Schema[Person] = Schema.derived[Person]
|
|
90
|
+
val structuralSchema = personSchema.structural
|
|
91
|
+
// Type: Schema[ts.StructuralType] (structural type inferred from macro)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Supported Conversions
|
|
95
|
+
|
|
96
|
+
The following type categories can be converted to structural schemas:
|
|
97
|
+
|
|
98
|
+
### Product Types (Case Classes)
|
|
99
|
+
|
|
100
|
+
Both Scala 2 and 3 support structural conversion of case classes:
|
|
101
|
+
|
|
102
|
+
```scala
|
|
103
|
+
import zio.blocks.schema.Schema
|
|
104
|
+
|
|
105
|
+
case class Address(street: String, city: String, zipCode: Int)
|
|
106
|
+
object Address {
|
|
107
|
+
implicit val schema: Schema[Address] = Schema.derived[Address]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
val schema = Schema.derived[Address]
|
|
111
|
+
val structural = schema.structural
|
|
112
|
+
// Schema[{ def street: String; def city: String; def zipCode: Int }]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Tuples
|
|
116
|
+
|
|
117
|
+
Tuples convert to structural records with field names derived from positions:
|
|
118
|
+
|
|
119
|
+
```scala
|
|
120
|
+
import zio.blocks.schema.Schema
|
|
121
|
+
|
|
122
|
+
type StringIntBool = (String, Int, Boolean)
|
|
123
|
+
implicit val schema: Schema[StringIntBool] = Schema.derived[StringIntBool]
|
|
124
|
+
|
|
125
|
+
val tupleSchema = Schema.derived[(String, Int, Boolean)]
|
|
126
|
+
val structuralSchema = tupleSchema.structural
|
|
127
|
+
// Schema[{ def _1: String; def _2: Int; def _3: Boolean }]
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Nested Products
|
|
131
|
+
|
|
132
|
+
Nested product fields keep their nominal types; only the outer product is structuralized:
|
|
133
|
+
|
|
134
|
+
```scala
|
|
135
|
+
import zio.blocks.schema.Schema
|
|
136
|
+
|
|
137
|
+
case class Address(street: String, city: String)
|
|
138
|
+
object Address {
|
|
139
|
+
implicit val schema: Schema[Address] = Schema.derived[Address]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case class Person(name: String, age: Int, address: Address)
|
|
143
|
+
object Person {
|
|
144
|
+
implicit val schema: Schema[Person] = Schema.derived[Person]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
val personSchema = Schema.derived[Person]
|
|
148
|
+
val structuralSchema = personSchema.structural
|
|
149
|
+
// Schema[{
|
|
150
|
+
// def name: String
|
|
151
|
+
// def age: Int
|
|
152
|
+
// def address: Address
|
|
153
|
+
// }]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Opaque Types (Scala 3)
|
|
157
|
+
|
|
158
|
+
Opaque type aliases are unwrapped to their underlying type:
|
|
159
|
+
|
|
160
|
+
```scala
|
|
161
|
+
import zio.blocks.schema.Schema
|
|
162
|
+
|
|
163
|
+
opaque type UserId = String
|
|
164
|
+
|
|
165
|
+
case class User(id: UserId, name: String)
|
|
166
|
+
object User {
|
|
167
|
+
implicit val schema: Schema[User] = Schema.derived[User]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
val schema = Schema.derived[User]
|
|
171
|
+
val structural = schema.structural
|
|
172
|
+
// Schema[{ def id: String; def name: String }]
|
|
173
|
+
// (UserId unwrapped to String)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Sum Types / Sealed Traits (Scala 3)
|
|
177
|
+
|
|
178
|
+
Sealed traits and enums convert to union types with nested method syntax:
|
|
179
|
+
|
|
180
|
+
```scala
|
|
181
|
+
import zio.blocks.schema.Schema
|
|
182
|
+
|
|
183
|
+
sealed trait Shape
|
|
184
|
+
object Shape {
|
|
185
|
+
case class Circle(radius: Double) extends Shape
|
|
186
|
+
case class Rectangle(width: Double, height: Double) extends Shape
|
|
187
|
+
implicit val schema: Schema[Shape] = Schema.derived[Shape]
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
val schema = Schema.derived[Shape]
|
|
191
|
+
val structural = schema.structural
|
|
192
|
+
// Schema[
|
|
193
|
+
// { def Circle: { def radius: Double } } |
|
|
194
|
+
// { def Rectangle: { def height: Double; def width: Double } }
|
|
195
|
+
// ]
|
|
196
|
+
// (cases sorted alphabetically)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Enum syntax** (Scala 3):
|
|
200
|
+
|
|
201
|
+
```scala
|
|
202
|
+
import zio.blocks.schema.Schema
|
|
203
|
+
|
|
204
|
+
enum Color {
|
|
205
|
+
case Red, Green, Blue
|
|
206
|
+
}
|
|
207
|
+
object Color {
|
|
208
|
+
implicit val schema: Schema[Color] = Schema.derived[Color]
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
val schema = Schema.derived[Color]
|
|
212
|
+
val structural = schema.structural
|
|
213
|
+
// Schema[
|
|
214
|
+
// { def Blue: {} } |
|
|
215
|
+
// { def Green: {} } |
|
|
216
|
+
// { def Red: {} }
|
|
217
|
+
// ]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Cases appear in **alphabetical order** in the union type. This alphabetical ordering (applied to fields in products and case names in unions) ensures **deterministic, normalized type identity**: two structural types with the same fields but different declaration order produce the same structural type and normalized name. This is essential for predictable schema evolution and cross-system interop.
|
|
221
|
+
|
|
222
|
+
## Direct Structural Derivation (Scala 3)
|
|
223
|
+
|
|
224
|
+
Create a schema directly for a structural type without a nominal base:
|
|
225
|
+
|
|
226
|
+
```scala
|
|
227
|
+
import zio.blocks.schema.Schema
|
|
228
|
+
|
|
229
|
+
// No case class needed — define the schema for the shape directly
|
|
230
|
+
val personStructural = Schema.derived[{ def name: String; def age: Int }]
|
|
231
|
+
|
|
232
|
+
// The schema is ready to use with values matching that structural shape
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
This is only supported in **Scala 3** with the right macro machinery.
|
|
236
|
+
|
|
237
|
+
## Round-tripping Through DynamicValue
|
|
238
|
+
|
|
239
|
+
Structural schemas enable **cross-type conversion through `DynamicValue`** — encode a value of one nominal type and decode it as a *different* nominal type with the same structural shape. This is the core benefit of structural types for system integration.
|
|
240
|
+
|
|
241
|
+
### Motivation
|
|
242
|
+
|
|
243
|
+
In real integrations, you often receive data from an external system shaped like one type, but you need to work with it as a different type in your system. Without structural types, field-by-field translation is required. With structural types, if both types have identical shape, `DynamicValue` acts as the seamless bridge.
|
|
244
|
+
|
|
245
|
+
Common scenarios:
|
|
246
|
+
- **API gateways** — receive a `PersonDTO` from an external API, decode as your internal `Person` type
|
|
247
|
+
- **Message brokers** — consume an event shaped like `UserEvent`, convert to your domain `Account` type
|
|
248
|
+
- **Data pipelines** — records with identical fields but different class names from different services
|
|
249
|
+
|
|
250
|
+
### Cross-type conversion in action
|
|
251
|
+
|
|
252
|
+
Set up two types with identical structural shape:
|
|
253
|
+
|
|
254
|
+
```scala
|
|
255
|
+
import zio.blocks.schema.Schema
|
|
256
|
+
import zio.blocks.schema.SchemaError
|
|
257
|
+
|
|
258
|
+
case class Person(name: String, age: Int)
|
|
259
|
+
object Person {
|
|
260
|
+
implicit val schema: Schema[Person] = Schema.derived[Person]
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
case class Employee(name: String, age: Int)
|
|
264
|
+
object Employee {
|
|
265
|
+
implicit val schema: Schema[Employee] = Schema.derived[Employee]
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
val personSchema = Schema.derived[Person]
|
|
269
|
+
val employeeSchema = Schema.derived[Employee]
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Now encode a `Person` to `DynamicValue` and decode it as an `Employee`:
|
|
273
|
+
|
|
274
|
+
```scala
|
|
275
|
+
val person = Person("Alice", 30)
|
|
276
|
+
// person: Person = Person(name = "Alice", age = 30)
|
|
277
|
+
val dynamic = personSchema.toDynamicValue(person)
|
|
278
|
+
// dynamic: DynamicValue = Record(
|
|
279
|
+
// IndexedSeq(("name", Primitive(String("Alice"))), ("age", Primitive(Int(30))))
|
|
280
|
+
// )
|
|
281
|
+
|
|
282
|
+
val employee: Either[SchemaError, Employee] =
|
|
283
|
+
employeeSchema.fromDynamicValue(dynamic)
|
|
284
|
+
// employee: Either[SchemaError, Employee] = Right(
|
|
285
|
+
// Employee(name = "Alice", age = 30)
|
|
286
|
+
// )
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The structural shape guarantee ensures type-safe conversion: at compile time, you know both schemas accept the same fields, so round-tripping through `DynamicValue` is safe and zero-cost.
|
|
290
|
+
|
|
291
|
+
## Integration
|
|
292
|
+
|
|
293
|
+
Structural types integrate seamlessly with ZIO Blocks' broader ecosystem:
|
|
294
|
+
|
|
295
|
+
### With Schema Evolution Macros
|
|
296
|
+
|
|
297
|
+
Structural schemas work with [Schema Evolution](./schema-evolution/into.md) macros for cross-type conversion. When two types share the same structural shape, the conversion machinery can work across type boundaries:
|
|
298
|
+
|
|
299
|
+
```scala
|
|
300
|
+
import zio.blocks.schema.Schema
|
|
301
|
+
|
|
302
|
+
case class Person(name: String, age: Int)
|
|
303
|
+
object Person {
|
|
304
|
+
implicit val schema: Schema[Person] = Schema.derived[Person]
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
case class PersonDTO(name: String, age: Int)
|
|
308
|
+
object PersonDTO {
|
|
309
|
+
implicit val schema: Schema[PersonDTO] = Schema.derived[PersonDTO]
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Both types have identical structural schemas
|
|
313
|
+
val personSchema = Schema.derived[Person]
|
|
314
|
+
val dtoSchema = Schema.derived[PersonDTO]
|
|
315
|
+
|
|
316
|
+
// They share the same structural shape:
|
|
317
|
+
// Schema[{ def name: String; def age: Int }]
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### With Binding.of (Serialization)
|
|
321
|
+
|
|
322
|
+
Structural types are also supported by the `Binding.of` macro for high-performance serialization via register-based encoding:
|
|
323
|
+
|
|
324
|
+
```scala
|
|
325
|
+
import zio.blocks.schema.binding.Binding
|
|
326
|
+
|
|
327
|
+
// Direct structural type serialization (JVM only)
|
|
328
|
+
val binding = Binding.of[{ def name: String; def age: Int }]
|
|
329
|
+
|
|
330
|
+
// Works with nested structural types
|
|
331
|
+
val nestedBinding = Binding.of[{
|
|
332
|
+
def name: String
|
|
333
|
+
def address: { def street: String; def city: String }
|
|
334
|
+
}]
|
|
335
|
+
|
|
336
|
+
// Works with containers
|
|
337
|
+
val containerBinding = Binding.of[{
|
|
338
|
+
def name: String
|
|
339
|
+
def emails: List[String]
|
|
340
|
+
}]
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
This enables anonymous structural types to benefit from ZIO Blocks' high-performance serialization without requiring nominal case class definitions. Like `Schema#structural`, this is **JVM-only**.
|
|
344
|
+
|
|
345
|
+
See [Binding](./binding.md) for detailed serialization documentation.
|
|
346
|
+
|
|
347
|
+
## Running the Examples
|
|
348
|
+
|
|
349
|
+
Example applications demonstrating structural types are available in `schema-examples`:
|
|
350
|
+
|
|
351
|
+
```sh
|
|
352
|
+
# Simple product type
|
|
353
|
+
sbt "schema-examples/runMain structural.StructuralSimpleProductExample"
|
|
354
|
+
|
|
355
|
+
# Nested products
|
|
356
|
+
sbt "schema-examples/runMain structural.StructuralNestedProductExample"
|
|
357
|
+
|
|
358
|
+
# Sealed trait (Scala 3)
|
|
359
|
+
sbt "schema-examples/runMain structural.StructuralSealedTraitExample"
|
|
360
|
+
|
|
361
|
+
# Enum (Scala 3)
|
|
362
|
+
sbt "schema-examples/runMain structural.StructuralEnumExample"
|
|
363
|
+
|
|
364
|
+
# Tuples
|
|
365
|
+
sbt "schema-examples/runMain structural.StructuralTupleExample"
|
|
366
|
+
|
|
367
|
+
# Integration with Into macro
|
|
368
|
+
sbt "schema-examples/runMain structural.StructuralIntoExample"
|
|
369
|
+
```
|
|
@@ -107,7 +107,7 @@ trait Deriver[TC[_]] {
|
|
|
107
107
|
def deriveRecord[F[_, _], A](
|
|
108
108
|
fields: IndexedSeq[Term[F, A, ?]],
|
|
109
109
|
typeId: TypeId[A],
|
|
110
|
-
binding: Binding
|
|
110
|
+
binding: Binding.Record[A],
|
|
111
111
|
doc: Doc,
|
|
112
112
|
modifiers: Seq[Modifier.Reflect],
|
|
113
113
|
defaultValue: Option[A],
|
|
@@ -194,7 +194,7 @@ object DeriveShow extends Deriver[Show] {
|
|
|
194
194
|
override def derivePrimitive[A](
|
|
195
195
|
primitiveType: PrimitiveType[A],
|
|
196
196
|
typeId: TypeId[A],
|
|
197
|
-
binding: Binding
|
|
197
|
+
binding: Binding.Primitive[A],
|
|
198
198
|
doc: Doc,
|
|
199
199
|
modifiers: Seq[Modifier.Reflect],
|
|
200
200
|
defaultValue: Option[A],
|
|
@@ -213,7 +213,7 @@ object DeriveShow extends Deriver[Show] {
|
|
|
213
213
|
override def deriveRecord[F[_, _], A](
|
|
214
214
|
fields: IndexedSeq[Term[F, A, ?]],
|
|
215
215
|
typeId: TypeId[A],
|
|
216
|
-
binding: Binding
|
|
216
|
+
binding: Binding.Record[A],
|
|
217
217
|
doc: Doc,
|
|
218
218
|
modifiers: Seq[Modifier.Reflect],
|
|
219
219
|
defaultValue: Option[A],
|
|
@@ -255,7 +255,7 @@ object DeriveShow extends Deriver[Show] {
|
|
|
255
255
|
override def deriveVariant[F[_, _], A](
|
|
256
256
|
cases: IndexedSeq[Term[F, A, ?]],
|
|
257
257
|
typeId: TypeId[A],
|
|
258
|
-
binding: Binding
|
|
258
|
+
binding: Binding.Variant[A],
|
|
259
259
|
doc: Doc,
|
|
260
260
|
modifiers: Seq[Modifier.Reflect],
|
|
261
261
|
defaultValue: Option[A],
|
|
@@ -289,7 +289,7 @@ object DeriveShow extends Deriver[Show] {
|
|
|
289
289
|
override def deriveSequence[F[_, _], C[_], A](
|
|
290
290
|
element: Reflect[F, A],
|
|
291
291
|
typeId: TypeId[C[A]],
|
|
292
|
-
binding: Binding
|
|
292
|
+
binding: Binding.Seq[C, A],
|
|
293
293
|
doc: Doc,
|
|
294
294
|
modifiers: Seq[Modifier.Reflect],
|
|
295
295
|
defaultValue: Option[C[A]],
|
|
@@ -315,7 +315,7 @@ object DeriveShow extends Deriver[Show] {
|
|
|
315
315
|
key: Reflect[F, K],
|
|
316
316
|
value: Reflect[F, V],
|
|
317
317
|
typeId: TypeId[M[K, V]],
|
|
318
|
-
binding: Binding
|
|
318
|
+
binding: Binding.Map[M, K, V],
|
|
319
319
|
doc: Doc,
|
|
320
320
|
modifiers: Seq[Modifier.Reflect],
|
|
321
321
|
defaultValue: Option[M[K, V]],
|
|
@@ -341,7 +341,7 @@ object DeriveShow extends Deriver[Show] {
|
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
override def deriveDynamic[F[_, _]](
|
|
344
|
-
binding: Binding
|
|
344
|
+
binding: Binding.Dynamic,
|
|
345
345
|
doc: Doc,
|
|
346
346
|
modifiers: Seq[Modifier.Reflect],
|
|
347
347
|
defaultValue: Option[DynamicValue],
|
|
@@ -380,7 +380,7 @@ object DeriveShow extends Deriver[Show] {
|
|
|
380
380
|
override def deriveWrapper[F[_, _], A, B](
|
|
381
381
|
wrapped: Reflect[F, B],
|
|
382
382
|
typeId: TypeId[A],
|
|
383
|
-
binding: Binding
|
|
383
|
+
binding: Binding.Wrapper[A, B],
|
|
384
384
|
doc: Doc,
|
|
385
385
|
modifiers: Seq[Modifier.Reflect],
|
|
386
386
|
defaultValue: Option[A],
|
|
@@ -414,7 +414,7 @@ When the derivation process encounters a primitive type (e.g., `String`, `Int`),
|
|
|
414
414
|
def derivePrimitive[A](
|
|
415
415
|
primitiveType: PrimitiveType[A],
|
|
416
416
|
typeId: TypeId[A],
|
|
417
|
-
binding: Binding
|
|
417
|
+
binding: Binding.Primitive[A],
|
|
418
418
|
doc: Doc,
|
|
419
419
|
modifiers: Seq[Modifier.Reflect],
|
|
420
420
|
defaultValue: Option[A],
|
|
@@ -444,7 +444,7 @@ When the derivation process encounters a record type (e.g., a case class), it ca
|
|
|
444
444
|
def deriveRecord[F[_, _], A](
|
|
445
445
|
fields: IndexedSeq[Term[F, A, ?]],
|
|
446
446
|
typeId: TypeId[A],
|
|
447
|
-
binding: Binding
|
|
447
|
+
binding: Binding.Record[A],
|
|
448
448
|
doc: Doc,
|
|
449
449
|
modifiers: Seq[Modifier.Reflect],
|
|
450
450
|
defaultValue: Option[A],
|
|
@@ -512,7 +512,7 @@ When the derivation process encounters a variant type (e.g., a sealed trait with
|
|
|
512
512
|
def deriveVariant[F[_, _], A](
|
|
513
513
|
cases: IndexedSeq[Term[F, A, ?]],
|
|
514
514
|
typeId: TypeId[A],
|
|
515
|
-
binding: Binding
|
|
515
|
+
binding: Binding.Variant[A],
|
|
516
516
|
doc: Doc,
|
|
517
517
|
modifiers: Seq[Modifier.Reflect],
|
|
518
518
|
defaultValue: Option[A],
|
|
@@ -556,7 +556,7 @@ When the derivation process encounters a sequence type (e.g., `List[A]`), it cal
|
|
|
556
556
|
def deriveSequence[F[_, _], C[_], A](
|
|
557
557
|
element: Reflect[F, A],
|
|
558
558
|
typeId: TypeId[C[A]],
|
|
559
|
-
binding: Binding
|
|
559
|
+
binding: Binding.Seq[C, A],
|
|
560
560
|
doc: Doc,
|
|
561
561
|
modifiers: Seq[Modifier.Reflect],
|
|
562
562
|
defaultValue: Option[C[A]],
|
|
@@ -590,7 +590,7 @@ def deriveMap[F[_, _], M[_, _], K, V](
|
|
|
590
590
|
key: Reflect[F, K],
|
|
591
591
|
value: Reflect[F, V],
|
|
592
592
|
typeId: TypeId[M[K, V]],
|
|
593
|
-
binding: Binding
|
|
593
|
+
binding: Binding.Map[M, K, V],
|
|
594
594
|
doc: Doc,
|
|
595
595
|
modifiers: Seq[Modifier.Reflect],
|
|
596
596
|
defaultValue: Option[M[K, V]],
|
|
@@ -620,11 +620,11 @@ The derivation process for maps is similar to sequences, but we have two child i
|
|
|
620
620
|
|
|
621
621
|
### Dynamic Derivation
|
|
622
622
|
|
|
623
|
-
When the derivation process encounters a dynamic type (e.g., `DynamicValue`), it calls the `deriveDynamic` method of the `Deriver`. This method receives a `Binding
|
|
623
|
+
When the derivation process encounters a dynamic type (e.g., `DynamicValue`), it calls the `deriveDynamic` method of the `Deriver`. This method receives a `Binding.Dynamic` representing the dynamic type, along with other metadata such as documentation, modifiers, default values, and examples:
|
|
624
624
|
|
|
625
625
|
```scala
|
|
626
626
|
def deriveDynamic[F[_, _]](
|
|
627
|
-
binding: Binding
|
|
627
|
+
binding: Binding.Dynamic,
|
|
628
628
|
doc: Doc,
|
|
629
629
|
modifiers: Seq[Modifier.Reflect],
|
|
630
630
|
defaultValue: Option[DynamicValue],
|
|
@@ -667,7 +667,7 @@ When the derivation process encounters a wrapper type (e.g., a value class, opaq
|
|
|
667
667
|
def deriveWrapper[F[_, _], A, B](
|
|
668
668
|
wrapped: Reflect[F, B],
|
|
669
669
|
typeId: TypeId[A],
|
|
670
|
-
binding: Binding
|
|
670
|
+
binding: Binding.Wrapper[A, B],
|
|
671
671
|
doc: Doc,
|
|
672
672
|
modifiers: Seq[Modifier.Reflect],
|
|
673
673
|
defaultValue: Option[A],
|
|
@@ -875,7 +875,7 @@ object DeriveGen extends Deriver[Gen] {
|
|
|
875
875
|
override def derivePrimitive[A](
|
|
876
876
|
primitiveType: PrimitiveType[A],
|
|
877
877
|
typeId: TypeId[A],
|
|
878
|
-
binding: Binding
|
|
878
|
+
binding: Binding.Primitive[A],
|
|
879
879
|
doc: Doc,
|
|
880
880
|
modifiers: Seq[Modifier.Reflect],
|
|
881
881
|
defaultValue: Option[A],
|
|
@@ -913,7 +913,7 @@ object DeriveGen extends Deriver[Gen] {
|
|
|
913
913
|
override def deriveRecord[F[_, _], A](
|
|
914
914
|
fields: IndexedSeq[Term[F, A, ?]],
|
|
915
915
|
typeId: TypeId[A],
|
|
916
|
-
binding: Binding
|
|
916
|
+
binding: Binding.Record[A],
|
|
917
917
|
doc: Doc,
|
|
918
918
|
modifiers: Seq[Modifier.Reflect],
|
|
919
919
|
defaultValue: Option[A],
|
|
@@ -957,7 +957,7 @@ object DeriveGen extends Deriver[Gen] {
|
|
|
957
957
|
override def deriveVariant[F[_, _], A](
|
|
958
958
|
cases: IndexedSeq[Term[F, A, ?]],
|
|
959
959
|
typeId: TypeId[A],
|
|
960
|
-
binding: Binding
|
|
960
|
+
binding: Binding.Variant[A],
|
|
961
961
|
doc: Doc,
|
|
962
962
|
modifiers: Seq[Modifier.Reflect],
|
|
963
963
|
defaultValue: Option[A],
|
|
@@ -990,7 +990,7 @@ object DeriveGen extends Deriver[Gen] {
|
|
|
990
990
|
override def deriveSequence[F[_, _], C[_], A](
|
|
991
991
|
element: Reflect[F, A],
|
|
992
992
|
typeId: TypeId[C[A]],
|
|
993
|
-
binding: Binding
|
|
993
|
+
binding: Binding.Seq[C, A],
|
|
994
994
|
doc: Doc,
|
|
995
995
|
modifiers: Seq[Modifier.Reflect],
|
|
996
996
|
defaultValue: Option[C[A]],
|
|
@@ -1033,7 +1033,7 @@ object DeriveGen extends Deriver[Gen] {
|
|
|
1033
1033
|
key: Reflect[F, K],
|
|
1034
1034
|
value: Reflect[F, V],
|
|
1035
1035
|
typeId: TypeId[M[K, V]],
|
|
1036
|
-
binding: Binding
|
|
1036
|
+
binding: Binding.Map[M, K, V],
|
|
1037
1037
|
doc: Doc,
|
|
1038
1038
|
modifiers: Seq[Modifier.Reflect],
|
|
1039
1039
|
defaultValue: Option[M[K, V]],
|
|
@@ -1069,7 +1069,7 @@ object DeriveGen extends Deriver[Gen] {
|
|
|
1069
1069
|
* content.
|
|
1070
1070
|
*/
|
|
1071
1071
|
override def deriveDynamic[F[_, _]](
|
|
1072
|
-
binding: Binding
|
|
1072
|
+
binding: Binding.Dynamic,
|
|
1073
1073
|
doc: Doc,
|
|
1074
1074
|
modifiers: Seq[Modifier.Reflect],
|
|
1075
1075
|
defaultValue: Option[DynamicValue],
|
|
@@ -1124,7 +1124,7 @@ object DeriveGen extends Deriver[Gen] {
|
|
|
1124
1124
|
override def deriveWrapper[F[_, _], A, B](
|
|
1125
1125
|
wrapped: Reflect[F, B],
|
|
1126
1126
|
typeId: TypeId[A],
|
|
1127
|
-
binding: Binding
|
|
1127
|
+
binding: Binding.Wrapper[A, B],
|
|
1128
1128
|
doc: Doc,
|
|
1129
1129
|
modifiers: Seq[Modifier.Reflect],
|
|
1130
1130
|
defaultValue: Option[A],
|
|
@@ -1153,7 +1153,7 @@ The `derivePrimitive` method is responsible for deriving a `Gen` instance for pr
|
|
|
1153
1153
|
def derivePrimitive[A](
|
|
1154
1154
|
primitiveType: PrimitiveType[A],
|
|
1155
1155
|
typeId: TypeId[A],
|
|
1156
|
-
binding: Binding
|
|
1156
|
+
binding: Binding.Primitive[A],
|
|
1157
1157
|
doc: Doc,
|
|
1158
1158
|
modifiers: Seq[Modifier.Reflect],
|
|
1159
1159
|
defaultValue: Option[A],
|
|
@@ -1187,7 +1187,7 @@ The `deriveRecord` method is responsible for deriving a `Gen` instance for recor
|
|
|
1187
1187
|
def deriveRecord[F[_, _], A](
|
|
1188
1188
|
fields: IndexedSeq[Term[F, A, ?]],
|
|
1189
1189
|
typeId: TypeId[A],
|
|
1190
|
-
binding: Binding
|
|
1190
|
+
binding: Binding.Record[A],
|
|
1191
1191
|
doc: Doc,
|
|
1192
1192
|
modifiers: Seq[Modifier.Reflect],
|
|
1193
1193
|
defaultValue: Option[A],
|
|
@@ -1233,7 +1233,7 @@ The `deriveVariant` method is responsible for deriving a `Gen` instance for vari
|
|
|
1233
1233
|
def deriveVariant[F[_, _], A](
|
|
1234
1234
|
cases: IndexedSeq[Term[F, A, ?]],
|
|
1235
1235
|
typeId: TypeId[A],
|
|
1236
|
-
binding: Binding
|
|
1236
|
+
binding: Binding.Variant[A],
|
|
1237
1237
|
doc: Doc,
|
|
1238
1238
|
modifiers: Seq[Modifier.Reflect],
|
|
1239
1239
|
defaultValue: Option[A],
|
|
@@ -1268,7 +1268,7 @@ The `deriveSequence` method is responsible for deriving a `Gen` instance for seq
|
|
|
1268
1268
|
def deriveSequence[F[_, _], C[_], A](
|
|
1269
1269
|
element: Reflect[F, A],
|
|
1270
1270
|
typeId: TypeId[C[A]],
|
|
1271
|
-
binding: Binding
|
|
1271
|
+
binding: Binding.Seq[C, A],
|
|
1272
1272
|
doc: Doc,
|
|
1273
1273
|
modifiers: Seq[Modifier.Reflect],
|
|
1274
1274
|
defaultValue: Option[C[A]],
|
|
@@ -1313,7 +1313,7 @@ def deriveMap[F[_, _], M[_, _], K, V](
|
|
|
1313
1313
|
key: Reflect[F, K],
|
|
1314
1314
|
value: Reflect[F, V],
|
|
1315
1315
|
typeId: TypeId[M[K, V]],
|
|
1316
|
-
binding: Binding
|
|
1316
|
+
binding: Binding.Map[M, K, V],
|
|
1317
1317
|
doc: Doc,
|
|
1318
1318
|
modifiers: Seq[Modifier.Reflect],
|
|
1319
1319
|
defaultValue: Option[M[K, V]],
|
|
@@ -1352,7 +1352,7 @@ The `deriveDynamic` method is responsible for deriving a `Gen` instance for dyna
|
|
|
1352
1352
|
|
|
1353
1353
|
```scala
|
|
1354
1354
|
def deriveDynamic[F[_, _]](
|
|
1355
|
-
binding: Binding
|
|
1355
|
+
binding: Binding.Dynamic,
|
|
1356
1356
|
doc: Doc,
|
|
1357
1357
|
modifiers: Seq[Modifier.Reflect],
|
|
1358
1358
|
defaultValue: Option[DynamicValue],
|
|
@@ -1415,7 +1415,7 @@ The `deriveWrapper` method is responsible for deriving a `Gen` instance for wrap
|
|
|
1415
1415
|
def deriveWrapper[F[_, _], A, B](
|
|
1416
1416
|
wrapped: Reflect[F, B],
|
|
1417
1417
|
typeId: TypeId[A],
|
|
1418
|
-
binding: Binding
|
|
1418
|
+
binding: Binding.Wrapper[A, B],
|
|
1419
1419
|
doc: Doc,
|
|
1420
1420
|
modifiers: Seq[Modifier.Reflect],
|
|
1421
1421
|
defaultValue: Option[A],
|
|
@@ -1456,7 +1456,7 @@ Now we can use the derived `Gen[Person]` instance to generate random `Person` va
|
|
|
1456
1456
|
|
|
1457
1457
|
```scala
|
|
1458
1458
|
val random = new Random(42) // Seeded for reproducible output
|
|
1459
|
-
// random: Random = scala.util.Random@
|
|
1459
|
+
// random: Random = scala.util.Random@1d1d8934
|
|
1460
1460
|
|
|
1461
1461
|
Person.gen.generate(random)
|
|
1462
1462
|
// res14: Person = Person(name = "p", age = -1360544799)
|