Skip to main content

fmi_export/fmi3/instance/
get_set.rs

1use fmi::fmi3::{Fmi3Error, Fmi3Res, GetSet, binding};
2
3use crate::fmi3::{
4    Model, UserModel,
5    traits::{Context, ModelGetSet},
6};
7
8/// Macro to generate getter implementations for ModelInstance
9macro_rules! instance_getter {
10    ($name:ident, $ty:ty) => {
11        paste::paste! {
12            fn [<get_ $name>](
13                &mut self,
14                vrs: &[binding::fmi3ValueReference],
15                values: &mut [$ty],
16            ) -> Result<Fmi3Res, Fmi3Error> {
17                if self.is_dirty_values {
18                    self.model.calculate_values(&self.context)?;
19                    self.is_dirty_values = false;
20                }
21                let mut value_index = 0;
22                for vr in vrs.iter() {
23                    if *vr == 0 {
24                        // 'time VR is not valid here
25                        return Err(Fmi3Error::Error);
26                    }
27                    let elements_read = self.model.[<get_ $name>](*vr-1, &mut values[value_index..], &self.context)?;
28                    value_index += elements_read;
29                }
30                Ok(Fmi3Res::OK)
31            }
32        }
33    };
34}
35
36/// Macro to generate setter implementations for ModelInstance
37macro_rules! instance_setter {
38    ($name:ident, $ty:ty) => {
39        paste::paste! {
40            fn [<set_ $name>](
41                &mut self,
42                vrs: &[binding::fmi3ValueReference],
43                values: &[$ty],
44            ) -> Result<Fmi3Res, Fmi3Error> {
45                // Validate variable setting restrictions before setting values
46                let mut value_index = 0;
47                for vr in vrs.iter() {
48                    if *vr == 0 {
49                        // 'time' VR is not settable
50                        return Err(Fmi3Error::Error);
51                    }
52                    self.validate_variable_setting(*vr - 1)?;
53                    let elements_written = self.model.[<set_ $name>](*vr-1, &values[value_index..], &self.context)?;
54                    value_index += elements_written;
55                }
56
57                self.is_dirty_values = true;
58                Ok(Fmi3Res::OK)
59            }
60        }
61    };
62}
63
64/// Macro to generate both getter and setter for standard types
65macro_rules! instance_getter_setter {
66    ($name:ident, $ty:ty) => {
67        instance_getter!($name, $ty);
68        instance_setter!($name, $ty);
69    };
70}
71
72/// Blanket implementation of the GetSet trait for ModelInstance.
73///
74/// These implementations delegate to the underlying user model's get/set methods which are generated by the derive macro).
75/// Here we have special handling for the 'time' variable reference (implicitly always VR=0).
76///
77/// The generated get/set methods *do not* take into account 'time' as VR=0, and expect VRs to be zero-based indices into
78/// the model's variables.
79///
80/// Only the float64 getter has special handling for 'time' VR=0, as it is the only type that can represent time.
81
82impl<M, C> GetSet for super::ModelInstance<M, C>
83where
84    M: Model + UserModel + ModelGetSet<M>,
85    C: Context<M>,
86{
87    // Standard getter/setter pairs
88    instance_getter_setter!(boolean, bool);
89    instance_getter_setter!(float32, f32);
90    instance_getter_setter!(int8, i8);
91    instance_getter_setter!(int16, i16);
92    instance_getter_setter!(int32, i32);
93    instance_getter_setter!(int64, i64);
94    instance_getter_setter!(uint8, u8);
95    instance_getter_setter!(uint16, u16);
96    instance_getter_setter!(uint32, u32);
97    instance_getter_setter!(uint64, u64);
98
99    fn get_float64(
100        &mut self,
101        vrs: &[binding::fmi3ValueReference],
102        values: &mut [f64],
103    ) -> Result<Fmi3Res, Fmi3Error> {
104        if self.is_dirty_values {
105            self.model.calculate_values(&self.context)?;
106            self.is_dirty_values = false;
107        }
108        let mut value_index = 0;
109        for vr in vrs.iter() {
110            // Special handling for 'time' vr=0
111            if *vr == 0 && value_index < values.len() {
112                values[value_index] = self.context.time();
113                value_index += 1;
114            } else {
115                let elements_read =
116                    self.model
117                        .get_float64(*vr - 1, &mut values[value_index..], &self.context)?;
118                value_index += elements_read;
119            }
120        }
121        Ok(Fmi3Res::OK)
122    }
123    instance_setter!(float64, f64);
124
125    fn get_string(
126        &mut self,
127        vrs: &[binding::fmi3ValueReference],
128        values: &mut [std::ffi::CString],
129    ) -> Result<(), Fmi3Error> {
130        let mut value_index = 0;
131        for vr in vrs.iter() {
132            if *vr == 0 {
133                // 'time' VR is not valid here
134                return Err(Fmi3Error::Error);
135            }
136            let elements_read =
137                self.model
138                    .get_string(*vr - 1, &mut values[value_index..], &self.context)?;
139            value_index += elements_read;
140        }
141        Ok(())
142    }
143
144    fn set_string(
145        &mut self,
146        vrs: &[binding::fmi3ValueReference],
147        values: &[std::ffi::CString],
148    ) -> Result<(), Fmi3Error> {
149        let mut value_index = 0;
150        for vr in vrs.iter() {
151            if *vr == 0 {
152                // 'time' VR is not settable
153                return Err(Fmi3Error::Error);
154            }
155            self.validate_variable_setting(*vr)?;
156            let elements_written =
157                self.model
158                    .set_string(*vr - 1, &values[value_index..], &self.context)?;
159            value_index += elements_written;
160        }
161        self.is_dirty_values = true;
162        Ok(())
163    }
164
165    fn get_binary(
166        &mut self,
167        vrs: &[binding::fmi3ValueReference],
168        values: &mut [&mut [u8]],
169    ) -> Result<Vec<usize>, Fmi3Error> {
170        let mut result_sizes = Vec::new();
171        let mut value_index = 0;
172        for vr in vrs.iter() {
173            if *vr == 0 {
174                // 'time' VR is not valid here
175                return Err(Fmi3Error::Error);
176            }
177            let binary_sizes =
178                self.model
179                    .get_binary(*vr - 1, &mut values[value_index..], &self.context)?;
180            result_sizes.extend(binary_sizes.iter());
181            value_index += binary_sizes.len();
182        }
183        Ok(result_sizes)
184    }
185
186    fn set_binary(
187        &mut self,
188        vrs: &[binding::fmi3ValueReference],
189        values: &[&[u8]],
190    ) -> Result<(), Fmi3Error> {
191        let mut value_index = 0;
192        for vr in vrs.iter() {
193            if *vr == 0 {
194                // 'time' VR is not settable
195                return Err(Fmi3Error::Error);
196            }
197            self.validate_variable_setting(*vr - 1)?;
198            let elements_written =
199                self.model
200                    .set_binary(*vr - 1, &values[value_index..], &self.context)?;
201            value_index += elements_written;
202        }
203        self.is_dirty_values = true;
204        Ok(())
205    }
206
207    fn get_clock(
208        &mut self,
209        vrs: &[binding::fmi3ValueReference],
210        values: &mut [binding::fmi3Clock],
211    ) -> Result<Fmi3Res, Fmi3Error> {
212        for (vr, value) in vrs.iter().zip(values.iter_mut()) {
213            if *vr == 0 {
214                // 'time' VR is not valid here
215                return Err(Fmi3Error::Error);
216            }
217            self.model.get_clock(*vr - 1, value, &self.context)?;
218        }
219        Ok(Fmi3Res::OK)
220    }
221
222    fn set_clock(
223        &mut self,
224        _vrs: &[binding::fmi3ValueReference],
225        _values: &[binding::fmi3Clock],
226    ) -> Result<Fmi3Res, Fmi3Error> {
227        for (vr, value) in _vrs.iter().zip(_values.iter()) {
228            if *vr == 0 {
229                // 'time' VR is not settable
230                return Err(Fmi3Error::Error);
231            }
232            self.validate_variable_setting(*vr - 1)?;
233            self.model.set_clock(*vr - 1, value, &self.context)?;
234        }
235        Ok(Fmi3Res::OK)
236    }
237}