1use indexmap::IndexMap;
9use serde::{Deserialize, Serialize};
10use serde_json::{Map, Number, Value};
11
12pub type Extra = Map<String, Value>;
14
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct IfcxFile {
18 pub header: IfcxHeader,
19 pub imports: Vec<ImportNode>,
20 pub schemas: IndexMap<String, IfcxSchema>,
22 pub data: Vec<IfcxNode>,
25 #[serde(flatten)]
26 pub extra: Extra,
27}
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
30pub struct IfcxHeader {
31 pub id: String,
33 #[serde(rename = "ifcxVersion")]
35 pub ifcx_version: String,
36 #[serde(rename = "dataVersion")]
37 pub data_version: String,
38 pub author: String,
39 pub timestamp: String,
41 #[serde(flatten)]
42 pub extra: Extra,
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
47pub struct ImportNode {
48 pub uri: String,
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub integrity: Option<String>,
51 #[serde(flatten)]
52 pub extra: Extra,
53}
54
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct IfcxNode {
59 pub path: String,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub children: Option<IndexMap<String, Option<String>>>,
62 #[serde(default, skip_serializing_if = "Option::is_none")]
63 pub inherits: Option<IndexMap<String, Option<String>>>,
64 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub attributes: Option<IndexMap<String, Value>>,
67 #[serde(flatten)]
68 pub extra: Extra,
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
73pub struct IfcxSchema {
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub uri: Option<String>,
76 pub value: IfcxValueDescription,
77 #[serde(flatten)]
78 pub extra: Extra,
79}
80
81#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
82pub struct IfcxValueDescription {
83 #[serde(rename = "dataType")]
84 pub data_type: DataType,
85 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub optional: Option<bool>,
87 #[serde(default, skip_serializing_if = "Option::is_none")]
88 pub inherits: Option<Vec<String>>,
89 #[serde(
91 rename = "quantityKind",
92 default,
93 skip_serializing_if = "Option::is_none"
94 )]
95 pub quantity_kind: Option<String>,
96 #[serde(
97 rename = "enumRestrictions",
98 default,
99 skip_serializing_if = "Option::is_none"
100 )]
101 pub enum_restrictions: Option<EnumRestrictions>,
102 #[serde(
103 rename = "arrayRestrictions",
104 default,
105 skip_serializing_if = "Option::is_none"
106 )]
107 pub array_restrictions: Option<Box<ArrayRestrictions>>,
108 #[serde(
109 rename = "objectRestrictions",
110 default,
111 skip_serializing_if = "Option::is_none"
112 )]
113 pub object_restrictions: Option<ObjectRestrictions>,
114 #[serde(flatten)]
115 pub extra: Extra,
116}
117
118#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub struct EnumRestrictions {
120 pub options: Vec<String>,
121 #[serde(flatten)]
122 pub extra: Extra,
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
126pub struct ArrayRestrictions {
127 #[serde(default, skip_serializing_if = "Option::is_none")]
128 pub min: Option<Number>,
129 #[serde(default, skip_serializing_if = "Option::is_none")]
130 pub max: Option<Number>,
131 pub value: IfcxValueDescription,
132 #[serde(flatten)]
133 pub extra: Extra,
134}
135
136#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
137pub struct ObjectRestrictions {
138 pub values: IndexMap<String, IfcxValueDescription>,
139 #[serde(flatten)]
140 pub extra: Extra,
141}
142
143#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
146#[serde(from = "String", into = "String")]
147pub enum DataType {
148 Real,
149 Boolean,
150 Integer,
151 String,
152 DateTime,
153 Enum,
154 Array,
155 Object,
156 Reference,
157 Blob,
158 Other(String),
159}
160
161impl DataType {
162 pub fn as_str(&self) -> &str {
163 match self {
164 Self::Real => "Real",
165 Self::Boolean => "Boolean",
166 Self::Integer => "Integer",
167 Self::String => "String",
168 Self::DateTime => "DateTime",
169 Self::Enum => "Enum",
170 Self::Array => "Array",
171 Self::Object => "Object",
172 Self::Reference => "Reference",
173 Self::Blob => "Blob",
174 Self::Other(name) => name,
175 }
176 }
177}
178
179impl From<String> for DataType {
180 fn from(name: String) -> Self {
181 match name.as_str() {
182 "Real" => Self::Real,
183 "Boolean" => Self::Boolean,
184 "Integer" => Self::Integer,
185 "String" => Self::String,
186 "DateTime" => Self::DateTime,
187 "Enum" => Self::Enum,
188 "Array" => Self::Array,
189 "Object" => Self::Object,
190 "Reference" => Self::Reference,
191 "Blob" => Self::Blob,
192 _ => Self::Other(name),
193 }
194 }
195}
196
197impl From<DataType> for String {
198 fn from(data_type: DataType) -> Self {
199 match data_type {
200 DataType::Other(name) => name,
201 known => known.as_str().to_owned(),
202 }
203 }
204}