use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Number, Value};
pub type Extra = Map<String, Value>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IfcxFile {
pub header: IfcxHeader,
pub imports: Vec<ImportNode>,
pub schemas: IndexMap<String, IfcxSchema>,
pub data: Vec<IfcxNode>,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IfcxHeader {
pub id: String,
#[serde(rename = "ifcxVersion")]
pub ifcx_version: String,
#[serde(rename = "dataVersion")]
pub data_version: String,
pub author: String,
pub timestamp: String,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ImportNode {
pub uri: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub integrity: Option<String>,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IfcxNode {
pub path: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub children: Option<IndexMap<String, Option<String>>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub inherits: Option<IndexMap<String, Option<String>>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub attributes: Option<IndexMap<String, Value>>,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IfcxSchema {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub uri: Option<String>,
pub value: IfcxValueDescription,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IfcxValueDescription {
#[serde(rename = "dataType")]
pub data_type: DataType,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub optional: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub inherits: Option<Vec<String>>,
#[serde(
rename = "quantityKind",
default,
skip_serializing_if = "Option::is_none"
)]
pub quantity_kind: Option<String>,
#[serde(
rename = "enumRestrictions",
default,
skip_serializing_if = "Option::is_none"
)]
pub enum_restrictions: Option<EnumRestrictions>,
#[serde(
rename = "arrayRestrictions",
default,
skip_serializing_if = "Option::is_none"
)]
pub array_restrictions: Option<Box<ArrayRestrictions>>,
#[serde(
rename = "objectRestrictions",
default,
skip_serializing_if = "Option::is_none"
)]
pub object_restrictions: Option<ObjectRestrictions>,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EnumRestrictions {
pub options: Vec<String>,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ArrayRestrictions {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub min: Option<Number>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max: Option<Number>,
pub value: IfcxValueDescription,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ObjectRestrictions {
pub values: IndexMap<String, IfcxValueDescription>,
#[serde(flatten)]
pub extra: Extra,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(from = "String", into = "String")]
pub enum DataType {
Real,
Boolean,
Integer,
String,
DateTime,
Enum,
Array,
Object,
Reference,
Blob,
Other(String),
}
impl DataType {
pub fn as_str(&self) -> &str {
match self {
Self::Real => "Real",
Self::Boolean => "Boolean",
Self::Integer => "Integer",
Self::String => "String",
Self::DateTime => "DateTime",
Self::Enum => "Enum",
Self::Array => "Array",
Self::Object => "Object",
Self::Reference => "Reference",
Self::Blob => "Blob",
Self::Other(name) => name,
}
}
}
impl From<String> for DataType {
fn from(name: String) -> Self {
match name.as_str() {
"Real" => Self::Real,
"Boolean" => Self::Boolean,
"Integer" => Self::Integer,
"String" => Self::String,
"DateTime" => Self::DateTime,
"Enum" => Self::Enum,
"Array" => Self::Array,
"Object" => Self::Object,
"Reference" => Self::Reference,
"Blob" => Self::Blob,
_ => Self::Other(name),
}
}
}
impl From<DataType> for String {
fn from(data_type: DataType) -> Self {
match data_type {
DataType::Other(name) => name,
known => known.as_str().to_owned(),
}
}
}