1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Header section of exchange structure
//!
//! `HEADER` section of exchange structure shall contains
//! one instance of each of following entities in this order:
//!
//! - `file_description`
//! - `file_name`
//! - `file_schema`
//!
//! and following entities may appear after `file_schema`:
//!
//! - `schema_population`
//! - `file_population`
//! - `section_language`
//! - `section_context`
//!
//! These entities are defined in [ISO-10303-21 "8.2 Header section declarations"](https://www.iso.org/standard/63141.html)
//! using EXPRESS schemas.
//! Although we can generate corresponding Rust struct using espr compiler,
//! we write these definitions manually to keep development process simple.
//!

use crate::{ast::*, error::Result};
use serde::Deserialize;

/// File description
///
/// Following EXPRESS schema is an exerpt from
/// [ISO-10303-21:2016(E) "8.2.2 file_description"](https://www.iso.org/standard/63141.html):
///
/// ```text
/// ENTITY file_description;
///   description          : LIST [1:?] OF STRING (256) ;
///   implementation_level : STRING (256) ;
/// END_ENTITY;
/// ```
#[derive(Debug, Clone, PartialEq, ruststep_derive::Deserialize)]
pub struct FileDescription {
    pub description: Vec<String>,
    pub implementation_level: String,
}

/// File name
///
/// Following EXPRESS schema is an exerpt from
/// [ISO-10303-21:2016(E) "8.2.3 file_name"](https://www.iso.org/standard/63141.html):
///
/// ```text
/// ENTITY file_name;
///   name                 : STRING (256) ;
///   time_stamp           : time_stamp_text ;
///   author               : LIST [ 1 : ? ] OF STRING (256) ;
///   organization         : LIST [ 1 : ? ] OF STRING (256) ;
///   preprocessor_version : STRING (256) ;
///   originating_system   : STRING (256) ;
///   authorization        : STRING (256) ;
/// END_ENTITY;
///
/// TYPE time_stamp_text = STRING(256);
/// END_TYPE;
/// ```
#[derive(Debug, Clone, PartialEq, ruststep_derive::Deserialize)]
pub struct FileName {
    pub name: String,
    /// ISO-8601 formatted date and time specifying when the exchange structure was created.
    pub time_stamp: String,
    pub author: Vec<String>,
    pub organization: Vec<String>,
    pub preprocessor_version: String,
    pub originating_system: String,
    pub authorization: String,
}

/// File schema
///
/// Following EXPRESS schema is an exerpt from
/// [ISO-10303-21:2016(E) "8.2.4 file_schema"](https://www.iso.org/standard/63141.html):
///
/// ```text
/// ENTITY file_schema;
///   schema_identifiers : LIST [1:?] OF UNIQUE schema_name;
/// END_ENTITY;
///
/// TYPE schema_name = STRING(1024);
/// END_TYPE;
/// ```
#[derive(Debug, Clone, PartialEq, ruststep_derive::Deserialize)]
pub struct FileSchema {
    pub schema: Vec<String>,
}

/// STEP-file HEADER section
///
/// There is a schema for HEADER section,
/// but we do not generate this structure from it to simplify build process.
///
#[derive(Debug, Clone, PartialEq)]
pub struct Header {
    pub file_description: FileDescription,
    pub file_name: FileName,
    pub file_schema: FileSchema,
}

impl Header {
    pub fn from_records(records: &[Record]) -> Result<Self> {
        assert!(records.len() >= 3);
        let file_description = FileDescription::deserialize(&records[0])?;
        let file_name = FileName::deserialize(&records[1])?;
        let file_schema = FileSchema::deserialize(&records[2])?;
        Ok(Header {
            file_description,
            file_name,
            file_schema,
        })
    }
}

#[cfg(test)]
mod tests {
    use nom::Finish;

    #[test]
    fn header() {
        // From ABC dataset example
        let header = r#"
        HEADER;
            FILE_DESCRIPTION( ( '' ), ' ' );
            FILE_NAME( '/vol/tmp/translate-2747021839723325609/5ae2de121ced560fc658f4c5.step', '2018-04-27T08:23:47', ( '' ), ( '' ), ' ', ' ', ' ' );
            FILE_SCHEMA( ( 'AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }' ) );
        ENDSEC;
        "#.trim();
        let (_residual, records) = crate::parser::exchange::header_section(header)
            .finish()
            .unwrap();
        let header = super::Header::from_records(&records).unwrap();
        dbg!(header);
    }
}