ruststep/ast/mod.rs
1//! Abstract syntax tree for exchange structure
2//!
3//! This module contains implementation of [serde::Serialize] and [serde::Deserialize]
4//! for AST structs.
5//!
6//! Deserialize
7//! ------------
8//!
9//! [Implementing a Deserializer](https://serde.rs/impl-deserializer.html) page of [serde manual](https://serde.rs/) says
10//! > The deserializer is responsible for mapping the input data
11//! > into [Serde's data model](https://serde.rs/data-model.html) by invoking exactly one of the methods
12//! > on the Visitor that it receives.
13//!
14//! [serde::de::Deserializer] trait is implemented for [Parameter],
15//! [Record], and [SubSuperRecord].
16//! Be sure that this mapping is not only for espr-generated structs.
17//! This can be used with other Rust structs using `serde_derive::Deserialize` custom derive:
18//!
19//! ```text
20//! ┌────────────────────┐
21//! │ Exchange Structure │
22//! └─┬──────────────────┘
23//! │ Deserialier trait ◄── Implemented here
24//! ┌─▼────────────────┐
25//! │ serde data model │
26//! └─┬────┬───────────┘
27//! │ │ ruststep_derive::Deserialize
28//! │ ┌──▼─────────────────────────┐
29//! │ │ espr-generated Rust struct │
30//! │ └────────────────────────────┘
31//! │ serde_derive::Deserialize
32//! ┌─▼─────────────────┐
33//! │ Other Rust struct │
34//! └───────────────────┘
35//! ```
36
37pub mod de;
38pub mod ser;
39
40use crate::parser;
41use std::str::FromStr;
42
43/// AST portion
44pub trait AST: FromStr<Err = crate::error::Error> {
45 fn parse(input: &str) -> parser::combinator::ParseResult<Self>;
46}
47
48macro_rules! derive_ast_from_str {
49 ($ast:ty, $parse:path) => {
50 impl std::str::FromStr for $ast {
51 type Err = $crate::error::Error;
52 fn from_str(input: &str) -> $crate::error::Result<Self> {
53 use nom::Finish;
54 let input = input.trim();
55 let (residual, record) = AST::parse(input)
56 .finish()
57 .map_err(|err| $crate::error::TokenizeFailed::new(input, err))?;
58 if !residual.is_empty() {
59 return Err($crate::error::Error::ExtraInputRemaining(input.to_string()));
60 }
61 Ok(record)
62 }
63 }
64
65 impl AST for $ast {
66 fn parse(input: &str) -> parser::combinator::ParseResult<Self> {
67 $parse(input)
68 }
69 }
70 };
71}
72
73/// Name of an entity instance or a value
74///
75/// Corresponding to [parser::token::rhs_occurrence_name] and [parser::token::lhs_occurrence_name]
76#[derive(Debug, Clone, PartialEq)]
77pub enum Name {
78 /// Like `#11`, corresponds to [parser::token::entity_instance_name]
79 Entity(u64),
80 /// Like `@11`, corresponds to [parser::token::value_instance_name]
81 Value(u64),
82 /// Like `#CONST_ENTITY`, corresponds to [parser::token::constant_entity_name]
83 ConstantEntity(String),
84 /// Like `@CONST_VALUE`, corresponds to [parser::token::constant_value_name]
85 ConstantValue(String),
86}
87derive_ast_from_str!(Name, parser::token::rhs_occurrence_name);
88
89/// A struct typed in EXPRESS schema, e.g. `A(1.0, 2.0)`
90///
91/// FromStr
92/// --------
93///
94/// ```
95/// use ruststep::ast::{Record, Parameter};
96/// use std::str::FromStr;
97///
98/// let record = Record::from_str("A(1, 2)").unwrap();
99/// assert_eq!(
100/// record,
101/// Record {
102/// name: "A".to_string(),
103/// parameter: vec![Parameter::Integer(1), Parameter::Integer(2)].into(),
104/// }
105/// )
106/// ```
107///
108/// Deserialize as a map
109/// ---------------------
110///
111/// [serde::Deserializer] implementation for [Record] provides
112/// a mapping it into "map" in serde data model.
113/// The keyword is mapped into the key and the parameters are its value:
114///
115/// ```
116/// use std::{str::FromStr, collections::HashMap};
117/// use ruststep::ast::*;
118/// use serde::Deserialize;
119///
120/// let p = Record::from_str("DATA_KEYWORD(1, 2)").unwrap();
121///
122/// // Map can be deserialize as a hashmap
123/// assert_eq!(
124/// HashMap::<String, Vec<i32>>::deserialize(&p).unwrap(),
125/// maplit::hashmap! {
126/// "DATA_KEYWORD".to_string() => vec![1, 2]
127/// }
128/// );
129///
130/// // Map in serde can be interpreted as Rust field
131/// #[derive(Debug, Clone, PartialEq, Deserialize)]
132/// struct X {
133/// #[serde(rename = "DATA_KEYWORD")]
134/// a: Vec<i32>,
135/// }
136/// assert_eq!(
137/// X::deserialize(&p).unwrap(),
138/// X { a: vec![1, 2] }
139/// );
140/// ```
141///
142/// Mapping to simple instance
143/// ---------------------------
144///
145/// It is deserialized as a "struct" only when the hint function
146/// [serde::Deserializer::deserialize_struct] is called
147/// and the struct name matches to its keyword appears in the exchange structure.
148/// See [the manual of container attribute in serde](https://serde.rs/container-attrs.html)
149/// for detail.
150///
151/// ```
152/// use std::{str::FromStr, collections::HashMap};
153/// use ruststep::ast::*;
154/// use serde::Deserialize;
155///
156/// let p = Record::from_str("DATA_KEYWORD(1, 2)").unwrap();
157///
158/// #[derive(Debug, Clone, PartialEq, Deserialize)]
159/// #[serde(rename = "DATA_KEYWORD")] // keyword matches
160/// struct A {
161/// x: i32,
162/// y: i32,
163/// }
164/// assert_eq!(
165/// A::deserialize(&p).unwrap(),
166/// A { x: 1, y: 2 }
167/// );
168///
169/// #[derive(Debug, Clone, PartialEq, Deserialize)]
170/// #[serde(rename = "ANOTHER_KEYWORD")] // keyword does not match
171/// struct B {
172/// x: i32,
173/// y: i32,
174/// }
175/// assert!(B::deserialize(&p).is_err());
176/// ```
177///
178/// Internal mapping to complex entity instance
179/// --------------------------------------------
180///
181/// Complex entity in EXPRESS language is
182/// a set of two or more primitive component called partial complex entity.
183///
184/// ```text
185/// ENTITY person;
186/// name: STRING;
187/// END_ENTITY;
188///
189/// ENTITY employee SUBTYPE OF (person);
190/// pay: INTEGER;
191/// END_ENTITY;
192///
193/// ENTITY student SUBTYPE OF (person);
194/// school_name: STRING;
195/// END_ENTITY;
196/// ```
197///
198/// In this EXPRESS schema, a complex entity of `person` can have three components
199/// representing `person`, `employee`, and `student`.
200/// There are two way of mapping it from an exchange structure.
201/// The internal mapping looks like usual case:
202///
203/// ```text
204/// #1 = EMPLOYEE('Hitori Goto', 10);
205/// #2 = STUDENT('Ikuno Kita', 'Shuka');
206/// ```
207///
208/// `#1` has two parameters while `employee` definition has a field `pay`.
209/// These parameters are consumed by supertype `person` first,
210/// and then subtype `employee` consumes:
211///
212/// ```text
213/// #1 = EMPLOYEE('Hitori Goto', 10);
214/// ▲ ▲
215/// │ └─ map to pay in employee
216/// └─ map to name in person
217/// ```
218///
219/// Internal mapping cannot handle the case where
220/// both `employee` and `student` components co-exist.
221/// This case will be handled by external mapping using [SubSuperRecord].
222///
223/// The detail of internal mapping is defined in 12.2.5.2 "Internal mapping"
224/// of [ISO-10303-21](https://www.iso.org/standard/63141.html).
225///
226/// In terms of serde data model, [Record] is not self-describing
227/// when using internal mapping rule.
228/// Structs using internal mapping should implement [serde::Deserialize]
229/// as described in subtype-supertype constraint in EXPRESS schema.
230///
231#[derive(Debug, Clone, PartialEq)]
232pub struct Record {
233 pub name: String,
234 pub parameter: Parameter,
235}
236derive_ast_from_str!(Record, parser::exchange::simple_record);
237
238/// A set of [Record] mapping to complex entity instance,
239/// e.g. `(A(1) B(2.0) C("3"))`
240///
241/// FromStr
242/// --------
243///
244/// ```
245/// use ruststep::ast::*;
246/// use std::str::FromStr;
247///
248/// let record = SubSuperRecord::from_str("(A(1, 2) B(3, 4))").unwrap();
249/// assert_eq!(
250/// record,
251/// SubSuperRecord(vec![
252/// Record {
253/// name: "A".to_string(),
254/// parameter: vec![
255/// Parameter::Integer(1),
256/// Parameter::Integer(2)
257/// ].into(),
258/// },
259/// Record {
260/// name: "B".to_string(),
261/// parameter: vec![
262/// Parameter::Integer(3),
263/// Parameter::Integer(4)
264/// ].into(),
265/// }
266/// ])
267/// )
268/// ```
269///
270/// Deserialize as a map
271/// ---------------------
272///
273/// Similar to [Record], [SubSuperRecord] can be deserialized as a "map":
274///
275/// ```
276/// use std::{str::FromStr, collections::HashMap};
277/// use ruststep::ast::*;
278/// use serde::Deserialize;
279///
280/// let p = SubSuperRecord::from_str("(A(1, 2) B(3, 4))").unwrap();
281///
282/// // Map can be deserialize as a hashmap
283/// assert_eq!(
284/// HashMap::<String, Vec<i32>>::deserialize(&p).unwrap(),
285/// maplit::hashmap! {
286/// "A".to_string() => vec![1, 2],
287/// "B".to_string() => vec![3, 4],
288/// }
289/// );
290///
291/// // Map in serde can be interpreted as Rust field
292/// #[derive(Debug, Clone, PartialEq, Deserialize)]
293/// struct X {
294/// #[serde(rename = "A")]
295/// a: Vec<i32>,
296/// #[serde(rename = "B")]
297/// b: Vec<i32>,
298/// }
299/// assert_eq!(
300/// X::deserialize(&p).unwrap(),
301/// X {
302/// a: vec![1, 2],
303/// b: vec![3, 4]
304/// }
305/// );
306/// ```
307///
308/// External mapping to complex entity instance
309/// --------------------------------------------
310///
311/// As discussed in [Record] for internal mapping,
312///
313/// ```text
314/// ENTITY person;
315/// name: STRING;
316/// END_ENTITY;
317///
318/// ENTITY employee SUBTYPE OF (person);
319/// pay: INTEGER;
320/// END_ENTITY;
321///
322/// ENTITY student SUBTYPE OF (person);
323/// school_name: STRING;
324/// END_ENTITY;
325/// ```
326///
327/// The instance of `person` may have three partial complex entity.
328/// External mapping has different looks in exchange structure:
329///
330/// ```text
331/// #3 = (PERSON('Hitori Goto') EMPLOYEE(10));
332/// #4 = (PERSON('Ikuno Kita') STUDENT('Shuka));
333/// #5 = (PERSON('Nizika Iziti') EMPLOYEE(15) STUDENT('Simokitazawa'))
334/// ```
335///
336/// Each components enclosed by `()` corresponds to a partial entity instance,
337/// which consists of fields declared in its entity definition.
338///
339/// ```text
340/// #5 = (PERSON('Nizika Iziti') EMPLOYEE(15) STUDENT('Simokitazawa'))
341/// ▲ ▲ ▲
342/// │ │ └─ school_name in student
343/// │ └─ pay in employee
344/// └─ name in person
345/// ```
346///
347/// The detail of external mapping is defined in 12.2.5.3 "External mapping"
348/// of [ISO-10303-21](https://www.iso.org/standard/63141.html).
349///
350/// [SubSuperRecord] is not self-describing because
351/// EXPRESS does not defines memory layout of complex entities.
352///
353#[derive(Debug, Clone, PartialEq)]
354pub struct SubSuperRecord(pub Vec<Record>);
355derive_ast_from_str!(SubSuperRecord, parser::exchange::subsuper_record);
356
357impl IntoIterator for SubSuperRecord {
358 type Item = Record;
359 type IntoIter = std::vec::IntoIter<Self::Item>;
360 fn into_iter(self) -> Self::IntoIter {
361 self.0.into_iter()
362 }
363}
364
365impl<'a> IntoIterator for &'a SubSuperRecord {
366 type Item = &'a Record;
367 type IntoIter = std::slice::Iter<'a, Record>;
368 fn into_iter(self) -> Self::IntoIter {
369 self.0.iter()
370 }
371}
372
373impl FromIterator<Record> for SubSuperRecord {
374 fn from_iter<I: IntoIterator<Item = Record>>(iter: I) -> Self {
375 Self(iter.into_iter().collect())
376 }
377}
378
379impl<'a> FromIterator<&'a Record> for SubSuperRecord {
380 fn from_iter<I: IntoIterator<Item = &'a Record>>(iter: I) -> Self {
381 Self(iter.into_iter().cloned().collect())
382 }
383}
384
385/// `DATA` section in STEP file
386///
387/// ```
388/// use ruststep::ast::DataSection;
389/// use std::str::FromStr;
390///
391/// let input = r#"
392/// DATA;
393/// #1 = A(1.0, 2.0);
394/// #2 = B(3.0, A((4.0, 5.0)));
395/// #3 = B(6.0, #1);
396/// ENDSEC;
397/// "#;
398/// let data_section = DataSection::from_str(input).unwrap();
399/// dbg!(data_section);
400/// ```
401#[derive(Debug, Clone, PartialEq)]
402pub struct DataSection {
403 /// Metadata
404 pub meta: Vec<Parameter>,
405 /// Each lines in data section
406 pub entities: Vec<EntityInstance>,
407}
408derive_ast_from_str!(DataSection, parser::exchange::data_section);
409
410/// Primitive value type in STEP data
411///
412/// Inline struct or list can be nested, i.e. `Parameter` can be a tree.
413///
414/// ```
415/// use nom::Finish;
416/// use ruststep::{parser::exchange, ast::{Parameter, Record}};
417///
418/// let (residual, p) = exchange::parameter("B((1.0, A((2.0, 3.0))))")
419/// .finish()
420/// .unwrap();
421/// assert_eq!(residual, "");
422///
423/// // A((2.0, 3.0))
424/// let a = Parameter::Typed {
425/// keyword: "A".to_string(),
426/// parameter: Box::new(vec![Parameter::real(2.0), Parameter::real(3.0)].into()),
427/// };
428///
429/// // B((1.0, a))
430/// let b = Parameter::Typed {
431/// keyword: "B".to_string(),
432/// parameter: Box::new(vec![Parameter::real(1.0), a].into()),
433/// };
434///
435/// assert_eq!(p, b);
436/// ```
437///
438/// FromIterator
439/// -------------
440/// Create a list as `Parameter::List` from `Iterator<Item=Parameter>` or `Iterator<Item=&Parameter>`.
441///
442/// ```
443/// use ruststep::ast::Parameter;
444///
445/// let p: Parameter = [Parameter::real(1.0), Parameter::real(2.0)]
446/// .iter()
447/// .collect();
448/// assert!(matches!(p, Parameter::List(_)));
449/// ```
450///
451/// Deserialize
452/// ------------
453///
454/// | Parameter | serde data model |
455/// |:------------|:-----------------|
456/// | Integer | i64 |
457/// | Real | f64 |
458/// | String | string |
459/// | List | seq |
460/// | NotProvided | option (always none)|
461/// | Omitted | option (always none)|
462/// | Enumeration | unit_variant (through [serde::de::value::StringDeserializer])|
463/// | Typed | map (through [de::RecordDeserializer])|
464/// | Ref | newtype_variant |
465///
466#[derive(Debug, Clone, PartialEq, derive_more::From)]
467pub enum Parameter {
468 /// Corresponding to `TYPED_PARAMETER` in WSN:
469 ///
470 /// ```text
471 /// TYPED_PARAMETER = KEYWORD "(" PARAMETER ")" .
472 /// ```
473 ///
474 /// and [parser::exchange::typed_parameter].
475 /// It takes only one `PARAMETER` different from [Record],
476 /// which takes many `PARAMETER`s.
477 ///
478 /// ```text
479 /// SIMPLE_RECORD = KEYWORD "(" [ PARAMETER_LIST ] ")" .
480 /// ```
481 ///
482 /// FromStr
483 /// --------
484 /// ```
485 /// use std::str::FromStr;
486 /// use ruststep::ast::Parameter;
487 ///
488 /// let p = Parameter::from_str("FILE_NAME('ruststep')").unwrap();
489 /// assert!(matches!(p, Parameter::Typed { .. }));
490 /// ```
491 ///
492 /// Deserialize
493 /// ------------
494 /// ```
495 /// use std::{str::FromStr, collections::HashMap};
496 /// use ruststep::ast::*;
497 /// use serde::Deserialize;
498 ///
499 /// // Regarded as a map `{ "A": [1, 2] }` in serde data model
500 /// let p = Parameter::from_str("A((1, 2))").unwrap();
501 ///
502 /// // Map can be deserialize as a hashmap
503 /// assert_eq!(
504 /// HashMap::<String, Vec<i32>>::deserialize(&p).unwrap(),
505 /// maplit::hashmap! {
506 /// "A".to_string() => vec![1, 2]
507 /// }
508 /// );
509 ///
510 /// // Map in serde can be interpreted as Rust field
511 /// #[derive(Debug, Clone, PartialEq, Deserialize)]
512 /// struct X {
513 /// #[serde(rename = "A")]
514 /// a: Vec<i32>,
515 /// }
516 /// assert_eq!(X::deserialize(&p).unwrap(), X { a: vec![1, 2] });
517 /// ```
518 ///
519 /// Different from [Record], deserializing into a struct is not supported:
520 ///
521 /// ```
522 /// use std::{str::FromStr, collections::HashMap};
523 /// use ruststep::ast::*;
524 /// use serde::Deserialize;
525 ///
526 /// let p = Parameter::from_str("A(1)").unwrap();
527 ///
528 /// #[derive(Debug, Clone, PartialEq, Deserialize)]
529 /// struct A {
530 /// x: i32,
531 /// }
532 /// assert!(A::deserialize(&p).is_err());
533 /// ```
534 ///
535 Typed {
536 keyword: String,
537 parameter: Box<Parameter>,
538 },
539
540 /// Signed integer
541 ///
542 /// FromStr
543 /// --------
544 /// ```
545 /// use std::str::FromStr;
546 /// use ruststep::ast::Parameter;
547 ///
548 /// let p = Parameter::from_str("10").unwrap();
549 /// assert_eq!(p, Parameter::Integer(10));
550 ///
551 /// let p = Parameter::from_str("-10").unwrap();
552 /// assert_eq!(p, Parameter::Integer(-10));
553 /// ```
554 ///
555 /// Deserialize
556 /// ------------
557 /// ```
558 /// use ruststep::ast::*;
559 /// use serde::Deserialize;
560 ///
561 /// let p = Parameter::Integer(2);
562 /// let a = i64::deserialize(&p).unwrap();
563 /// assert_eq!(a, 2);
564 ///
565 /// // can be deserialized as unsigned
566 /// let a = u64::deserialize(&p).unwrap();
567 /// assert_eq!(a, 2);
568 ///
569 /// // cannot be deserialized negative integer into unsigned
570 /// let p = Parameter::Integer(-2);
571 /// let a = i64::deserialize(&p).unwrap();
572 /// assert_eq!(a, -2);
573 /// assert!(u64::deserialize(&p).is_err());
574 /// ```
575 #[from]
576 Integer(i64),
577
578 /// Real number
579 ///
580 /// FromStr
581 /// --------
582 /// ```
583 /// use std::str::FromStr;
584 /// use ruststep::ast::Parameter;
585 ///
586 /// let p = Parameter::from_str("1.0").unwrap();
587 /// assert_eq!(p, Parameter::Real(1.0));
588 /// ```
589 #[from]
590 Real(f64),
591
592 /// string literal
593 ///
594 /// FromStr
595 /// --------
596 /// ```
597 /// use std::str::FromStr;
598 /// use ruststep::ast::Parameter;
599 ///
600 /// let p = Parameter::from_str("'EXAMPLE STRING'").unwrap();
601 /// assert_eq!(p, Parameter::String("EXAMPLE STRING".to_string()));
602 /// ```
603 #[from]
604 String(String),
605
606 /// Enumeration defined in EXPRESS schema, like `.TRUE.`
607 ///
608 /// FromStr
609 /// --------
610 /// ```
611 /// # use std::str::FromStr;
612 /// # use ruststep::ast::Parameter;
613 /// let p = Parameter::from_str(".TRUE.").unwrap();
614 /// assert_eq!(p, Parameter::Enumeration("TRUE".to_string()));
615 /// ```
616 ///
617 /// Deserialize
618 /// ------------
619 /// ```
620 /// use ruststep::ast::*;
621 /// use serde::Deserialize;
622 /// use std::str::FromStr;
623 ///
624 /// let p = Parameter::from_str(".A.").unwrap();
625 ///
626 /// #[derive(Debug, PartialEq, Deserialize)]
627 /// enum E {
628 /// A,
629 /// B
630 /// }
631 /// assert_eq!(E::deserialize(&p).unwrap(), E::A);
632 /// ```
633 ///
634 Enumeration(String),
635
636 /// List of parameters. This can be non-uniform.
637 ///
638 /// FromStr
639 /// --------
640 /// ```
641 /// use std::str::FromStr;
642 /// use ruststep::ast::Parameter;
643 ///
644 /// let p = Parameter::from_str("(1.0, 2, 'STRING')").unwrap();
645 /// assert_eq!(p, Parameter::List(vec![
646 /// Parameter::Real(1.0),
647 /// Parameter::Integer(2),
648 /// Parameter::String("STRING".to_string()),
649 /// ]));
650 /// ```
651 ///
652 /// Deserialize
653 /// ------------
654 /// ```
655 /// use std::str::FromStr;
656 /// use ruststep::ast::*;
657 /// use serde::Deserialize;
658 ///
659 /// let p = Parameter::from_str("(1, 2, 3)").unwrap();
660 ///
661 /// // As Vec<i32>
662 /// let a = Vec::<i32>::deserialize(&p).unwrap();
663 /// assert_eq!(a, vec![1, 2, 3]);
664 ///
665 /// // As user-defined struct
666 /// #[derive(Debug, Clone, PartialEq, Deserialize)]
667 /// struct A {
668 /// x: i32,
669 /// y: i32,
670 /// z: i32,
671 /// }
672 /// let a = A::deserialize(&p).unwrap();
673 /// assert_eq!(a, A { x: 1, y: 2, z: 3 });
674 /// ```
675 #[from]
676 List(Vec<Parameter>),
677
678 /// A reference to entity or value
679 ///
680 /// Deserialize
681 /// ------------
682 /// ```
683 /// use ruststep::ast::*;
684 /// use serde::Deserialize;
685 /// use std::str::FromStr;
686 ///
687 /// let p = Parameter::from_str("#12").unwrap();
688 ///
689 /// #[derive(Debug, PartialEq, Deserialize)]
690 /// enum Id {
691 /// #[serde(rename = "Entity")] // "Entity" is keyword for entity reference
692 /// E(usize),
693 /// #[serde(rename = "Value")] // "Value" is keyword for value reference
694 /// V(usize),
695 /// }
696 /// assert_eq!(Id::deserialize(&p).unwrap(), Id::E(12));
697 /// ```
698 #[from]
699 Ref(Name),
700
701 /// The special token dollar sign (`$`) is used to represent
702 /// an object whose value is not provided in the exchange structure.
703 ///
704 /// Deserialize
705 /// -----------
706 /// ```
707 /// use ruststep::ast::*;
708 /// use serde::Deserialize;
709 ///
710 /// let p = Parameter::NotProvided;
711 /// assert_eq!(Option::<i64>::deserialize(&p).unwrap(), None);
712 /// ```
713 NotProvided,
714
715 /// Omitted parameter denoted by `*`
716 ///
717 /// Deserialize
718 /// ------------
719 /// ```
720 /// use ruststep::ast::*;
721 /// use serde::Deserialize;
722 ///
723 /// let p = Parameter::Omitted;
724 /// assert_eq!(Option::<i64>::deserialize(&p).unwrap(), None);
725 /// ```
726 Omitted,
727}
728
729impl Parameter {
730 pub fn integer(i: i64) -> Self {
731 Parameter::Integer(i)
732 }
733
734 pub fn real(x: f64) -> Self {
735 Parameter::Real(x)
736 }
737
738 pub fn string(s: &str) -> Self {
739 Parameter::String(s.to_string())
740 }
741}
742
743impl std::iter::FromIterator<Parameter> for Parameter {
744 fn from_iter<Iter: IntoIterator<Item = Parameter>>(iter: Iter) -> Self {
745 Parameter::List(iter.into_iter().collect())
746 }
747}
748
749impl<'a> std::iter::FromIterator<&'a Parameter> for Parameter {
750 fn from_iter<Iter: IntoIterator<Item = &'a Parameter>>(iter: Iter) -> Self {
751 iter.into_iter().cloned().collect()
752 }
753}
754
755derive_ast_from_str!(Parameter, parser::exchange::parameter);
756
757/// Entire exchange structure
758#[derive(Debug, Clone, PartialEq)]
759pub struct Exchange {
760 /// `HEADER` section
761 pub header: Vec<Record>,
762 /// `ANCHOR` section
763 pub anchor: Vec<Anchor>,
764 /// `REFERENCE` section
765 pub reference: Vec<ReferenceEntry>,
766 /// `DATA` section
767 pub data: Vec<DataSection>,
768 /// `SIGNATURE` section
769 pub signature: Vec<String>,
770}
771derive_ast_from_str!(Exchange, parser::exchange::exchange_file);
772
773/// Each line of data section
774#[derive(Debug, Clone, PartialEq)]
775pub enum EntityInstance {
776 Simple { id: u64, record: Record },
777 Complex { id: u64, subsuper: SubSuperRecord },
778}
779derive_ast_from_str!(EntityInstance, parser::exchange::entity_instance);
780
781#[derive(Debug, Clone, PartialEq)]
782pub struct ReferenceEntry {
783 pub name: Name,
784 pub resource: URI,
785}
786derive_ast_from_str!(ReferenceEntry, parser::exchange::reference);
787
788#[derive(Debug, Clone, PartialEq)]
789pub struct URI(pub String);
790
791#[derive(Debug, Clone, PartialEq)]
792pub struct Anchor {
793 pub name: String,
794 pub item: AnchorItem,
795 pub tags: Vec<(String, AnchorItem)>,
796}
797derive_ast_from_str!(Anchor, parser::exchange::anchor);
798
799#[derive(Debug, Clone, PartialEq)]
800pub enum AnchorItem {
801 Integer(i64),
802 Real(f64),
803 String(String),
804 Enumeration(String),
805 /// The special token dollar sign (`$`) is used to represent an object whose value is not provided in the exchange structure.
806 NotProvided,
807 /// A reference to entity or value
808 Name(Name),
809 /// List of other parameters
810 List(Vec<AnchorItem>),
811}
812derive_ast_from_str!(AnchorItem, parser::exchange::anchor_item);