use fmi::fmi3::{Fmi3Error, Fmi3Res, GetSet, binding};
use crate::fmi3::{
Model, UserModel,
traits::{Context, ModelGetSet},
};
macro_rules! instance_getter {
($name:ident, $ty:ty) => {
paste::paste! {
fn [<get_ $name>](
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &mut [$ty],
) -> Result<Fmi3Res, Fmi3Error> {
if self.is_dirty_values {
self.model.calculate_values(&self.context)?;
self.is_dirty_values = false;
}
let mut value_index = 0;
for vr in vrs.iter() {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
let elements_read = self.model.[<get_ $name>](*vr-1, &mut values[value_index..], &self.context)?;
value_index += elements_read;
}
Ok(Fmi3Res::OK)
}
}
};
}
macro_rules! instance_setter {
($name:ident, $ty:ty) => {
paste::paste! {
fn [<set_ $name>](
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &[$ty],
) -> Result<Fmi3Res, Fmi3Error> {
let mut value_index = 0;
for vr in vrs.iter() {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
self.validate_variable_setting(*vr - 1)?;
let elements_written = self.model.[<set_ $name>](*vr-1, &values[value_index..], &self.context)?;
value_index += elements_written;
}
self.is_dirty_values = true;
Ok(Fmi3Res::OK)
}
}
};
}
macro_rules! instance_getter_setter {
($name:ident, $ty:ty) => {
instance_getter!($name, $ty);
instance_setter!($name, $ty);
};
}
impl<M, C> GetSet for super::ModelInstance<M, C>
where
M: Model + UserModel + ModelGetSet<M>,
C: Context<M>,
{
instance_getter_setter!(boolean, bool);
instance_getter_setter!(float32, f32);
instance_getter_setter!(int8, i8);
instance_getter_setter!(int16, i16);
instance_getter_setter!(int32, i32);
instance_getter_setter!(int64, i64);
instance_getter_setter!(uint8, u8);
instance_getter_setter!(uint16, u16);
instance_getter_setter!(uint32, u32);
instance_getter_setter!(uint64, u64);
fn get_float64(
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &mut [f64],
) -> Result<Fmi3Res, Fmi3Error> {
if self.is_dirty_values {
self.model.calculate_values(&self.context)?;
self.is_dirty_values = false;
}
let mut value_index = 0;
for vr in vrs.iter() {
if *vr == 0 && value_index < values.len() {
values[value_index] = self.context.time();
value_index += 1;
} else {
let elements_read =
self.model
.get_float64(*vr - 1, &mut values[value_index..], &self.context)?;
value_index += elements_read;
}
}
Ok(Fmi3Res::OK)
}
instance_setter!(float64, f64);
fn get_string(
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &mut [std::ffi::CString],
) -> Result<(), Fmi3Error> {
let mut value_index = 0;
for vr in vrs.iter() {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
let elements_read =
self.model
.get_string(*vr - 1, &mut values[value_index..], &self.context)?;
value_index += elements_read;
}
Ok(())
}
fn set_string(
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &[std::ffi::CString],
) -> Result<(), Fmi3Error> {
let mut value_index = 0;
for vr in vrs.iter() {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
self.validate_variable_setting(*vr)?;
let elements_written =
self.model
.set_string(*vr - 1, &values[value_index..], &self.context)?;
value_index += elements_written;
}
self.is_dirty_values = true;
Ok(())
}
fn get_binary(
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &mut [&mut [u8]],
) -> Result<Vec<usize>, Fmi3Error> {
let mut result_sizes = Vec::new();
let mut value_index = 0;
for vr in vrs.iter() {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
let binary_sizes =
self.model
.get_binary(*vr - 1, &mut values[value_index..], &self.context)?;
result_sizes.extend(binary_sizes.iter());
value_index += binary_sizes.len();
}
Ok(result_sizes)
}
fn set_binary(
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &[&[u8]],
) -> Result<(), Fmi3Error> {
let mut value_index = 0;
for vr in vrs.iter() {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
self.validate_variable_setting(*vr - 1)?;
let elements_written =
self.model
.set_binary(*vr - 1, &values[value_index..], &self.context)?;
value_index += elements_written;
}
self.is_dirty_values = true;
Ok(())
}
fn get_clock(
&mut self,
vrs: &[binding::fmi3ValueReference],
values: &mut [binding::fmi3Clock],
) -> Result<Fmi3Res, Fmi3Error> {
for (vr, value) in vrs.iter().zip(values.iter_mut()) {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
self.model.get_clock(*vr - 1, value, &self.context)?;
}
Ok(Fmi3Res::OK)
}
fn set_clock(
&mut self,
_vrs: &[binding::fmi3ValueReference],
_values: &[binding::fmi3Clock],
) -> Result<Fmi3Res, Fmi3Error> {
for (vr, value) in _vrs.iter().zip(_values.iter()) {
if *vr == 0 {
return Err(Fmi3Error::Error);
}
self.validate_variable_setting(*vr - 1)?;
self.model.set_clock(*vr - 1, value, &self.context)?;
}
Ok(Fmi3Res::OK)
}
}