-
Notifications
You must be signed in to change notification settings - Fork 160
/
schema-schema.ipldsch
818 lines (763 loc) · 34 KB
/
schema-schema.ipldsch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
## -----
## This is the schema describing the schema declarations for IPLD Schemas.
## Yes, it's self-describing! :)
## -----
## Schema is a the root element of an IPLD Schema document.
##
## A complete (if quite short) Schema might look like this:
##
## ```
## {
## "types": {
## "MyFooType": {
## "type": "string"
## }
## }
## }
## ```
##
## The main bulk of a schema is the types map,
## which is TypeName mapped to TypeDefn.
##
## Some additional top level fields are optional,
## such as some maps which may store data about where ADLs
## should be expected to be used within the data described by the schema.
## However, not all schemas use these features.
##
type Schema struct {
types {TypeName:TypeDefn}
advanced optional AdvancedDataLayoutMap
}
## Type names are a simple alias of string.
##
## There are some additional rules that should be applied. Type names:
## - *Must* only contain alphanumeric ASCII characters and underscores
## - *Must* begin with a capital letter
## - *Should* avoid more than one connected underscore character,
## multiple-underscores may be used for codegen
##
## Type names are strings meant for human consumption at a local scope.
## When making a Schema, note that the TypeName is the key of the map:
## a TypeName must be unique within the Schema.
##
type TypeName string
## AdvancedDataLayoutName defines the name of an ADL as a string.
##
## The same constraints and conventions apply as for TypeName.
##
## This identifier is used for keys in the AdvancedDataLayoutMap and also as
## references to ADLs where the "advanced" representation strategy is used for
## the types that support it.
##
type AdvancedDataLayoutName string
## AdvancedDataLayoutMap defines the set of ADLs found within the schema. It
## maps the name (AdvancedDataLayoutName) to the AdvancedDataLayout, which is
## currently an empty map.
##
type AdvancedDataLayoutMap {AdvancedDataLayoutName:AdvancedDataLayout}
## TypeDefn is a union type, where each of the possible members describes one kind of type.
## For example, TypeDefnBool is a member of the TypeDefn union, as is TypeDefnMap.
##
## The TypeDefn union is serialized using "keyed" union representation,
## which means in the serial form, we will always see a map with one key,
## and that key will indicate which member type is coming up as the value.
##
## Some of the kinds of type are so simple the union discriminant is the only
## content at all, e.g. strings:
##
## ```
## {
## "string": {}
## }
## ```
##
## Other types have more content. Consider this example of a map type:
##
## ```
## {
## "map": {
## "keyType": "String",
## "valueType": "Int"
## }
## }
## ```
##
type TypeDefn union {
| TypeDefnBool "bool"
| TypeDefnString "string"
| TypeDefnBytes "bytes"
| TypeDefnInt "int"
| TypeDefnFloat "float"
| TypeDefnMap "map"
| TypeDefnList "list"
| TypeDefnLink "link"
| TypeDefnUnion "union"
| TypeDefnStruct "struct"
| TypeDefnEnum "enum"
| TypeDefnUnit "unit"
| TypeDefnAny "any"
| TypeDefnCopy "copy"
} representation keyed
## TypeKind enumerates all the major kinds of type.
## Notice this enum's members are the same as the set of strings used as
## discriminants in the TypeDefn union.
## (Almost! TypeDefn also contains TypeDefnCopy, which is a slight outlier.
## (TypeDefnCopy can be used to define a type, but isn't a typekind itself.))
##
## This enum is not actually used elsewhere in the schema-schema,
## but does correspond to the discriminant values used in the TypeDefn union.
type TypeKind enum {
| Bool ("bool")
| String ("string")
| Bytes ("bytes")
| Int ("int")
| Float ("float")
| Map ("map")
| List ("list")
| Link ("link")
| Union ("union")
| Struct ("struct")
| Enum ("enum")
| Unit ("unit")
| Any ("any")
}
## RepresentationKind is similar to TypeKind, but includes only those concepts
## which exist at the IPLD *Data Model* level.
##
## In other words, structs, unions, and enumerations are not present:
## those concepts are introduced in the IPLD Schema system, and when serialized,
## all of them must be transformable to one of these representation kinds
## (e.g. a "struct" TypeKind will usually be transformed to a "map"
## RepresentationKind; "enum" TypeKind are typically a "string" RepresentationKind;
## and so on; exactly what RepresentationKind a type defintion will have
## is determined by its representation strategy).
##
## RepresentationKind strings are sometimes used to to indicate part of the
## definition in the details of TypeDefn; for example, they're used describing
## some of the detailed behaviors of a "kinded"-style union type.
type RepresentationKind enum {
| Bool ("bool")
| String ("string")
| Bytes ("bytes")
| Int ("int")
| Float ("float")
| Map ("map")
| List ("list")
| Link ("link")
}
## AnyScalar defines a union of the basic non-complex kinds.
##
## Useful defining usage of IPLD nodes that do compose from other nodes.
##
type AnyScalar union {
| Bool bool
| String string
| Bytes bytes
| Int int
| Float float
} representation kinded
## AdvancedDataLayout defines `advanced` definitions which are stored in the
## top-level "advanced" map (AdvancedDataLayoutMap)
##
## Used as `advanced Foo` rather than `type Foo` to indicate an advanced data
## layout (ADL) with that name which can be used as a representation for type
## definitions whose kind the ADL is able to support.
##
## The AdvancedDataLayoutName is currently the only identifier that can be used
## to make a connection with the algorithm/logic behind this ADL. Future
## iterations may formalize this connection by some other means.
##
type AdvancedDataLayout struct {}
## TypeDefnBool describes a simple boolean type.
## It has no details.
##
type TypeDefnBool struct {}
## TypeDefnString describes a simple string type.
## It has no details.
##
type TypeDefnString struct {}
## TypeDefnBytes describes a simple byte array type.
##
type TypeDefnBytes struct {
representation BytesRepresentation
}
## BytesRepresentation specifies how a TypeDefnBytes is to be serialized. By
## default it will be stored as bytes in the data model but it may be replaced
## with an ADL.
##
type BytesRepresentation union {
| BytesRepresentation_Bytes "bytes"
| AdvancedDataLayoutName "advanced"
} representation keyed
## BytesRepresentation_Bytes is the default representation for TypeDefnBytes and
## will be used implicitly if no representation is specified.
##
type BytesRepresentation_Bytes struct {}
## TypeDefnInt describes a simple integer numeric type.
## It has no details.
##
type TypeDefnInt struct {}
## TypeDefnFloat describes a simple floating point numeric type.
## It has no details.
##
type TypeDefnFloat struct {}
## TypeDefnMap describes a key-value map.
## The keys and values of the map have some specific type of their own.
##
## A constraint on keyType is that the referenced type must have a string
## representation kind. The IPLD Data Model only allows for string keys on maps,
## so this constraint is imposed here.
##
type TypeDefnMap struct {
keyType TypeName
valueType TypeNameOrInlineDefn
valueNullable Bool (implicit false)
representation optional MapRepresentation
}
## MapRepresentation describes how a map type should be mapped onto
## its IPLD Data Model representation.
##
## By default, a map type is also represented as a map in the Data Model,
## but other representation strategies can be configured
##
## Note that the `TypeDefnMap.representation` field is optional --
## the default behavior is demarcated by the lack of any of these values.
##
type MapRepresentation union {
| MapRepresentation_StringPairs "stringpairs"
| MapRepresentation_ListPairs "listpairs"
| AdvancedDataLayoutName "advanced"
} representation keyed
## MapRepresentation_StringPairs describes that a map should be encoded as a
## string of delimited "k/v" entries, e.g. "k1=v1,k2=v2".
## The separating delimiter may be specified with "entryDelim", and the k/v
## delimiter may be specified with "innerDelim". So a "k=v" naive
## comma-separated form would use an "innerDelim" of "=" and an "entryDelim"
## of ",".
##
## This serial representation is limited: the domain of keys must
## exclude the "innerDelim" and values and keys must exclude ",".
## There is no facility for escaping, such as in escaped CSV.
## This also leads to a further restriction that this representation is only
## valid for maps whose keys and values may all be encoded to string form
## without conflicts in delimiter character. It is recommended, therefore,
## that its use be limited to maps containing values with the basic data
## model kinds that exclude multiple values (i.e. no maps, lists, and therefore
## structs or unions).
##
type MapRepresentation_StringPairs struct {
innerDelim String
entryDelim String
}
## MapRepresentation_ListPairs describes that a map should be encoded as a
## list in the IPLD Data Model. This list comprises a sub-list for each entry,
## in the form: [[k1,v1],[k2,v2]].
##
## This representation type is similar to StructRepresentation_Tuple except
## it includes the keys. This is critical for maps since the keys are not
## defined in the schema (hence "tuple" representation isn't available for
## maps).
##
type MapRepresentation_ListPairs struct {}
## TypeDefnList describes a list.
## The values of the list have some specific type of their own.
##
type TypeDefnList struct {
valueType TypeNameOrInlineDefn
valueNullable Bool (implicit false)
representation optional ListRepresentation
}
## ListRepresentation describes how a map type should be mapped onto
## its IPLD Data Model representation. By default a list is a list in the
## data model but it may be replaced with an ADL.
##
## Note that the `TypeDefnList.representation` field is optional --
## the default behavior is demarcated by the lack of any of these values.
##
type ListRepresentation union {
| AdvancedDataLayoutName "advanced"
} representation keyed
## TypeDefnLink describes an IPLD link, which is a content-addressable pointer to more data.
## (Links in IPLD are implemented by CIDs: they're a hash that identifies another another block of data,
## plus a codec hint for how to parse it into IPLD Data Model).
##
## A typed link can optionally state an "expectedType".
## This provides a mechanism for suggesting what we should expect find
## if we were to follow the link.
## (Note that this cannot be strictly enforced by a node or block-level schema validation!
## But may be enforced elsewhere in an application using a schema, and
## is generally enforced as soon as possible when traversing typed links.)
##
## In the Schema DSL, links are specified with the `&FooBar` syntax --
## The ampersand character denotes a link, and the rest of the declaration
## is the name of the expected type for the linked content.
##
## If you want the equivalent of untyped links, in the DSL, you can say `&Any`.
## This is also available in the Prelude, and that type is simply name "Link"
## (in other words, the Prelude contains `type Link &Any`).
##
type TypeDefnLink struct {
expectedType TypeName (implicit "Any")
}
## TypeDefnUnion describes a union (sometimes called a "sum type", or
## more verbosely, a "discriminated union", or in yet other literature, a "variant" type).
## A union is a type that can have a value of several different types, but
## unlike maps or structs, in a union, only one of those values may be present
## at a time.
##
## Unions can be represented in several significantly different ways:
## see the documentation of the UnionRepresentation type for details.
## Also note that there is no default representation for union types --
## you must _always_ explicitly specify a representation strategy when defining unions!
##
type TypeDefnUnion struct {
members [UnionMember]
representation UnionRepresentation
}
## UnionMember is a type for identifying the members of a union.
## Most commonly, this is simply a TypeName string;
## however, it can also be a UnionMemberInlineDefn,
## which is used to allow inline link definitions within a kinded union as a shorthand
## (rather than requiring all links be declared as a named type before being usable within a union).
type UnionMember union {
| TypeName string
| UnionMemberInlineDefn map
} representation kinded
## UnionMemberInlineDefn is a very similar purpose to InlineDefn,
## but found specifically within UnionMember.
## It only allows describing a link type (and not maps nor lists, as InlineDefn does),
## which is a constraint applied to union membership largely to make sure
## if there are errors in processing unions, we can make legible messages about it!
type UnionMemberInlineDefn union {
| TypeDefnLink "link"
} representation keyed
## UnionRepresentation is a union of all the distinct ways a TypeDefnUnion's values
## can be mapped onto a serialized format for the IPLD Data Model.
##
## There are six strategies that can be used to encode a union:
## "keyed", "envelope", "inline", "stringprefix", "bytesprefix", and "kinded".
## The "keyed", "envelope", and "inline" strategies are all ways to produce
## representations in a map format, using map keys as type discriminators
## (some literature may describe this as a "tagged" style of union).
## The "stringprefix" strategy, only available for unions in which all member
## types themselves represent as strings in the data model, uses a prefix
## string as the type discrimination hint (and like the map-oriented strategies,
## may also be seen as a form of "tagged" style unions).
## The "bytesprefix" strategy, only available for unions in which all member
## types themselves represent as bytes in the data model, similar to
## "stringprefix" but with bytes.
## The "kinded" strategy can describe a union in which member types have
## several different representation kinds, and uses the representation kind
## itself as the type discrimination hint to do so.
##
## Note: Unions can be used to produce a "nominative" style of type declarations
## -- yes, even given that IPLD Schema systems are natively "structural" typing!
##
type UnionRepresentation union {
| UnionRepresentation_Kinded "kinded"
| UnionRepresentation_Keyed "keyed"
| UnionRepresentation_Envelope "envelope"
| UnionRepresentation_Inline "inline"
| UnionRepresentation_StringPrefix "stringprefix"
| UnionRepresentation_BytesPrefix "bytesprefix"
} representation keyed
## "Kinded" union representations describe a bidirectional mapping between
## a RepresentationKind and the type which should be the
## union member decoded when one sees this RepresentationKind.
##
## The referenced type must of course produce the RepresentationKind it's
## matched with!
type UnionRepresentation_Kinded {RepresentationKind:UnionMember}
## "Keyed" union representations will encode as a map, where the map has
## exactly one entry, the key string of which will be used to look up the name
## of the Type; and the value should be the content, and be of that Type.
##
## Note: when writing a new protocol, it may be wise to prefer keyed unions
## over the other styles wherever possible; keyed unions tend to have good
## performance characteristics, as they have most "mechanical sympathy" with
## parsing and deserialization implementation order.
type UnionRepresentation_Keyed {String:UnionMember}
## "Envelope" union representations will encode as a map, where the map has
## exactly two entries: the two keys should be of the exact strings specified
## for this envelope representation. The value for the discriminant key
## should be one of the strings in the discriminant table. The value for
## the content key should be the content, and be of the Type matching the
## lookup in the discriminant table.
type UnionRepresentation_Envelope struct {
discriminantKey String
contentKey String
discriminantTable {String:UnionMember}
}
## "Inline" union representations require that all of their members encode
## as a map, and encode their type info into the same map as the member data.
## Thus, the map for an inline union may have any number of entries: it is
## however many fields the member value has, plus one (for the discriminant).
##
## All members of an inline union must be struct types and must encode to
## the map RepresentationKind. Other types which encode to map (such as map
## types themselves!) cannot be used: the potential for content values with
## with keys overlapping with the discriminantKey would result in undefined
## behavior! Similarly, the member struct types may not have fields which
## have names that collide with the discriminantKey.
##
## When designing a new protocol, use inline unions sparingly; despite
## appearing simple, they have the most edge cases of any kind of union
## representation, and their implementation is generally the most complex and
## is difficult to optimize deserialization to support.
type UnionRepresentation_Inline struct {
discriminantKey String
discriminantTable {String:TypeName}
}
## UnionRepresentation_StringPrefix describes a union representation for unions
## whose member types are all strings. Strings used for this representation
## strategy use the first characters as the discriminator, and the subsequent
## characters as the discriminated type's value.
##
## There is currently no limitation on prefix length, other than needing to be
## at least one character. Nor is there a requirement that they all be of the
## same length, although they must all represent unique prefixes.
##
## stringprefix is an invalid representation for any union that contains a type
## that does not have a string representation.
##
type UnionRepresentation_StringPrefix struct {
prefixes {String:TypeName}
}
## UnionRepresentation_BytesPrefix describes a union representation for unions
## whose member types are all bytes. It is encoded to a byte array whose
## first bytes are the discriminator and subsequent bytes form the discriminated
## type.
##
## Discriminators are represented as hexadecimal strings. There is currently
## no limitation on their length, other than needing to be at least one byte.
## Nor is there a requirement that they all be of the same length, although
## they must all represent unique prefixes.
##
## Only valid, upper-case, hexadecimal strings representing at least one byte
## are allowed.
##
## bytesprefix is an invalid representation for any union that contains a type
## that does not have a bytes representation.
##
type UnionRepresentation_BytesPrefix struct {
prefixes {HexString:TypeName}
}
## HexString is an alias for string, to denote and clarify that it's not a regular freetext string.
## It's seen used in the UnionRepresentation_BytesPrefix type.
##
## (We use hexadecimal strings in the schema-schema in some places,
## even though we could've used bytes types, because the schema DSL also uses hex strings,
## and consistency (and, the ability to keep the schema-schema in plain JSON!) is valuable.)
type HexString string
## TypeDefnStruct describes a type which has a group of fields of varying Type.
## Each field has a name, which is used to access its value, similarly to
## accessing values in a map.
##
## The most typical representation of a struct is as a map, in which case field
## names also serve as the the map keys (though this is a default, and details
## of this representation may be configured; and other representation strategies
## also exist).
##
type TypeDefnStruct struct {
fields {FieldName:StructField}
representation StructRepresentation
}
## FieldName is an alias of string.
##
## There are some additional rules that should be applied:
## - Field names should by convention begin with a lower-case letter;
## - Field names must be all printable characters (no whitespace);
## - Field names must not contain punctuation other than underscores
## (dashes, dots, etc.).
##
## Field names are strings meant for human consumption at a local scope.
## When making a Schema, note that the FieldName is the key of the map:
## a FieldName must be unique within the Schema.
##
type FieldName string
## StructField describes the properties of each field declared by a TypeDefnStruct.
##
## StructField contains properties similar to TypeDefnMap -- namely, it describes
## a content type (as a TypeNameOrInlineDefn -- it supports inline definitions) -- and
## has a boolean property for whether or not the value is permitted to be null.
##
## In addition, StructField also has a property called "optional".
## An "optional" field is one which is permitted to be absent entirely.
## This is distinct from "nullable": a field can be optional=false and
## nullable=true, in which case it's an error if the key is missing entirely,
## but null is of course valid. Conversely, if a field is optional=true and
## nullable=false, it's an error if the field is present and assigned null, but
## fine for a map to be missing a key of the field's name entirely and still be
## recognized as this struct.
## (The specific behavior of optionals may vary per StructRepresentation.)
##
## Note that the 'optional' and 'nullable' properties are not themselves
## optional... however, in the IPLD serial representation of schemas, you'll
## often see them absent from the map encoding a StructField. This is because
## these fields are specified to be implicitly false.
## Implicits in a map representation of a struct mean that those entries may
## be missing from the map encoding... but unlike with "optional" fields, there
## is no "undefined" value; absence is simply interpreted as the value specified
## as the implicit.
## (With implicit fields, an explicitly encoded implicit value is actually an
## error instead!) "Optional" fields give rise to N+1 cardinality logic,
## just like "nullable" fields; "implicit" fields *do not*.
##
type StructField struct {
type TypeNameOrInlineDefn
optional Bool (implicit false)
nullable Bool (implicit false)
}
## TypeNameOrInlineDefn is a union of either TypeName or an InlineDefn.
## It's used for the value type in the recursive types (maps, lists, and the fields of structs),
## which allows the use of InlineDefn in any of those positions.
##
## TypeNameOrInlineDefn is simply a TypeName if the kind of data is a string;
## this is simple and common case.
## If the data is a map, then it requires further recognition as an InlineDefn.
##
## Note that TypeNameOrInlineDefn isn't used to describe *keys* in the recursive types that
## have them (maps, structs) -- recursive types in keys would not lend itself
## well to serialization!
## TypeNameOrInlineDefn also isn't used to describe members in Unions -- this is a choice
## aimed to limit syntactical complexity (both at type definition authoring
## time, as well as for the sake of error messaging during typechecking).
##
type TypeNameOrInlineDefn union {
| TypeName string
| InlineDefn map
} representation kinded
## InlineDefn represents a declaration of an anonymous type of one of the simple
## recursive kinds (e.g. map or list) which is found "inline" in another type's definition.
## InlineDefn also allows description of anonymous but typed links for similar reasons.
## InlineDefn is the more complex option of the TypeNameOrInlineDefn union.
##
## Note that the representation of this union -- the use of a keyed representation,
## as well as the keywords for its members -- align exactly with those
## in the TypeNameOrInlineDefn union. Technically, this isn't a necessary property (in that
## nothing would break if that sameness was violated) but it's awfully nice for
## sanity; what we're saying here is that the representation of the types in an
## InlineDefn should look *exactly the same* as the top-level type declarations...
## it's just that within an InlineDefn, we're restricted to a subset of the members.
##
type InlineDefn union {
| TypeDefnMap "map"
| TypeDefnList "list"
| TypeDefnLink "link"
} representation keyed
## StructRepresentation describes how a struct type should be mapped onto
## its IPLD Data Model representation.
##
## The default representation strategy for struct types is a map,
## with the struct's field names as keys.
## However, that can be configured.
## For example, the map representation can be configured with
## directives to use different keys in the representation form;
## or, configured to consider some fields as having values which should be seen as the implicit value for that field,
## meaning the entire field shouldn't get an entry in the representation map if that value is found in that field.
## Or, wholly different representation strategies can be used
## (such as the tuple strategy, which results in a data model list kind,
## or stringjoin, which results a data model string kind!).
##
type StructRepresentation union {
| StructRepresentation_Map "map"
| StructRepresentation_Tuple "tuple"
| StructRepresentation_StringPairs "stringpairs"
| StructRepresentation_StringJoin "stringjoin"
| StructRepresentation_ListPairs "listpairs"
} representation keyed
## StructRepresentation_Map describes a way to map a struct type onto a map
## representation. Field serialization options may optionally be configured to
## enable mapping serialized keys using the 'rename' option, or implicit values
## specified where the field is omitted from the serialized form using the
## 'implicit' option.
##
## See StructRepresentation_Map_FieldDetails for details on the 'rename' and
## 'implicit' options.
##
type StructRepresentation_Map struct {
fields optional {FieldName:StructRepresentation_Map_FieldDetails}
}
## StructRepresentation_Map_FieldDetails describes additional properties of a
## struct field when represented as a map. For example, fields may be renamed,
## or implicit values associated.
##
## If an implicit value is defined, then during marshalling, if the actual value
## is the implicit value, that field will be omitted from the map; and during
## unmarshalling, correspondingly, the absence of that field will be interpreted
## as being the implicit value.
##
## Note that fields with implicits are distinct from fields which are optional!
## The cardinality of membership of an optional field is is incremented:
## e.g., the cardinality of "fieldname Bool" is 2; "fieldname optional Bool" is
## membership cardinality *3*, because it may also be undefined.
## By contrast, the cardinality of membership of a field with an implicit value
## remains unchanged; there is serial state which can map to an undefined value.
##
## Note that 'rename' supports exactly one string, and not a list: this is
## intentional. The rename feature is meant to allow serial representations
## to use a different key string than the schema type definition field name;
## it is not intended to be used for migration purposes.
##
type StructRepresentation_Map_FieldDetails struct {
rename optional String
implicit optional AnyScalar
}
## StructRepresentation_Tuple describes a way to map a struct type into a list
## representation.
##
## Tuple representations are less flexible than map representations:
## field order can be specified in order to override the order defined
## in the type, but optionals and implicits are not (currently) supported.
## A `fieldOrder` list must include quoted strings (FieldName is a string
## type) which are coerced to the names of the struct fields. e.g.:
## fieldOrder ["Foo", "Bar", "Baz"]
##
type StructRepresentation_Tuple struct {
fieldOrder optional [FieldName]
}
## StructRepresentation_StringPairs describes that a struct should be encoded
## as a string of delimited "k/v" entries, e.g. "k1=v1,k2=v2".
## The separating delimiter may be specified with "entryDelim", and the k/v
## delimiter may be specified with "innerDelim". So a "k=v" naive
## comma-separated form would use an "innerDelim" of "=" and an "entryDelim"
## of ",".
##
## Serialization a struct with stringpairs works the same way as serializing
## a map with stringpairs and the same character limitations exist. See
## MapRepresentation_StringPairs for more details on these limitations.
##
type StructRepresentation_StringPairs struct {
innerDelim String
entryDelim String
}
## StructRepresentation_StringJoin describes a way to encode a struct to
## a string in the IPLD Data Model. Similar to tuple representation, the
## keys are dropped as they may be inferred from the struct definition.
## values are concatenated, in order, and separated by a "join" delimiter.
## For example, specifying ":" as the "join": "v1,v2,v3".
##
## stringjoin is necessarily restrictive and therefore only valid for structs
## whose values may all be encoded to string form without conflicts in "join"
## character. It is recommended, therefore, that its use be limited to structs
## containing values with the basic data model kinds that exclude multiple
## values (i.e. no maps, lists, and therefore structs or unions).
##
type StructRepresentation_StringJoin struct {
join String
fieldOrder optional [FieldName]
}
## StructRepresentation_ListPairs describes that a struct, should be encoded as
## a list in the IPLD Data Model. This list comprises a sub-list for each
## entry, in the form: [[k1,v1],[k2,v2]].
##
## This representation type encodes in the same way as
## MapStructRepresentation_Tuple. It is also similar to
## StructRepresentation_Tuple except it includes the keys in nested lists.
## A tuple representation for a struct will encode more compact than listpairs.
##
type StructRepresentation_ListPairs struct {}
## TypeDefnEnum describes a type which has a known, pre-defined set of possible values.
## Each of the member values is named by a string (of EnumMember type).
##
## Enums can have either string or int-based representations.
## Integer and string values (for int and string representations respectively)
## are provided in parens in the DSL. Where the string used in serialization is
## the same as the EnumMember, it may be omitted. For int representation enums,
## all int values are required.
##
type TypeDefnEnum struct {
members [EnumMember]
representation EnumRepresentation
}
## EnumMember is a string that that names a member of an Enum type.
##
## The range of valid values for an EnumMember are the same as for TypeName
## but without the convention of an uppercase first character.
## Capitalization is left up to the discretion of the schema writer.
##
type EnumMember string
## EnumRepresentation describes how an enum type should be mapped onto
## its IPLD Data Model representation. By default an enum is represented as a
## string kind but it may also be represented as an int kind.
##
type EnumRepresentation union {
| EnumRepresentation_String "string"
| EnumRepresentation_Int "int"
} representation keyed
## EnumRepresentation_String describes the way an enum is represented as a
## string in the data model. By default, the strings used as EnumMember will be
## used at the serialization. A custom string may be provided (with `Foo ("x")`
## in the DSL) which will be stored here in the representation block. Missing
## entries in this map will use the default.
##
type EnumRepresentation_String {EnumMember:String}
## EnumRepresentation_Int describes the way an enum is represented as an int
## in the data model. A mapping of names to ints is required to perform the
## conversion from int to enum value. In the DSL, int values _must_ be provided
## for each EnumMember (with `Foo ("100")`, those are stored here.
##
type EnumRepresentation_Int {EnumMember:Int}
## TypeDefnUnit describes a type which contains no data at all (other than that fact of its existence).
## (If this seems strange, consider that the cardinality of a bool type is 2;
## the cardinality of a unit type is simply 1.)
##
type TypeDefnUnit struct {
representation UnitRepresentation
}
## UnitRepresentation is an enum for describing how a TypeDefnUnit should be represented in the data model.
##
## Unit types are commonly seen represented in several ways.
## A null token is a common one.
## A true token is sometimes seen (especially, when people encode "sets" in json:
## often this will be seen as a map where the values are keys and the map values are 'true').
## Also, an empty map can be a useful unit value;
## an empty map accurately communicates a lack of data.
## (The emptymap strategy can be a particularly interesting choice if you want to
## have a schema that is evolvable in the future to start using a struct or map
## in the same place as the unit type currently stands, while having older documents
## continue to be parsable by the evolved schema.)
##
## Unlike many of the other representation information types seen in the schema-schema,
## this one is just an enum, rather than being a union.
## That's because there's no possibility of every needing to annotate more customization
## onto values in the unit type... because there are no possible values in the unit type.
##
## Note that there is no discernible logical difference between
## `type Foo struct {}` and `type Foo unit representation emptymap`;
## only that the latter can be said to be a more explicit description of intent.
## Both will result in identical representations, and both have identical cardinality (which is 1).
##
type UnitRepresentation enum {
| Null ("null")
| True ("true")
| False ("false")
| Emptymap ("emptymap")
}
## TypeDefnAny describes a type which can contain data of any kind.
## It's essentially an escape valve; it says "we don't really know what lies beyond here".
## The type-level data model kind of an "any" type can be anything;
## it depends on what the inhabitant value is.
## The representation-level kind can similarly be anything;
## it will match whatever the type-level kind is.
##
## It is not possible to regain useful types on deeper values after using an 'any' type;
## from then on, the rest of the data is locked in on having exactly that 'any' type,
## and having no further ability to have separate type-level and representation-level behaviors.
##
## 'any' was introduced as a typekind after discovering it is not possible
## to emulate its behavior by constructing a union; see
## https://github.com/ipld/specs/issues/318 for some discussion of this.
type TypeDefnAny struct {}
## TypeDefnCopy describes a special "copy" unit that indicates that a type name
## should copy the type descriptor of another type. TypeDefnCopy does not redirect a
## name to another type. Instead, it copies the entire type definition and
## assigns it to another type.
##
## The DSL defines a TypeDefnCopy as `type NewThing = CopiedThing`, where
## "CopiedThing" refers to a `type` defined elsewhere in a schema and is not
## one of TypeKind or an inline type descriptor (`{}`, `[]`, `&`).
##
type TypeDefnCopy struct {
fromType TypeName
}