ifc_tabular/read/
series.rs1use ifc_model::{Entity, EntityId, Model, Value};
11use ifc_schema::Schema;
12
13use super::decode::{Need, Slots};
14use super::issue::TabularIssue;
15
16pub(crate) const REGULAR: &str = "IFCREGULARTIMESERIES";
17pub(crate) const IRREGULAR: &str = "IFCIRREGULARTIMESERIES";
18const VALUE: &str = "IFCTIMESERIESVALUE";
19const IRREGULAR_VALUE: &str = "IFCIRREGULARTIMESERIESVALUE";
20
21#[derive(Debug, Clone, Copy, PartialEq)]
23#[non_exhaustive]
24pub enum TimeSeriesKind {
25 Regular {
27 time_step: Option<f64>,
29 },
30 Irregular,
32}
33
34#[derive(Debug, Clone)]
37pub struct TimeSeries<'m> {
38 id: EntityId,
39 kind: TimeSeriesKind,
40 name: Option<&'m str>,
41 description: Option<&'m str>,
42 start_time: Option<&'m str>,
43 end_time: Option<&'m str>,
44 data_type: Option<&'m str>,
45 data_origin: Option<&'m str>,
46 user_defined_data_origin: Option<&'m str>,
47 unit: Option<EntityId>,
48 values: Vec<SeriesValue<'m>>,
49 issues: Vec<TabularIssue>,
50}
51
52impl<'m> TimeSeries<'m> {
53 #[must_use]
55 pub const fn id(&self) -> EntityId {
56 self.id
57 }
58
59 #[must_use]
61 pub const fn kind(&self) -> TimeSeriesKind {
62 self.kind
63 }
64
65 #[must_use]
67 pub const fn name(&self) -> Option<&'m str> {
68 self.name
69 }
70
71 #[must_use]
73 pub const fn description(&self) -> Option<&'m str> {
74 self.description
75 }
76
77 #[must_use]
79 pub const fn start_time(&self) -> Option<&'m str> {
80 self.start_time
81 }
82
83 #[must_use]
85 pub const fn end_time(&self) -> Option<&'m str> {
86 self.end_time
87 }
88
89 #[must_use]
91 pub const fn data_type(&self) -> Option<&'m str> {
92 self.data_type
93 }
94
95 #[must_use]
97 pub const fn data_origin(&self) -> Option<&'m str> {
98 self.data_origin
99 }
100
101 #[must_use]
103 pub const fn user_defined_data_origin(&self) -> Option<&'m str> {
104 self.user_defined_data_origin
105 }
106
107 #[must_use]
109 pub const fn unit(&self) -> Option<EntityId> {
110 self.unit
111 }
112
113 #[must_use]
116 pub fn values(&self) -> &[SeriesValue<'m>] {
117 &self.values
118 }
119
120 #[must_use]
122 pub fn issues(&self) -> &[TabularIssue] {
123 &self.issues
124 }
125}
126
127#[derive(Debug, Clone, Copy)]
129pub struct SeriesValue<'m> {
130 id: EntityId,
131 timestamp: Option<&'m str>,
132 values: Option<&'m [Value]>,
133}
134
135impl<'m> SeriesValue<'m> {
136 #[must_use]
138 pub const fn id(&self) -> EntityId {
139 self.id
140 }
141
142 #[must_use]
145 pub const fn timestamp(&self) -> Option<&'m str> {
146 self.timestamp
147 }
148
149 #[must_use]
151 pub const fn values(&self) -> Option<&'m [Value]> {
152 self.values
153 }
154}
155
156pub(crate) fn read_series<'m>(
158 model: &'m Model,
159 schema: &'m Schema,
160 id: EntityId,
161 entity: &'m Entity,
162 type_name: &'static str,
163) -> TimeSeries<'m> {
164 let regular = type_name == REGULAR;
165 let mut issues = Vec::new();
166 let mut slots = Slots::open(model, schema, id, entity, type_name, &mut issues);
167 let name = slots.text("Name", Need::Required);
168 let description = slots.text("Description", Need::Optional);
169 let start_time = slots.text("StartTime", Need::Required);
170 let end_time = slots.text("EndTime", Need::Required);
171 let data_type = slots.enumeration("TimeSeriesDataType", Need::Required);
172 let data_origin = slots.enumeration("DataOrigin", Need::Required);
173 let user_defined_data_origin = slots.text("UserDefinedDataOrigin", Need::Optional);
174 let unit = slots.reference("Unit", Need::Optional);
175 let kind = if regular {
176 TimeSeriesKind::Regular {
177 time_step: slots.number("TimeStep", Need::Required),
178 }
179 } else {
180 TimeSeriesKind::Irregular
181 };
182 let value_type = if regular { VALUE } else { IRREGULAR_VALUE };
183 let members = slots.records("Values", Need::Required, value_type);
184
185 let values = members
186 .into_iter()
187 .flatten()
188 .map(|(value, record)| {
189 let mut slots = Slots::open(model, schema, value, record, value_type, &mut issues);
190 SeriesValue {
191 id: value,
192 timestamp: if regular {
193 None
194 } else {
195 slots.text("TimeStamp", Need::Required)
196 },
197 values: slots.values("ListValues", Need::Required),
198 }
199 })
200 .collect();
201
202 TimeSeries {
203 id,
204 kind,
205 name,
206 description,
207 start_time,
208 end_time,
209 data_type,
210 data_origin,
211 user_defined_data_origin,
212 unit,
213 values,
214 issues,
215 }
216}