step_p21/header.rs
1//! Header section of exchange structure
2//!
3//! `HEADER` section of exchange structure shall contains
4//! one instance of each of following entities in this order:
5//!
6//! - `file_description`
7//! - `file_name`
8//! - `file_schema`
9//!
10//! and following entities may appear after `file_schema`:
11//!
12//! - `schema_population`
13//! - `file_population`
14//! - `section_language`
15//! - `section_context`
16//!
17//! These entities are defined in [ISO-10303-21 "8.2 Header section declarations"](https://www.iso.org/standard/63141.html)
18//! using EXPRESS schemas.
19//! Although we can generate corresponding Rust struct using step_p11 compiler,
20//! we write these definitions manually to keep development process simple.
21
22use crate::{ast::*, error::Result};
23use serde::Deserialize;
24
25/// File description
26///
27/// Following EXPRESS schema is an exerpt from
28/// [ISO-10303-21:2016(E) "8.2.2 file_description"](https://www.iso.org/standard/63141.html):
29///
30/// ```text
31/// ENTITY file_description;
32/// description : LIST [1:?] OF STRING (256) ;
33/// implementation_level : STRING (256) ;
34/// END_ENTITY;
35/// ```
36#[derive(Debug, Clone, PartialEq, step_p21_derive::Deserialize)]
37pub struct FileDescription {
38 pub description: Vec<String>,
39 pub implementation_level: String,
40}
41
42/// File name
43///
44/// Following EXPRESS schema is an exerpt from
45/// [ISO-10303-21:2016(E) "8.2.3 file_name"](https://www.iso.org/standard/63141.html):
46///
47/// ```text
48/// ENTITY file_name;
49/// name : STRING (256) ;
50/// time_stamp : time_stamp_text ;
51/// author : LIST [ 1 : ? ] OF STRING (256) ;
52/// organization : LIST [ 1 : ? ] OF STRING (256) ;
53/// preprocessor_version : STRING (256) ;
54/// originating_system : STRING (256) ;
55/// authorization : STRING (256) ;
56/// END_ENTITY;
57///
58/// TYPE time_stamp_text = STRING(256);
59/// END_TYPE;
60/// ```
61#[derive(Debug, Clone, PartialEq, step_p21_derive::Deserialize)]
62pub struct FileName {
63 pub name: String,
64 /// ISO-8601 formatted date and time specifying when the exchange structure
65 /// was created.
66 pub time_stamp: String,
67 pub author: Vec<String>,
68 pub organization: Vec<String>,
69 pub preprocessor_version: String,
70 pub originating_system: String,
71 pub authorization: String,
72}
73
74/// File schema
75///
76/// Following EXPRESS schema is an exerpt from
77/// [ISO-10303-21:2016(E) "8.2.4 file_schema"](https://www.iso.org/standard/63141.html):
78///
79/// ```text
80/// ENTITY file_schema;
81/// schema_identifiers : LIST [1:?] OF UNIQUE schema_name;
82/// END_ENTITY;
83///
84/// TYPE schema_name = STRING(1024);
85/// END_TYPE;
86/// ```
87#[derive(Debug, Clone, PartialEq, step_p21_derive::Deserialize)]
88pub struct FileSchema {
89 pub schema: Vec<String>,
90}
91
92/// STEP-file HEADER section
93///
94/// There is a schema for HEADER section,
95/// but we do not generate this structure from it to simplify build process.
96#[derive(Debug, Clone, PartialEq)]
97pub struct Header {
98 pub file_description: FileDescription,
99 pub file_name: FileName,
100 pub file_schema: FileSchema,
101}
102
103impl Header {
104 pub fn from_records(records: &[Record]) -> Result<Self> {
105 assert!(records.len() >= 3);
106 let file_description = FileDescription::deserialize(&records[0])?;
107 let file_name = FileName::deserialize(&records[1])?;
108 let file_schema = FileSchema::deserialize(&records[2])?;
109 Ok(Header {
110 file_description,
111 file_name,
112 file_schema,
113 })
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use nom::Finish;
120
121 #[test]
122 fn header() {
123 // From ABC dataset example
124 let header = r#"
125 HEADER;
126 FILE_DESCRIPTION( ( '' ), ' ' );
127 FILE_NAME( '/vol/tmp/translate-2747021839723325609/5ae2de121ced560fc658f4c5.step', '2018-04-27T08:23:47', ( '' ), ( '' ), ' ', ' ', ' ' );
128 FILE_SCHEMA( ( 'AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }' ) );
129 ENDSEC;
130 "#.trim();
131 let (_residual, records) =
132 crate::parser::exchange::header_section(header)
133 .finish()
134 .unwrap();
135 let header = super::Header::from_records(&records).unwrap();
136 dbg!(header);
137 }
138}