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.
81impl<M, C> GetSet for super::ModelInstance<M, C>
82where
83    M: Model + UserModel + ModelGetSet<M>,
84    C: Context<M>,
85{
86    // Standard getter/setter pairs
87    instance_getter_setter!(boolean, bool);
88    instance_getter_setter!(float32, f32);
89    instance_getter_setter!(int8, i8);
90    instance_getter_setter!(int16, i16);
91    instance_getter_setter!(int32, i32);
92    instance_getter_setter!(int64, i64);
93    instance_getter_setter!(uint8, u8);
94    instance_getter_setter!(uint16, u16);
95    instance_getter_setter!(uint32, u32);
96    instance_getter_setter!(uint64, u64);
97
98    fn get_float64(
99        &mut self,
100        vrs: &[binding::fmi3ValueReference],
101        values: &mut [f64],
102    ) -> Result<Fmi3Res, Fmi3Error> {
103        if self.is_dirty_values {
104            self.model.calculate_values(&self.context)?;
105            self.is_dirty_values = false;
106        }
107        let mut value_index = 0;
108        for vr in vrs.iter() {
109            // Special handling for 'time' vr=0
110            if *vr == 0 && value_index < values.len() {
111                values[value_index] = self.context.time();
112                value_index += 1;
113            } else {
114                let elements_read =
115                    self.model
116                        .get_float64(*vr - 1, &mut values[value_index..], &self.context)?;
117                value_index += elements_read;
118            }
119        }
120        Ok(Fmi3Res::OK)
121    }
122    instance_setter!(float64, f64);
123
124    fn get_string(
125        &mut self,
126        vrs: &[binding::fmi3ValueReference],
127        values: &mut [std::ffi::CString],
128    ) -> Result<(), Fmi3Error> {
129        let mut value_index = 0;
130        for vr in vrs.iter() {
131            if *vr == 0 {
132                // 'time' VR is not valid here
133                return Err(Fmi3Error::Error);
134            }
135            let elements_read =
136                self.model
137                    .get_string(*vr - 1, &mut values[value_index..], &self.context)?;
138            value_index += elements_read;
139        }
140        Ok(())
141    }
142
143    fn set_string(
144        &mut self,
145        vrs: &[binding::fmi3ValueReference],
146        values: &[std::ffi::CString],
147    ) -> Result<(), Fmi3Error> {
148        let mut value_index = 0;
149        for vr in vrs.iter() {
150            if *vr == 0 {
151                // 'time' VR is not settable
152                return Err(Fmi3Error::Error);
153            }
154            self.validate_variable_setting(*vr)?;
155            let elements_written =
156                self.model
157                    .set_string(*vr - 1, &values[value_index..], &self.context)?;
158            value_index += elements_written;
159        }
160        self.is_dirty_values = true;
161        Ok(())
162    }
163
164    fn get_binary(
165        &mut self,
166        vrs: &[binding::fmi3ValueReference],
167        values: &mut [&mut [u8]],
168    ) -> Result<Vec<usize>, Fmi3Error> {
169        let mut result_sizes = Vec::new();
170        let mut value_index = 0;
171        for vr in vrs.iter() {
172            if *vr == 0 {
173                // 'time' VR is not valid here
174                return Err(Fmi3Error::Error);
175            }
176            let binary_sizes =
177                self.model
178                    .get_binary(*vr - 1, &mut values[value_index..], &self.context)?;
179            result_sizes.extend(binary_sizes.iter());
180            value_index += binary_sizes.len();
181        }
182        Ok(result_sizes)
183    }
184
185    fn set_binary(
186        &mut self,
187        vrs: &[binding::fmi3ValueReference],
188        values: &[&[u8]],
189    ) -> Result<(), Fmi3Error> {
190        let mut value_index = 0;
191        for vr in vrs.iter() {
192            if *vr == 0 {
193                // 'time' VR is not settable
194                return Err(Fmi3Error::Error);
195            }
196            self.validate_variable_setting(*vr - 1)?;
197            let elements_written =
198                self.model
199                    .set_binary(*vr - 1, &values[value_index..], &self.context)?;
200            value_index += elements_written;
201        }
202        self.is_dirty_values = true;
203        Ok(())
204    }
205
206    fn get_clock(
207        &mut self,
208        vrs: &[binding::fmi3ValueReference],
209        values: &mut [binding::fmi3Clock],
210    ) -> Result<Fmi3Res, Fmi3Error> {
211        for (vr, value) in vrs.iter().zip(values.iter_mut()) {
212            if *vr == 0 {
213                // 'time' VR is not valid here
214                return Err(Fmi3Error::Error);
215            }
216            self.model.get_clock(*vr - 1, value, &self.context)?;
217        }
218        Ok(Fmi3Res::OK)
219    }
220
221    fn set_clock(
222        &mut self,
223        _vrs: &[binding::fmi3ValueReference],
224        _values: &[binding::fmi3Clock],
225    ) -> Result<Fmi3Res, Fmi3Error> {
226        for (vr, value) in _vrs.iter().zip(_values.iter()) {
227            if *vr == 0 {
228                // 'time' VR is not settable
229                return Err(Fmi3Error::Error);
230            }
231            self.validate_variable_setting(*vr - 1)?;
232            self.model.set_clock(*vr - 1, value, &self.context)?;
233        }
234        Ok(Fmi3Res::OK)
235    }
236}