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