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);