1#![allow(dead_code)]
2
3use std::fmt;
4
5use proptest::{collection::btree_map, prelude::*};
6use serde::{Deserialize, Serialize};
7
8#[cfg(feature = "fast-test")]
9const DEFAULT_SIZE_RANGE: std::ops::RangeInclusive<usize> = 0..=10;
10#[cfg(not(feature = "fast-test"))]
11const DEFAULT_SIZE_RANGE: std::ops::RangeInclusive<usize> = 0..=100;
12
13type Int = i64;
14type Float = f64;
15type Map<K, V> = std::collections::BTreeMap<K, V>;
16
17#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
22struct Null;
23
24#[derive(
25 Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, test_strategy::Arbitrary,
26)]
27pub(crate) struct TypeName(#[strategy("[A-Z][a-z0-9_]*")] String);
28
29#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
30struct SchemaMap(
31 #[strategy(btree_map(any::<TypeName>(), any::<Type>(), DEFAULT_SIZE_RANGE))]
33 Map<TypeName, Type>,
34);
35
36#[derive(
37 Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, test_strategy::Arbitrary,
38)]
39pub(crate) struct AdvancedDataLayoutName(String);
40
41#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, test_strategy::Arbitrary)]
42pub(crate) struct AdvancedDataLayoutMap(
43 #[strategy(Just(Map::new()))] Map<AdvancedDataLayoutName, AdvancedDataLayout>,
44);
45
46#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
47#[serde(rename_all = "camelCase")]
48#[derive(test_strategy::Arbitrary)]
49pub(crate) struct Schema {
50 types: SchemaMap,
51 #[serde(default, skip_serializing_if = "is_default")]
52 advanced: AdvancedDataLayoutMap,
53}
54
55#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
56#[serde(tag = "kind", rename_all = "lowercase")]
57#[derive(test_strategy::Arbitrary)]
58pub(crate) enum Type {
60 Bool(TypeBool),
61 String(TypeString),
62 Bytes(TypeBytes),
63 Int(TypeInt),
64 Float(TypeFloat),
65 Map(TypeMap),
66 List(TypeList),
67 Link(TypeLink),
68 Union(TypeUnion),
69 #[weight(0)]
70 Struct(TypeStruct),
71 #[weight(0)]
72 Enum(TypeEnum),
73 Copy(TypeCopy),
74}
75
76#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
96#[serde(rename_all = "lowercase")]
97#[derive(test_strategy::Arbitrary)]
98pub(crate) enum RepresentationKind {
99 Bool,
100 String,
101 Bytes,
102 Int,
103 Float,
104 Map,
105 List,
106 Link,
107}
108
109#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
110#[serde(untagged)]
111#[derive(test_strategy::Arbitrary)]
112pub(crate) enum AnyScalar {
113 Bool(bool),
114 String(String),
115 Bytes(Vec<u8>),
116 Int(Int),
117 Float(Float),
118}
119
120#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
121struct AdvancedDataLayout;
122
123#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
124pub(crate) struct TypeBool;
125
126#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
127pub(crate) struct TypeString;
128
129#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
130pub(crate) struct TypeBytes {
131 representation: BytesRepresentation,
132}
133
134#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
135#[serde(rename_all = "lowercase")]
136#[derive(test_strategy::Arbitrary)]
137enum BytesRepresentation {
139 Bytes(bytes_representation::Bytes),
140 #[weight(0)]
141 Advanced(AdvancedDataLayoutName),
142}
143
144mod bytes_representation {
145 use serde::{Deserialize, Serialize};
146
147 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
148 pub(crate) struct Bytes;
149}
150
151impl Default for BytesRepresentation {
152 fn default() -> Self {
153 Self::Bytes(bytes_representation::Bytes)
154 }
155}
156
157#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
158pub(crate) struct TypeInt;
159
160#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
161pub(crate) struct TypeFloat;
162
163fn is_default<D: Default + PartialEq>(d: &D) -> bool {
164 *d == D::default()
165}
166
167#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
168#[serde(rename_all = "camelCase")]
169#[derive(test_strategy::Arbitrary)]
170pub(crate) struct TypeMap {
171 key_type: TypeName,
172
173 value_type: TypeTerm,
174
175 #[serde(default, skip_serializing_if = "is_default")]
176 value_nullable: bool,
177
178 #[serde(default, skip_serializing_if = "is_default")]
179 representation: MapRepresentation,
180}
181
182#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
183#[serde(rename_all = "lowercase")]
184#[derive(test_strategy::Arbitrary)]
185enum MapRepresentation {
187 Map(map_representation::Map),
188 StringPairs(map_representation::StringPairs),
189 ListPairs(map_representation::ListPairs),
190 #[weight(0)]
191 Advanced(AdvancedDataLayoutName),
192}
193
194mod map_representation {
195 use serde::{Deserialize, Serialize};
196
197 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
198 pub(crate) struct Map;
199
200 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
201 #[serde(rename_all = "camelCase")]
202 #[derive(test_strategy::Arbitrary)]
203 pub(crate) struct StringPairs {
204 #[strategy("[^\"]+")]
205 pub(crate) inner_delim: String,
206
207 #[strategy("[^\"]+")]
208 pub(crate) entry_delim: String,
209 }
210
211 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
212 pub(crate) struct ListPairs;
213}
214
215impl Default for MapRepresentation {
216 fn default() -> Self {
217 Self::Map(map_representation::Map)
218 }
219}
220
221#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
222#[serde(rename_all = "camelCase")]
223#[derive(test_strategy::Arbitrary)]
224pub(crate) struct TypeList {
225 value_type: TypeTerm,
226
227 #[serde(default, skip_serializing_if = "is_default")]
228 value_nullable: bool,
229
230 #[serde(default, skip_serializing_if = "is_default")]
231 representation: ListRepresentation,
232}
233
234#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
235enum ListRepresentation {
236 List(list_representation::List),
237 #[weight(0)]
238 Advanced(AdvancedDataLayoutName),
239}
240
241mod list_representation {
242 use serde::{Deserialize, Serialize};
243
244 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
245 pub(crate) struct List;
246}
247
248impl Default for ListRepresentation {
249 fn default() -> Self {
250 Self::List(list_representation::List)
251 }
252}
253
254#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
255#[serde(rename_all = "camelCase")]
256#[derive(test_strategy::Arbitrary)]
257pub(crate) struct TypeLink {
258 #[strategy("[A-Z][a-z0-9_]*")]
259 expected_type: String,
260}
261
262impl Default for TypeLink {
263 fn default() -> Self {
264 Self {
265 expected_type: "Any".to_string(),
266 }
267 }
268}
269
270#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
271#[serde(rename_all = "camelCase")]
272#[derive(test_strategy::Arbitrary)]
273pub(crate) struct TypeUnion {
274 representation: UnionRepresentation,
275}
276
277#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
278#[serde(rename_all = "lowercase")]
279#[derive(test_strategy::Arbitrary)]
280enum UnionRepresentation {
281 Kinded(union_representation::Kinded),
282 Keyed(union_representation::Keyed),
283 Envelope(union_representation::Envelope),
284 Inline(union_representation::Inline),
285 BytePrefix(union_representation::BytePrefix),
286}
287
288mod union_representation {
289 use super::{Map, RepresentationKind, TypeName, DEFAULT_SIZE_RANGE};
290 use proptest::{collection::btree_map, prelude::any};
291 use serde::{Deserialize, Serialize};
292
293 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
294 pub(crate) struct Kinded(pub(crate) Map<RepresentationKind, TypeName>);
295
296 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
297 pub(crate) struct Keyed(
298 #[strategy(btree_map("[^\"]*", any::<TypeName>(), DEFAULT_SIZE_RANGE))]
299 pub(crate) Map<String, TypeName>,
300 );
301
302 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
303 #[serde(rename_all = "camelCase")]
304 #[derive(test_strategy::Arbitrary)]
305 pub(crate) struct Envelope {
306 #[strategy("[^\"]*")]
307 pub(crate) discriminant_key: String,
308
309 #[strategy("[^\"]*")]
310 pub(crate) content_key: String,
311
312 #[strategy(btree_map("[^\"]*", any::<TypeName>(), DEFAULT_SIZE_RANGE))]
313 pub(crate) discriminant_table: Map<String, TypeName>,
314 }
315
316 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
317 #[serde(rename_all = "camelCase")]
318 #[derive(test_strategy::Arbitrary)]
319 pub(crate) struct Inline {
320 #[strategy("[^\"]*")]
321 pub(crate) discriminant_key: String,
322
323 #[strategy(btree_map("[^\"]*", any::<TypeName>(), DEFAULT_SIZE_RANGE))]
324 pub(crate) discriminant_table: Map<String, TypeName>,
325 }
326
327 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
328 #[serde(rename_all = "camelCase")]
329 #[derive(test_strategy::Arbitrary)]
330 pub(crate) struct BytePrefix {
331 #[strategy(btree_map(any::<TypeName>(), any::<u8>(), DEFAULT_SIZE_RANGE))]
332 pub(crate) discriminant_table: Map<TypeName, u8>,
333 }
334}
335
336#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
337#[serde(rename_all = "camelCase")]
338#[derive(test_strategy::Arbitrary)]
339pub(crate) struct TypeStruct {
340 #[strategy(btree_map(any::<FieldName>(), any::<StructField>(), DEFAULT_SIZE_RANGE))]
342 fields: Map<FieldName, StructField>,
343 representation: StructRepresentation,
344}
345
346#[derive(
347 Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, test_strategy::Arbitrary,
348)]
349pub(crate) struct FieldName(#[strategy("[a-zA-Z0-9_]+")] String);
350
351#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
352#[serde(rename_all = "camelCase")]
353#[derive(test_strategy::Arbitrary)]
354struct StructField {
355 r#type: TypeTerm,
356
357 #[serde(default, skip_serializing_if = "is_default")]
358 optional: bool,
359
360 #[serde(default, skip_serializing_if = "is_default")]
361 nullable: bool,
362}
363
364#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
365#[serde(untagged)]
366#[derive(test_strategy::Arbitrary)]
367pub(crate) enum TypeTerm {
369 TypeName(TypeName),
370 #[weight(0)]
371 InlineDefn(Box<InlineDefn>),
372}
373
374#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
375#[serde(tag = "kind", rename_all = "lowercase")]
376#[derive(test_strategy::Arbitrary)]
377pub(crate) enum InlineDefn {
378 Map(TypeMap),
379 List(TypeList),
380}
381
382#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
383#[serde(rename_all = "lowercase")]
384#[derive(test_strategy::Arbitrary)]
385enum StructRepresentation {
388 Map(struct_representation::Map),
389 Tuple(struct_representation::Tuple),
390 StringPairs(struct_representation::StringPairs),
391
392 #[weight(0)]
394 StringJoin(struct_representation::StringJoin),
395 ListPairs(struct_representation::ListPairs),
396}
397
398mod struct_representation {
399 use super::{AnyScalar, FieldName};
400 use serde::{Deserialize, Serialize};
401
402 use super::DEFAULT_SIZE_RANGE;
403 use proptest::{collection::btree_map, prelude::any};
404
405 #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
406 #[serde(rename_all = "camelCase")]
407 #[derive(test_strategy::Arbitrary)]
408 pub(crate) struct Map {
409 #[serde(default)]
410 #[strategy(btree_map(any::<FieldName>(), any::<MapFieldDetails>(), DEFAULT_SIZE_RANGE))]
411 pub(crate) fields: super::Map<FieldName, MapFieldDetails>,
412 }
413
414 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
415 #[serde(rename_all = "camelCase")]
416 #[derive(test_strategy::Arbitrary)]
417 pub(crate) struct MapFieldDetails {
418 pub(crate) rename: Option<String>,
419 pub(crate) implicit: Option<AnyScalar>,
420 }
421
422 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
423 #[serde(rename_all = "camelCase")]
424 #[derive(test_strategy::Arbitrary)]
425 pub(crate) struct Tuple {
426 pub(crate) field_order: Option<Vec<FieldName>>,
428 }
429
430 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
431 #[serde(rename_all = "camelCase")]
432 #[derive(test_strategy::Arbitrary)]
433 pub(crate) struct StringPairs {
434 #[strategy("[^\"]+")]
435 pub(crate) inner_delim: String,
436
437 #[strategy("[^\"]+")]
438 pub(crate) entry_delim: String,
439 }
440
441 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
442 #[serde(rename_all = "camelCase")]
443 #[derive(test_strategy::Arbitrary)]
444 pub(crate) struct StringJoin {
445 #[strategy("[^\"]+")]
446 pub(crate) join: String,
447
448 pub(crate) field_order: Vec<FieldName>,
449 }
450
451 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
452 pub(crate) struct ListPairs;
453}
454
455impl Default for StructRepresentation {
456 fn default() -> Self {
457 Self::Map(struct_representation::Map::default())
458 }
459}
460
461#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
462pub(crate) struct TypeEnum {
463 #[strategy(btree_map(any::<EnumValue>(), any::<Null>(), DEFAULT_SIZE_RANGE))]
464 members: Map<EnumValue, Null>,
465 representation: EnumRepresentation,
466}
467
468#[derive(
469 Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, test_strategy::Arbitrary,
470)]
471pub(crate) struct EnumValue(#[strategy("[a-z0-9_]+")] String);
472
473#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
474#[serde(rename_all = "lowercase")]
475#[derive(test_strategy::Arbitrary)]
476enum EnumRepresentation {
477 String(enum_representation::String),
478 #[weight(0)]
479 Int(enum_representation::Int),
480}
481
482mod enum_representation {
483 use super::{EnumValue, Map, DEFAULT_SIZE_RANGE};
484 use proptest::{collection::btree_map, prelude::*};
485 use serde::{Deserialize, Serialize};
486
487 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, test_strategy::Arbitrary)]
488 pub(crate) struct String(
489 #[strategy(btree_map(any::<EnumValue>(), "[^\"]*", DEFAULT_SIZE_RANGE))]
490 Map<EnumValue, std::string::String>,
491 );
492
493 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, test_strategy::Arbitrary)]
494 pub(crate) struct Int(
495 #[strategy(btree_map(any::<EnumValue>(), any::<Int>(), DEFAULT_SIZE_RANGE))]
496 Map<EnumValue, Int>,
497 );
498}
499
500impl Default for EnumRepresentation {
501 fn default() -> Self {
502 Self::String(enum_representation::String::default())
503 }
504}
505
506#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, test_strategy::Arbitrary)]
507pub(crate) struct TypeCopy {
508 from_type: TypeName,
509}
510
511const L_BOOL: &str = "bool";
512const L_STRING: &str = "string";
513const L_BYTES: &str = "bytes";
514const L_INT: &str = "int";
515const L_FLOAT: &str = "float";
516const L_MAP: &str = "map";
517const L_LIST: &str = "list";
518const L_LINK: &str = "link";
519const L_UNION: &str = "union";
520const L_STRUCT: &str = "struct";
521const L_ENUM: &str = "enum";
522
523const L_TYPE: &str = "type";
524const L_OPTIONAL: &str = "optional";
525const L_NULLABLE: &str = "nullable";
526const L_LINK_REF: &str = "&";
527const L_COPY: &str = "=";
528const L_REPRESENTATION: &str = "representation";
529const L_KINDED: &str = "kinded";
530const L_KEYED: &str = "keyed";
531const L_ENVELOPE: &str = "envelope";
532const L_INLINE: &str = "inline";
533const L_TUPLE: &str = "tuple";
534const L_STRINGPAIRS: &str = "stringpairs";
535const L_STRINGJOIN: &str = "stringjoin";
536const L_LISTPAIRS: &str = "listpairs";
537const L_DISCRIMINANT_KEY: &str = "discriminantKey";
538const L_CONTENT_KEY: &str = "contentKey";
539const L_IMPLICIT: &str = "implicit";
540const L_BYTEPREFIX: &str = "byteprefix";
541
542impl fmt::Display for TypeName {
543 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
544 write!(f, "{}", self.0)
545 }
546}
547
548impl fmt::Display for SchemaMap {
549 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
550 for (name, ty) in &self.0 {
551 write!(f, "{} {} {}\n\n", L_TYPE, name, ty)?;
552 }
553 Ok(())
554 }
555}
556
557impl fmt::Display for Schema {
558 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
559 write!(f, "{}", &self.types)
561 }
562}
563
564impl fmt::Display for Type {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
566 match self {
567 Self::Bool(x) => write!(f, "{}", x),
568 Self::String(x) => write!(f, "{}", x),
569 Self::Bytes(x) => write!(f, "{}", x),
570 Self::Int(x) => write!(f, "{}", x),
571 Self::Float(x) => write!(f, "{}", x),
572 Self::Map(x) => write!(f, "{}", x),
573 Self::List(x) => write!(f, "{}", x),
574 Self::Link(x) => write!(f, "{}", x),
575 Self::Union(x) => write!(f, "{}", x),
576 Self::Struct(x) => write!(f, "{}", x),
577 Self::Enum(x) => write!(f, "{}", x),
578 Self::Copy(x) => write!(f, "{}", x),
579 }
580 }
581}
582
583impl fmt::Display for RepresentationKind {
604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
605 match self {
606 Self::Bool => write!(f, "{}", L_BOOL),
607 Self::String => write!(f, "{}", L_STRING),
608 Self::Bytes => write!(f, "{}", L_BYTES),
609 Self::Int => write!(f, "{}", L_INT),
610 Self::Float => write!(f, "{}", L_FLOAT),
611 Self::Map => write!(f, "{}", L_MAP),
612 Self::List => write!(f, "{}", L_LIST),
613 Self::Link => write!(f, "{}", L_LINK),
614 }
615 }
616}
617
618impl fmt::Display for AnyScalar {
619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
620 match self {
621 Self::Bool(x) => write!(f, "\"{}\"", x),
622 Self::String(x) => write!(f, "\"{}\"", x),
623 Self::Bytes(_x) => todo!("literal bytes"), Self::Int(x) => write!(f, "{}", x),
625 Self::Float(x) => write!(f, "{}", x),
626 }
627 }
628}
629
630impl fmt::Display for TypeBool {
631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
632 write!(f, "{}", L_BOOL)
633 }
634}
635
636impl fmt::Display for TypeString {
637 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
638 write!(f, "{}", L_STRING)
639 }
640}
641
642impl fmt::Display for TypeBytes {
643 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
644 write!(f, "{}", self.representation)
645 }
646}
647
648impl fmt::Display for BytesRepresentation {
649 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
650 match self {
651 Self::Bytes(b) => write!(f, "{}", b),
652 Self::Advanced(_name) => todo!("advanced layout for bytes"),
653 }
654 }
655}
656
657impl fmt::Display for bytes_representation::Bytes {
658 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
659 write!(f, "{}", L_BYTES)
660 }
661}
662
663impl fmt::Display for TypeInt {
664 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
665 write!(f, "{}", L_INT)
666 }
667}
668
669impl fmt::Display for TypeFloat {
670 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
671 write!(f, "{}", L_FLOAT)
672 }
673}
674
675impl fmt::Display for TypeMap {
676 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
677 match &self.representation {
678 MapRepresentation::Map(_) => {
679 if self.value_nullable {
680 write!(f, "{} ", L_NULLABLE)?;
681 }
682 write!(f, "{{{}:{}}}", self.key_type, self.value_type)
683 }
684 MapRepresentation::StringPairs(sp) => {
685 if self.value_nullable {
686 write!(f, "{} ", L_NULLABLE)?;
687 }
688 writeln!(
689 f,
690 "{{{}:{}}} {} {} {{",
691 self.key_type, self.value_type, L_REPRESENTATION, L_STRINGPAIRS
692 )?;
693 writeln!(f, " innerDelim \"{}\"", sp.inner_delim)?;
694 writeln!(f, " entryDelim \"{}\"", sp.entry_delim)?;
695 writeln!(f, "}}")
696 }
697 MapRepresentation::ListPairs(_) => {
698 if self.value_nullable {
699 write!(f, "{} ", L_NULLABLE)?;
700 }
701 writeln!(
702 f,
703 "{{{}:{}}} representation listpairs",
704 self.key_type, self.value_type
705 )
706 }
707 MapRepresentation::Advanced(_) => todo!(),
708 }
709 }
710}
711
712impl fmt::Display for TypeList {
713 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
714 if self.value_nullable {
715 write!(f, "{} ", L_NULLABLE)?;
716 }
717 write!(f, "[{}]", self.value_type)
718
719 }
721}
722
723impl fmt::Display for TypeLink {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
725 write!(f, "{}{}", L_LINK_REF, self.expected_type)
726 }
727}
728
729impl fmt::Display for TypeUnion {
730 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
731 write!(f, "{}", self.representation)
732 }
733}
734
735impl fmt::Display for UnionRepresentation {
736 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
737 match self {
738 Self::Kinded(x) => write!(f, "{}", x),
739 Self::Keyed(x) => write!(f, "{}", x),
740 Self::Envelope(x) => write!(f, "{}", x),
741 Self::Inline(x) => write!(f, "{}", x),
742 Self::BytePrefix(x) => write!(f, "{}", x),
743 }
744 }
745}
746
747impl fmt::Display for union_representation::Kinded {
748 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
749 write!(f, "{} {{", L_UNION)?;
750 for (kind, name) in &self.0 {
751 write!(f, "\n | {} {}", name, kind)?;
752 }
753 if !self.0.is_empty() {
754 writeln!(f)?;
755 }
756 write!(f, "}} {} {}", L_REPRESENTATION, L_KINDED)
757 }
758}
759
760impl fmt::Display for union_representation::Keyed {
761 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
762 write!(f, "{} {{", L_UNION)?;
763 for (ty, name) in &self.0 {
764 write!(f, "\n | {} \"{}\"", name, ty)?;
765 }
766 if !self.0.is_empty() {
767 writeln!(f)?;
768 }
769 write!(f, "}} {} {}", L_REPRESENTATION, L_KEYED)
770 }
771}
772
773impl fmt::Display for union_representation::Envelope {
774 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
775 write!(f, "{} {{", L_UNION)?;
776 for (ty, name) in &self.discriminant_table {
777 write!(f, "\n | {} \"{}\"", name, ty)?;
778 }
779 if !self.discriminant_table.is_empty() {
780 writeln!(f)?;
781 }
782 writeln!(f, "}} {} {} {{", L_REPRESENTATION, L_ENVELOPE)?;
783 writeln!(f, " {} \"{}\"", L_DISCRIMINANT_KEY, self.discriminant_key)?;
784 writeln!(f, " {} \"{}\"", L_CONTENT_KEY, self.content_key)?;
785 writeln!(f, "}}")
786 }
787}
788
789impl fmt::Display for union_representation::Inline {
790 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
791 write!(f, "{} {{", L_UNION)?;
792 for (ty, name) in &self.discriminant_table {
793 write!(f, "\n | {} \"{}\"", name, ty)?;
794 }
795 if !self.discriminant_table.is_empty() {
796 writeln!(f)?;
797 }
798 write!(
799 f,
800 "}} {} {} {{\n {} \"{}\"\n}}",
801 L_REPRESENTATION, L_INLINE, L_DISCRIMINANT_KEY, self.discriminant_key
802 )
803 }
804}
805
806impl fmt::Display for union_representation::BytePrefix {
807 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
808 write!(f, "{} {{", L_UNION)?;
809 for (ty, byte) in &self.discriminant_table {
810 write!(f, "\n | {} {}", ty, byte)?;
811 }
812 if !self.discriminant_table.is_empty() {
813 writeln!(f)?;
814 }
815 write!(f, "}} {} {}", L_REPRESENTATION, L_BYTEPREFIX)
816 }
817}
818
819impl fmt::Display for TypeStruct {
820 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
821 match &self.representation {
822 StructRepresentation::Map(m) => {
823 write!(f, "{} {{", L_STRUCT)?;
824 for (name, val) in &self.fields {
825 write!(f, "\n {} {}", name, val)?;
826 if let Some(details) = m.fields.get(name) {
827 write!(f, " (")?;
828 if let Some(implicit) = &details.implicit {
829 write!(f, "{} {}", L_IMPLICIT, implicit)?;
830 }
831 write!(f, ")")?;
832 }
833 }
834 if !self.fields.is_empty() {
835 writeln!(f)?;
836 }
837 write!(f, "}}")
838 }
839 StructRepresentation::Tuple(t) => {
840 write!(f, "{} {{", L_STRUCT)?;
841 for (name, val) in &self.fields {
842 write!(f, "\n {} {}", name, val)?;
843 }
844 if !self.fields.is_empty() {
845 writeln!(f)?;
846 }
847 write!(f, "}} {} {}", L_REPRESENTATION, L_TUPLE)?;
848 if let Some(field_order) = &t.field_order {
849 writeln!(f, " {{")?;
850 writeln!(
851 f,
852 " fieldOrder [{}]",
853 field_order
854 .iter()
855 .map(|f| format!("\"{}\"", f))
856 .collect::<Vec<_>>()
857 .join(", ")
858 )?;
859 writeln!(f, "}}")?;
860 }
861 Ok(())
862 }
863 StructRepresentation::StringPairs(sp) => {
864 write!(f, "{} {{", L_STRUCT)?;
865 for (name, val) in &self.fields {
866 write!(f, "\n {} {}", name, val)?;
867 }
868 if !self.fields.is_empty() {
869 writeln!(f)?;
870 }
871 writeln!(f, "}} {} {} {{", L_REPRESENTATION, L_STRINGPAIRS)?;
872 writeln!(f, " innerDelim \"{}\"", sp.inner_delim)?;
873 writeln!(f, " entryDelim \"{}\"", sp.entry_delim)?;
874 writeln!(f, "}}")
875 }
876 StructRepresentation::StringJoin(sj) => {
877 write!(f, "{} {{", L_STRUCT)?;
878 for (name, val) in &self.fields {
879 write!(f, "\n {} {}", name, val)?;
880 }
881 if !self.fields.is_empty() {
882 writeln!(f)?;
883 }
884 writeln!(f, "}} {} {} {{", L_REPRESENTATION, L_STRINGJOIN)?;
885 writeln!(f, " join \"{}\"", sj.join)?;
886 writeln!(f, "}}")
887 }
888 StructRepresentation::ListPairs(_) => {
889 write!(f, "{} {{", L_STRUCT)?;
890 for (name, val) in &self.fields {
891 write!(f, "\n {} {}", name, val)?;
892 }
893 if !self.fields.is_empty() {
894 writeln!(f)?;
895 }
896 write!(f, "}} {} {}", L_REPRESENTATION, L_LISTPAIRS)
897 }
898 }
899 }
900}
901
902impl fmt::Display for FieldName {
903 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
904 write!(f, "{}", self.0)
905 }
906}
907
908impl fmt::Display for StructField {
909 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
910 if self.optional {
911 write!(f, "{} ", L_OPTIONAL)?;
912 }
913 if self.nullable {
914 write!(f, "{} ", L_NULLABLE)?;
915 }
916 write!(f, "{}", self.r#type)
917 }
918}
919
920impl fmt::Display for TypeTerm {
921 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
922 match self {
923 Self::TypeName(name) => write!(f, "{}", name),
924 Self::InlineDefn(inline) => write!(f, "{}", inline),
925 }
926 }
927}
928
929impl fmt::Display for InlineDefn {
930 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
931 match self {
932 Self::Map(map) => write!(f, "{}", map),
933 Self::List(list) => write!(f, "{}", list),
934 }
935 }
936}
937
938impl fmt::Display for TypeEnum {
939 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
940 write!(f, "{} {{", L_ENUM)?;
941 #[allow(clippy::for_kv_map)]
942 for (value, _null) in &self.members {
943 write!(f, "\n | {}", value)?;
944 }
945 if !self.members.is_empty() {
946 writeln!(f)?;
947 }
948 write!(f, "}}")
949
950 }
952}
953
954impl fmt::Display for EnumValue {
955 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
956 write!(f, "{}", self.0)
957 }
958}
959
960impl fmt::Display for TypeCopy {
961 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
962 write!(f, "{} {}", L_COPY, self.from_type)
963 }
964}
965
966peg::parser! {
967 pub(crate) grammar schema_dsl() for str {
968 rule _eof() -> () = ![_] { }
969 rule _eol() -> () = "\n" / "\r\n" { }
970 rule _ws1() -> () = " " / "\t" { }
971
972 rule _comment() -> String = _ws1()* "#" s:$((!_eol() [_])*) _eol() { s.to_string() }
973 rule _empty_line() -> () = _ws1()* _eol() { }
974 rule _ws_block() -> () = (_comment() / _empty_line())* _ws1()* { }
975
976 pub(crate) rule type_name() -> TypeName = cs:$(['A'..='Z'] (['A'..='Z'] / ['a'..='z'] / ['0'..='9'] / "_")*) { TypeName(cs.to_string()) }
977
978 rule schema_map() -> SchemaMap = _ws_block() decls:(type_decl() ** _ws_block()) _ws_block() _eof() { SchemaMap(decls.into_iter().collect()) }
979
980 pub(crate) rule parse() -> Schema = types:schema_map() { Schema { types, advanced: AdvancedDataLayoutMap::default() } }
982
983 rule m_map() -> TypeMap
984 = nil:("nullable" _ws1()+)? "{" _ws1()* n:type_name() _ws1()* ":" _ws1()* t:type_term() "}"
985 {
986 TypeMap {
987 key_type: n,
988 value_type: t,
989 value_nullable: nil.is_some(),
990 representation: MapRepresentation::default()
991 }
992 }
993 rule m_stringpairs() -> TypeMap
994 = nil:("nullable" _ws1()+)? "{" _ws1()* n:type_name() _ws1()* ":" _ws1()* t:type_term() "}"
995 _ws1()* "representation" _ws1()+ "stringpairs" _ws1()* "{" _eol() _ws1()* "innerDelim" _ws1()+ id:string() _eol() _ws1()* "entryDelim" _ws1()+ ed:string() _ws_block() "}"
997 {
998 TypeMap {
999 key_type: n,
1000 value_type: t,
1001 value_nullable: nil.is_some(),
1002 representation: MapRepresentation::StringPairs(map_representation::StringPairs { inner_delim: id, entry_delim: ed })
1003 }
1004 }
1005 rule m_listpairs() -> TypeMap
1006 = nil:("nullable" _ws1()+)? "{" _ws1()* n:type_name() _ws1()* ":" _ws1()* t:type_term() "}" _ws1()* "representation" _ws1()+ "listpairs"
1007 {
1008 TypeMap {
1009 key_type: n,
1010 value_type: t,
1011 value_nullable: nil.is_some(),
1012 representation: MapRepresentation::ListPairs(map_representation::ListPairs)
1013 }
1014 }
1015 rule type_map() -> TypeMap = m:(
1016 m_stringpairs() /
1017 m_listpairs() /
1018 m_map()
1019 )
1020
1021 rule type_list() -> TypeList = nil:("nullable" _ws1()+)? "[" _ws1()* t:type_term() _ws1()* "]" { TypeList { value_type: t, value_nullable: nil.is_some(), representation: ListRepresentation::default()} }
1023
1024 rule t_bool() -> Type = "bool" { Type::Bool(TypeBool) }
1025 rule t_string() -> Type = "string" { Type::String(TypeString) }
1026 rule t_bytes() -> Type = "bytes" { Type::Bytes(TypeBytes { representation: BytesRepresentation::default() }) }
1027 rule t_int() -> Type = "int" { Type::Int(TypeInt) }
1028 rule t_float() -> Type = "float" { Type::Float(TypeFloat) }
1029 rule t_map() -> Type = m:type_map() { Type::Map(m) }
1030 rule t_list() -> Type = l:type_list() { Type::List(l) }
1031 rule t_link() -> Type = "&" t:type_name() { Type::Link(TypeLink { expected_type: t.to_string() }) }
1032 rule t_union() -> Type = r:union_representation() { Type::Union(TypeUnion { representation: r }) }
1033 rule t_struct() -> Type = s:struct_model() { Type::Struct(s) }
1034 rule t_enum() -> Type = "enum" _ws1()* "{" _ws_block() ms:(enum_member()*) _ws_block() "}" { Type::Enum(TypeEnum { members: ms.into_iter().map(|m| (m, Null)).collect(), representation: EnumRepresentation::default() }) }
1035 rule t_copy() -> Type = "=" _ws1()* n:type_name() { Type::Copy(TypeCopy { from_type: n }) }
1036 rule r#type() -> Type = t:(
1037 t_bool() /
1038 t_string() /
1039 t_bytes() /
1040 t_int() /
1041 t_float() /
1042 t_map() /
1043 t_list() /
1044 t_link() /
1045 t_union() /
1046 t_struct() /
1047 t_enum() /
1048 t_copy()
1049 ) { t }
1050 pub(crate) rule schema_type() -> Type = t:r#type() { t }
1051
1052
1053 rule union_representation() -> UnionRepresentation = ur:(
1054 ur_kinded() /
1055 ur_keyed() /
1056 ur_envelope() /
1057 ur_inline() /
1058 ur_byteprefix()
1059 ) { ur }
1060 rule ur_kinded() -> UnionRepresentation = "union" _ws1()* "{" _ws_block() ts:(type_name_and_representation_kind()*) _ws1()* "}" _ws1()* "representation" _ws1()+ "kinded" _ws1()* (_eol() / _eof()) { UnionRepresentation::Kinded(union_representation::Kinded(ts.into_iter().map(|(tn, rk)| (rk, tn)).collect())) }
1061 rule ur_keyed() -> UnionRepresentation = "union" _ws1()* "{" _ws_block() ts:(type_name_and_string()*) _ws1()* "}" _ws1()* "representation" _ws1()+ "keyed" _ws1()* (_eol() / _eof()) { UnionRepresentation::Keyed(union_representation::Keyed(ts.into_iter().map(|(tn, s)| (s, tn)).collect())) }
1062 rule ur_envelope() -> UnionRepresentation = "union" _ws1()* "{" _ws_block() ts:(type_name_and_string()*) _ws1()* "}" _ws1()* "representation" _ws1()+ "envelope" _ws1()* "{" _ws_block() "discriminantKey" _ws1()+ dk:string() _ws_block() "contentKey" _ws1()+ ck:string() _ws_block() "}" (_eol() / _eof()) { UnionRepresentation::Envelope(union_representation::Envelope { discriminant_table: ts.into_iter().map(|(tn, s)| (s, tn)).collect(), discriminant_key: dk, content_key: ck }) }
1063 rule ur_inline() -> UnionRepresentation = "union" _ws1()* "{" _ws_block() ts:(type_name_and_string()*) _ws1()* "}" _ws1()* "representation" _ws1()+ "inline" _ws1()* "{" _ws_block() "discriminantKey" _ws1()+ k:string() _ws_block() "}" (_eol() / _eof()) { UnionRepresentation::Inline(union_representation::Inline { discriminant_key: k, discriminant_table: ts.into_iter().map(|(tn, s)| (s, tn)).collect() }) }
1064 rule ur_byteprefix() -> UnionRepresentation = "union" _ws1()* "{" _ws_block() ts:(type_name_and_byte()*) _ws1()* "}" _ws1()* "representation" _ws1()+ "byteprefix" (_eol() / _eof()) { UnionRepresentation::BytePrefix(union_representation::BytePrefix { discriminant_table: ts.into_iter().collect() }) }
1065
1066 rule type_name_and_string() -> (TypeName, String) = _ws1()* "|" _ws1()* t:type_name() _ws1()+ s:string() _ws1()* _eol() { (t, s) }
1067 rule string() -> String = "\"" cs:$((!"\"" [_])*) "\"" { cs.to_string() }
1068
1069 rule type_name_and_byte() -> (TypeName, u8) = _ws1()* "|" _ws1()* s:type_name() _ws1()+ b:$(['0'..='9']+) _ws1()* _eol() { (s, b.parse().unwrap()) }
1070
1071 rule type_name_and_representation_kind() -> (TypeName, RepresentationKind) = _ws1()* "|" _ws1()* t:type_name() _ws1()+ r:representation_kind() _ws1()* _eol() { (t, r) }
1072 rule rk_bool() -> RepresentationKind = "bool" { RepresentationKind::Bool }
1073 rule rk_string() -> RepresentationKind = "string" { RepresentationKind::String }
1074 rule rk_bytes() -> RepresentationKind = "bytes" { RepresentationKind::Bytes }
1075 rule rk_int() -> RepresentationKind = "int" { RepresentationKind::Int }
1076 rule rk_float() -> RepresentationKind = "float" { RepresentationKind::Float }
1077 rule rk_map() -> RepresentationKind = "map" { RepresentationKind::Map }
1078 rule rk_list() -> RepresentationKind = "list" { RepresentationKind::List }
1079 rule rk_link() -> RepresentationKind = "link" { RepresentationKind::Link }
1080 rule representation_kind() -> RepresentationKind = r:(
1081 rk_bool() /
1082 rk_string() /
1083 rk_bytes() /
1084 rk_int() /
1085 rk_float() /
1086 rk_map() /
1087 rk_list() /
1088 rk_link()
1089 ) { r }
1090
1091 rule as_bool_false() -> AnyScalar = "\"false\"" { AnyScalar::Bool(false) }
1092 rule as_bool_true() -> AnyScalar = "\"true\"" { AnyScalar::Bool(true) }
1093 rule as_string() -> AnyScalar = s:string() { AnyScalar::String(s) }
1094 rule as_bytes() -> AnyScalar = "x" { todo!() }
1095 rule as_int() -> AnyScalar = "x" { todo!() }
1096 rule as_float() -> AnyScalar = "x" { todo!() }
1097 rule any_scalar() -> AnyScalar = a:(
1098 as_bool_false() /
1099 as_bool_true() /
1100 as_string() /
1101 as_bytes() /
1102 as_int() /
1103 as_float()
1104 ) { a }
1105
1106
1107 pub(crate) rule field_name() -> FieldName = cs:$((['A'..='Z'] / ['a'..='z'] / ['0'..='9'] / "_")+) { FieldName(cs.to_string()) }
1108 rule quoted_field_name() -> FieldName = "\"" f:field_name() "\"" { f }
1109 rule struct_field() -> StructField = o:("optional" _ws1()+)? n:("nullable" _ws1()+)? t:type_term() { StructField { r#type: t, optional: o.is_some(), nullable: n.is_some() } }
1111
1112 rule tt_type_name() -> TypeTerm = n:type_name() { TypeTerm::TypeName(n) }
1113 rule id_map() -> InlineDefn = m:type_map() { InlineDefn::Map(m) }
1114 rule id_list() -> InlineDefn = l:type_list() { InlineDefn::List(l) }
1115 rule tt_inline_defn() -> TypeTerm = i:(id_map() / id_list()) { TypeTerm::InlineDefn(Box::new(i)) }
1116 pub(crate) rule type_term() -> TypeTerm = tt:(tt_type_name() / tt_inline_defn()) { tt }
1117
1118 rule st_map() -> TypeStruct = "struct" _ws1()* "{" _ws_block() fs:(st_map_field()*) _ws1()* "}" {
1119 let fields = fs.iter().cloned().map(|(f, s, _)| (f, s)).collect();
1120 let representation = StructRepresentation::Map(struct_representation::Map {
1121 fields: fs.into_iter().filter_map(|(f, _, x)| x.map(|x| (f, x))).collect()
1122 });
1123
1124 TypeStruct { fields, representation }
1125 }
1126 rule st_map_field() -> (FieldName, StructField, Option<struct_representation::MapFieldDetails>) = _ws1()* n:field_name() _ws1()+ f:struct_field() x:st_map_field_details()? _ws1()* _eol() { (n, f, x) }
1127 rule st_map_field_details() -> struct_representation::MapFieldDetails = _ws1()* "(" _ws1()* "implicit" _ws1()+ i:any_scalar()? _ws1()* ")" { struct_representation::MapFieldDetails { implicit: i, rename: None } }
1128
1129 rule st_tuple() -> TypeStruct
1130 = "struct" _ws1()* "{" _ws_block() fs:(st_map_field()*) _ws1()* "}"
1131 _ws1()* "representation" _ws1()+ "tuple" _ws1()* o:st_field_order()?
1132 {
1133 let fields = fs.iter().cloned().map(|(f, s, _)| (f, s)).collect();
1134 let representation = StructRepresentation::Tuple(struct_representation::Tuple {
1135 field_order: o,
1136 });
1137
1138 TypeStruct { fields, representation }
1139 }
1140 rule st_field_order() -> Vec<FieldName> = "{" _ws_block() "fieldOrder" _ws1()+ "[" fs:(quoted_field_name() ** ("," _ws_block())) "]" _ws_block() "}" { fs }
1141
1142 rule st_stringpairs() -> TypeStruct
1143 = "struct" _ws1()* "{" _ws_block() fs:(st_map_field()*) _ws1()* "}"
1144 _ws1()* "representation" _ws1()+ "stringpairs" _ws1()* "{" _eol() _ws1()* "innerDelim" _ws1()+ id:string() _eol() _ws1()* "entryDelim" _ws1()+ ed:string() _ws_block() "}"
1146 {
1147 TypeStruct {
1148 fields: fs.iter().cloned().map(|(f, s, _)| (f, s)).collect(),
1149 representation: StructRepresentation::StringPairs(struct_representation::StringPairs {
1150 inner_delim: id,
1151 entry_delim: ed,
1152 }),
1153 }
1154 }
1155
1156 rule st_stringjoin() -> TypeStruct
1157 = "struct" _ws1()* "{" _ws_block() fs:(st_map_field()*) _ws1()* "}"
1158 _ws1()* "representation" _ws1()+ "stringjoin" _ws1()* "{" _eol() _ws1()* "join" _ws1()+ j:string() _ws_block() "}"
1160 {
1161 TypeStruct {
1162 fields: fs.iter().cloned().map(|(f, s, _)| (f, s)).collect(),
1163 representation: StructRepresentation::StringJoin(struct_representation::StringJoin {
1164 join: j,
1165 field_order: fs.into_iter().map(|(f, _, _)| f).collect::<Vec<_>>(),
1166 }),
1167 }
1168 }
1169
1170 rule st_listpairs() -> TypeStruct
1171 = "struct" _ws1()* "{" _ws_block() fs:(st_map_field()*) _ws1()* "}" _ws1()* "representation" _ws1()+ "listpairs"
1172 {
1173 TypeStruct {
1174 fields: fs.iter().cloned().map(|(f, s, _)| (f, s)).collect(),
1175 representation: StructRepresentation::ListPairs(struct_representation::ListPairs),
1176 }
1177 }
1178
1179 pub(crate) rule struct_model() -> TypeStruct = s:(
1180 st_tuple() /
1181 st_stringpairs() /
1182 st_stringjoin() /
1183 st_listpairs() /
1184 st_map()
1185 ) { s }
1186
1187
1188 pub(crate) rule enum_value() -> EnumValue = cs:$((['A'..='Z'] / ['a'..='z'] / ['0'..='9'] / "_")+) { EnumValue(cs.to_string()) }
1189 rule enum_member() -> EnumValue = _ws1()* "|" _ws1()* ev:enum_value() _ws1()* _eol() { ev }
1190
1191 rule type_decl() -> (TypeName, Type) = "type" _ws1()+ n:type_name() _ws1()+ t:r#type() (_eol() / _eof()) { (n, t) }
1192 }
1193}
1194
1195#[cfg(test)]
1196mod tests {
1197 use super::*;
1198
1199 use std::fs::read_to_string;
1200
1201 use insta::{assert_debug_snapshot, assert_json_snapshot, with_settings};
1202 use pretty_assertions::assert_eq;
1203 use test_strategy::proptest;
1204
1205 #[cfg(feature = "fast-test")]
1206 const CASES: u32 = 10;
1207 #[cfg(not(feature = "fast-test"))]
1208 const CASES: u32 = 1000;
1209
1210 #[cfg(feature = "fast-test")]
1211 const MAX_SHRINK_ITERS: u32 = 100;
1212 #[cfg(not(feature = "fast-test"))]
1213 const MAX_SHRINK_ITERS: u32 = 10000;
1214
1215 fn schema_schema() -> Schema {
1216 schema_dsl::parse(&read_to_string("./specs/schemas/schema-schema.ipldsch").unwrap())
1217 .unwrap()
1218 }
1219
1220 fn schema_schema_json() -> String {
1221 read_to_string("./specs/schemas/schema-schema.ipldsch.json").unwrap()
1222 }
1223
1224 fn schema_roundtrips_through_json(schema: &Schema) {
1225 assert_eq!(
1226 *schema,
1227 serde_json::from_str(&serde_json::to_string(schema).unwrap()).unwrap()
1228 );
1229 }
1230
1231 fn schema_roundtrips_through_dsl(schema: &Schema) {
1232 let rendered = schema.to_string();
1233
1234 for (n, line) in rendered.lines().enumerate() {
1235 eprintln!(" {:>4} │ {}", n + 1, line);
1236 }
1237
1238 assert_eq!(*schema, schema_dsl::parse(&rendered).unwrap());
1239 }
1240
1241 #[test]
1242 fn snapshot_of_parsed_schema_schema() {
1243 assert_debug_snapshot!(schema_schema());
1244 }
1245
1246 #[test]
1247 fn snapshot_of_reified_json_form_of_schema_schema() {
1248 with_settings!({sort_maps => true}, {
1249 assert_json_snapshot!(schema_schema())
1250 });
1251 }
1252
1253 #[test]
1254 fn struct_representation_tuple_reifies_correctly() {
1255 schema_roundtrips_through_json(
1256 &schema_dsl::parse(
1257 r#"type StructRepresentation_Tuple struct {
1258 fieldOrder optional [FieldName]
1259 }"#,
1260 )
1261 .unwrap(),
1262 );
1263 }
1264
1265 #[test]
1266 fn reified_form_of_schema_schema_matches_parsed_dsl_form() {
1267 assert_eq!(
1268 schema_schema(),
1269 serde_json::from_str(&schema_schema_json()).unwrap()
1270 );
1271 }
1272
1273 #[test]
1274 fn schema_schema_roundtrips_through_parsing_and_display() {
1275 schema_roundtrips_through_dsl(&schema_schema());
1276 }
1277
1278 #[proptest(cases = CASES, max_shrink_iters = MAX_SHRINK_ITERS)]
1279 fn roundtrips_through_dsl_form(schema: Schema) {
1280 schema_roundtrips_through_dsl(&schema);
1281 }
1282
1283 #[proptest(cases = CASES, max_shrink_iters = MAX_SHRINK_ITERS)]
1284 fn roundtrips_through_json_form(schema: Schema) {
1285 schema_roundtrips_through_json(&schema);
1286 }
1287}