1use anyhow::Context;
4use arrow::{
5 array::{
6 ArrayRef, AsArray, BinaryBuilder, BooleanBuilder, Float32Array, Float32Builder,
7 Float64Array, Float64Builder, Int8Builder, Int16Builder, Int32Builder, Int64Builder,
8 StringBuilder, UInt8Array, UInt8Builder, UInt16Array, UInt16Builder, UInt32Array,
9 UInt32Builder, UInt64Array, UInt64Builder, downcast_array,
10 },
11 datatypes::{
12 DataType, Float32Type, Float64Type, Int8Type, Int16Type, Int32Type, Int64Type, UInt8Type,
13 UInt16Type, UInt32Type, UInt64Type,
14 },
15};
16
17use crate::sim::{
18 RecorderState,
19 interpolation::{Interpolate, PreLookup},
20 io::Recorder,
21 traits::{InstRecordValues, InstSetValues},
22};
23
24use fmi::{fmi3::GetSet, traits::FmiInstance};
25
26use itertools::Itertools;
27
28const DEFAULT_BINARY_BUFFER_SIZE: usize = 1024;
29
30macro_rules! impl_recorder {
31 ($getter:ident, $builder_type:ident, $inst:expr, $vr:ident, $builder:ident) => {{
32 let mut value = [std::default::Default::default()];
33 $inst.$getter(&[*$vr], &mut value)?;
34 $builder
35 .as_any_mut()
36 .downcast_mut::<$builder_type>()
37 .expect(concat!("column is not ", stringify!($builder_type)))
38 .append_value(value[0]);
39 }};
40}
41
42macro_rules! impl_record_values {
43 ($inst:ty) => {
44 impl InstRecordValues for $inst {
45 fn record_outputs(
46 &mut self,
47 time: f64,
48 recorder: &mut RecorderState<Self>,
49 ) -> anyhow::Result<()> {
50 log::trace!("Recording variables at time {}", time);
51
52 recorder.time.append_value(time);
53 for Recorder {
54 field,
55 value_reference: vr,
56 builder,
57 binary_max_size,
58 } in &mut recorder.recorders
59 {
60 log::trace!(
61 "Recording variable VR={} of type {:?}",
62 vr,
63 field.data_type()
64 );
65 match field.data_type() {
66 DataType::Boolean => {
67 impl_recorder!(get_boolean, BooleanBuilder, self, vr, builder)
68 }
69 DataType::Int8 => {
70 impl_recorder!(get_int8, Int8Builder, self, vr, builder)
71 }
72 DataType::Int16 => {
73 impl_recorder!(get_int16, Int16Builder, self, vr, builder)
74 }
75 DataType::Int32 => {
76 impl_recorder!(get_int32, Int32Builder, self, vr, builder)
77 }
78 DataType::Int64 => {
79 impl_recorder!(get_int64, Int64Builder, self, vr, builder)
80 }
81 DataType::UInt8 => {
82 impl_recorder!(get_uint8, UInt8Builder, self, vr, builder)
83 }
84 DataType::UInt16 => {
85 impl_recorder!(get_uint16, UInt16Builder, self, vr, builder)
86 }
87 DataType::UInt32 => {
88 impl_recorder!(get_uint32, UInt32Builder, self, vr, builder)
89 }
90 DataType::UInt64 => {
91 impl_recorder!(get_uint64, UInt64Builder, self, vr, builder)
92 }
93 DataType::Float32 => {
94 impl_recorder!(get_float32, Float32Builder, self, vr, builder)
95 }
96 DataType::Float64 => {
97 impl_recorder!(get_float64, Float64Builder, self, vr, builder)
98 }
99 DataType::Binary => {
100 let buffer_len = binary_max_size.unwrap_or(DEFAULT_BINARY_BUFFER_SIZE);
101 let mut data = vec![0u8; buffer_len];
102 let mut value = [data.as_mut_slice()];
103 let sizes = self
104 .get_binary(&[*vr], &mut value)
105 .context("Failed to get binary data")?;
106 let actual_size = sizes.get(0).copied().unwrap_or(0);
107 data.truncate(actual_size);
108 builder
109 .as_any_mut()
110 .downcast_mut::<BinaryBuilder>()
111 .expect("column is not Binary")
112 .append_value(data);
113 }
114 DataType::Utf8 => {
115 let mut values = [std::ffi::CString::new("").unwrap()];
116 let _ = self.get_string(&[*vr], &mut values);
117 let string_value = values[0].to_string_lossy();
118 builder
119 .as_any_mut()
120 .downcast_mut::<StringBuilder>()
121 .expect("column is not Utf8")
122 .append_value(string_value);
123 }
124 _ => unimplemented!("Unsupported data type: {:?}", field.data_type()),
125 }
126 }
127 Ok(())
128 }
129 }
130 };
131}
132
133macro_rules! impl_set_values {
134 ($t:ty) => {
135 impl InstSetValues for $t {
136 fn set_array(&mut self, vrs: &[Self::ValueRef], values: &ArrayRef) {
137 match values.data_type() {
138 DataType::Boolean => {
139 let values = values.as_boolean().iter().map(|x| x.unwrap()).collect_vec();
140 self.set_boolean(vrs, &values).unwrap();
141 }
142 DataType::Int8 => {
143 self.set_int8(vrs, values.as_primitive::<Int8Type>().values()).unwrap();
144 }
145 DataType::Int16 => {
146 self.set_int16(vrs, values.as_primitive::<Int16Type>().values()).unwrap();
147 }
148 DataType::Int32 => {
149 self.set_int32(vrs, values.as_primitive::<Int32Type>().values()).unwrap();
150 }
151 DataType::Int64 => {
152 self.set_int64(vrs, values.as_primitive::<Int64Type>().values()).unwrap();
153 }
154 DataType::UInt8 => {
155 self.set_uint8(vrs, values.as_primitive::<UInt8Type>().values()).unwrap();
156 }
157 DataType::UInt16 => {
158 self.set_uint16(vrs, values.as_primitive::<UInt16Type>().values()).unwrap();
159 }
160 DataType::UInt32 => {
161 self.set_uint32(vrs, values.as_primitive::<UInt32Type>().values()).unwrap();
162 }
163 DataType::UInt64 => {
164 self.set_uint64(vrs, values.as_primitive::<UInt64Type>().values()).unwrap();
165 }
166 DataType::Float16 => {
167 unimplemented!()
168 }
169 DataType::Float32 => {
170 self.set_float32(vrs, values.as_primitive::<Float32Type>().values()).unwrap();
171 }
172 DataType::Float64 => {
173 self.set_float64(vrs, values.as_primitive::<Float64Type>().values()).unwrap();
174 }
175 DataType::Binary => {
176 let binary_refs: Vec<&[u8]> = values
177 .as_binary::<i32>()
178 .iter()
179 .filter_map(|opt| opt) .collect();
181 let _ = self.set_binary(vrs, &binary_refs);
182 }
183 DataType::FixedSizeBinary(_) => todo!(),
184 DataType::LargeBinary => todo!(),
185 DataType::Utf8 => {
186 let string_values: Vec<std::ffi::CString> = values
187 .as_string::<i32>()
188 .iter()
189 .filter_map(|opt| opt) .map(|s| std::ffi::CString::new(s).unwrap())
191 .collect();
192 let _ = self.set_string(vrs, &string_values);
193 }
194 DataType::LargeUtf8 => todo!(),
195 _ => unimplemented!("Unsupported data type"),
196 }
197 }
198
199 fn set_interpolated<I: Interpolate>(
200 &mut self,
201 vr: <Self as FmiInstance>::ValueRef,
202 pl: &PreLookup,
203 array: &ArrayRef,
204 ) -> anyhow::Result<()> {
205 match array.data_type() {
206 DataType::Boolean => todo!(),
207 DataType::Int8 => {
208 let array = array.as_primitive::<Int8Type>();
209 let value = I::interpolate(pl, &array);
210 self.set_int8(&[vr], &[value])?;
211 }
212 DataType::Int16 => {
213 let array = array.as_primitive::<Int16Type>();
214 let value = I::interpolate(pl, &array);
215 self.set_int16(&[vr], &[value])?;
216 }
217 DataType::Int32 => {
218 let array = array.as_primitive::<Int32Type>();
219 let value = I::interpolate(pl, &array);
220 self.set_int32(&[vr], &[value])?;
221 }
222 DataType::Int64 => {
223 let array = array.as_primitive::<Int64Type>();
224 let value = I::interpolate(pl, &array);
225 self.set_int64(&[vr], &[value])?;
226 }
227 DataType::UInt8 => {
228 let array: UInt8Array = downcast_array(&array);
229 let value = I::interpolate(pl, &array);
230 self.set_uint8(&[vr], &[value])?;
231 }
232 DataType::UInt16 => {
233 let array: UInt16Array = downcast_array(&array);
234 let value = I::interpolate(pl, &array);
235 self.set_uint16(&[vr], &[value])?;
236 }
237 DataType::UInt32 => {
238 let array: UInt32Array = downcast_array(&array);
239 let value = I::interpolate(pl, &array);
240 self.set_uint32(&[vr], &[value])?;
241 }
242 DataType::UInt64 => {
243 let array: UInt64Array = downcast_array(&array);
244 let value = I::interpolate(pl, &array);
245 self.set_uint64(&[vr], &[value])?;
246 }
247 DataType::Float32 => {
248 let array: Float32Array = downcast_array(&array);
249 let value = I::interpolate(pl, &array);
250 self.set_float32(&[vr], &[value])?;
251 }
252 DataType::Float64 => {
253 let array: Float64Array = downcast_array(&array);
254 let value = I::interpolate(pl, &array);
255 self.set_float64(&[vr], &[value])?;
256 }
257 DataType::Binary => todo!(),
258 DataType::Utf8 => {
259 let array = array.as_string::<i32>();
261 let index = pl.next_index().min(array.iter().count().saturating_sub(1));
262 if let Some(Some(value)) = array.iter().nth(index) {
263 let cstring = std::ffi::CString::new(value).unwrap();
264 let _ = self.set_string(&[vr], &[cstring]);
265 }
266 }
267 _ => unimplemented!("Unsupported data type: {:?}", array.data_type()),
268 }
269 Ok(())
270 }
271 }
272 };
273}
274
275#[cfg(feature = "cs")]
276impl_set_values!(fmi::fmi3::instance::InstanceCS);
277#[cfg(feature = "cs")]
278impl_record_values!(fmi::fmi3::instance::InstanceCS);
279
280#[cfg(feature = "me")]
281impl_set_values!(fmi::fmi3::instance::InstanceME);
282#[cfg(feature = "me")]
283impl_record_values!(fmi::fmi3::instance::InstanceME);