ifc_lite_export/step_log/
wire.rs1use serde::{Deserialize, Deserializer, Serialize};
23use serde_json::Value;
24
25fn present<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Value>, D::Error> {
29 Value::deserialize(d).map(Some)
30}
31
32#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35#[non_exhaustive]
36pub struct MutationLog {
37 #[serde(default)]
39 pub model_id: String,
40 #[serde(default)]
42 pub mutations: Vec<LogMutation>,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub exported_at: Option<f64>,
46 #[serde(default, skip_serializing_if = "Vec::is_empty")]
48 pub new_entities: Vec<LogNewEntity>,
49 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub georef_mutations: Option<GeorefMutations>,
52}
53
54impl MutationLog {
55 pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
60 serde_json::from_str(json)
61 }
62
63 pub fn new(mutations: Vec<LogMutation>) -> Self {
65 MutationLog { mutations, ..MutationLog::default() }
66 }
67
68 pub fn with_new_entities(mut self, entities: Vec<LogNewEntity>) -> Self {
70 self.new_entities = entities;
71 self
72 }
73
74 pub fn with_georef_mutations(mut self, georef: GeorefMutations) -> Self {
76 self.georef_mutations = Some(georef);
77 self
78 }
79
80 pub fn is_empty(&self) -> bool {
82 self.mutations.is_empty() && self.new_entities.is_empty() && self.georef_mutations.is_none()
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
88#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
89#[non_exhaustive]
90pub enum MutationKind {
91 CreateProperty,
92 UpdateProperty,
93 DeleteProperty,
94 CreatePropertySet,
95 DeletePropertySet,
96 CreateQuantity,
97 UpdateQuantity,
98 DeleteQuantity,
99 DeleteQuantitySet,
100 UpdateAttribute,
101 UpdatePositionalAttribute,
102 UpdateEntityType,
103 CreateEntity,
104 DeleteEntity,
105 #[serde(other)]
107 Unknown,
108}
109
110#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
115#[serde(rename_all = "camelCase")]
116#[non_exhaustive]
117pub struct LogMutation {
118 #[serde(default)]
119 pub id: String,
120 #[serde(rename = "type")]
121 pub kind: MutationKind,
122 #[serde(default)]
123 pub timestamp: f64,
124 #[serde(default)]
125 pub model_id: String,
126 pub entity_id: u32,
127 #[serde(default, skip_serializing_if = "Option::is_none")]
128 pub pset_name: Option<String>,
129 #[serde(default, skip_serializing_if = "Option::is_none")]
130 pub prop_name: Option<String>,
131 #[serde(default, deserialize_with = "present", skip_serializing_if = "Option::is_none")]
132 pub old_value: Option<Value>,
133 #[serde(default, deserialize_with = "present", skip_serializing_if = "Option::is_none")]
134 pub new_value: Option<Value>,
135 #[serde(default, skip_serializing_if = "Option::is_none")]
137 pub value_type: Option<f64>,
138 #[serde(default, skip_serializing_if = "Option::is_none")]
140 pub quantity_type: Option<f64>,
141 #[serde(default, skip_serializing_if = "Option::is_none")]
142 pub unit: Option<String>,
143 #[serde(default, skip_serializing_if = "Option::is_none")]
144 pub attribute_name: Option<String>,
145 #[serde(default, skip_serializing_if = "Option::is_none")]
146 pub entity_type: Option<String>,
147 #[serde(default, skip_serializing_if = "Option::is_none")]
148 pub predefined_type: Option<String>,
149}
150
151impl LogMutation {
152 pub fn new(kind: MutationKind, entity_id: u32) -> Self {
154 LogMutation {
155 id: String::new(),
156 kind,
157 timestamp: 0.0,
158 model_id: String::new(),
159 entity_id,
160 pset_name: None,
161 prop_name: None,
162 old_value: None,
163 new_value: None,
164 value_type: None,
165 quantity_type: None,
166 unit: None,
167 attribute_name: None,
168 entity_type: None,
169 predefined_type: None,
170 }
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
179#[serde(rename_all = "camelCase")]
180#[non_exhaustive]
181pub struct LogNewEntity {
182 pub express_id: u32,
183 #[serde(rename = "type")]
184 pub entity_type: String,
185 #[serde(default)]
186 pub attributes: Vec<Value>,
187}
188
189impl LogNewEntity {
190 pub fn new(express_id: u32, entity_type: impl Into<String>, attributes: Vec<Value>) -> Self {
191 LogNewEntity { express_id, entity_type: entity_type.into(), attributes }
192 }
193}
194
195#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
200#[serde(rename_all = "camelCase")]
201#[non_exhaustive]
202pub struct GeorefMutations {
203 #[serde(default, rename = "projectedCRS", skip_serializing_if = "Option::is_none")]
204 pub projected_crs: Option<serde_json::Map<String, Value>>,
205 #[serde(default, skip_serializing_if = "Option::is_none")]
206 pub map_conversion: Option<serde_json::Map<String, Value>>,
207}
208
209impl GeorefMutations {
210 pub fn new(
211 projected_crs: Option<serde_json::Map<String, Value>>,
212 map_conversion: Option<serde_json::Map<String, Value>>,
213 ) -> Self {
214 GeorefMutations { projected_crs, map_conversion }
215 }
216}