use fmi::fmi3::{Fmi3Error, binding};
use crate::fmi3::{Clock, types::Binary};
use super::{Context, Model};
macro_rules! model_getter_setter {
($name:ident, $ty:ty) => {
paste::paste! {
fn [<get_ $name>](
&self,
_vr: binding::fmi3ValueReference,
_values: &mut [$ty],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
Err(Fmi3Error::Error)
}
fn [<set_ $name>](
&mut self,
_vr: binding::fmi3ValueReference,
_values: &[$ty],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
Err(Fmi3Error::Error)
}
}
};
}
macro_rules! impl_model_get_set_primitive {
($name:ident, $ty:ty, $data_type:expr) => {
paste::paste! {
impl<M: Model> ModelGetSet<M> for $ty {
const FIELD_COUNT: usize = 1;
fn [<get_ $name>](
&self,
vr: binding::fmi3ValueReference,
values: &mut [$ty],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
if vr == 0 && !values.is_empty() {
values[0] = *self;
Ok(1)
} else {
Err(Fmi3Error::Error)
}
}
fn [<set_ $name>](
&mut self,
vr: binding::fmi3ValueReference,
values: &[$ty],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
if vr == 0 && !values.is_empty() {
*self = values[0];
Ok(1)
} else {
Err(Fmi3Error::Error)
}
}
}
impl<M: Model, const N: usize> ModelGetSet<M> for [$ty; N] {
const FIELD_COUNT: usize = 1;
fn [<get_ $name>](
&self,
vr: binding::fmi3ValueReference,
values: &mut [$ty],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
let _ = vr;
if values.is_empty() {
return Err(Fmi3Error::Error);
}
let len = std::cmp::min(N, values.len());
values[..len].copy_from_slice(&self[..len]);
Ok(len)
}
fn [<set_ $name>](
&mut self,
vr: binding::fmi3ValueReference,
values: &[$ty],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
let _ = vr;
if values.is_empty() {
return Err(Fmi3Error::Error);
}
let len = std::cmp::min(N, values.len());
self[..len].copy_from_slice(&values[..len]);
Ok(len)
}
}
}
};
}
pub trait ModelGetSet<M: Model> {
const FIELD_COUNT: usize;
model_getter_setter!(boolean, bool);
model_getter_setter!(float32, f32);
model_getter_setter!(float64, f64);
model_getter_setter!(int8, i8);
model_getter_setter!(int16, i16);
model_getter_setter!(int32, i32);
model_getter_setter!(int64, i64);
model_getter_setter!(uint8, u8);
model_getter_setter!(uint16, u16);
model_getter_setter!(uint32, u32);
model_getter_setter!(uint64, u64);
model_getter_setter!(string, std::ffi::CString);
fn get_binary(
&self,
_vr: binding::fmi3ValueReference,
_values: &mut [&mut [u8]],
_context: &dyn Context<M>,
) -> Result<Vec<usize>, Fmi3Error> {
Err(Fmi3Error::Error)
}
fn set_binary(
&mut self,
_vr: binding::fmi3ValueReference,
_values: &[&[u8]],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
Err(Fmi3Error::Error)
}
fn get_clock(
&mut self,
_vr: binding::fmi3ValueReference,
_value: &mut binding::fmi3Clock,
_context: &dyn Context<M>,
) -> Result<(), Fmi3Error> {
Err(Fmi3Error::Error)
}
fn set_clock(
&mut self,
_vr: binding::fmi3ValueReference,
_value: &binding::fmi3Clock,
_context: &dyn Context<M>,
) -> Result<(), Fmi3Error> {
Err(Fmi3Error::Error)
}
}
impl_model_get_set_primitive!(boolean, bool, schema::DataType::Boolean);
impl_model_get_set_primitive!(float32, f32, schema::DataType::Float32);
impl_model_get_set_primitive!(float64, f64, schema::DataType::Float64);
impl_model_get_set_primitive!(int8, i8, schema::DataType::Int8);
impl_model_get_set_primitive!(int16, i16, schema::DataType::Int16);
impl_model_get_set_primitive!(int32, i32, schema::DataType::Int32);
impl_model_get_set_primitive!(int64, i64, schema::DataType::Int64);
impl_model_get_set_primitive!(uint8, u8, schema::DataType::Uint8);
impl_model_get_set_primitive!(uint16, u16, schema::DataType::Uint16);
impl_model_get_set_primitive!(uint32, u32, schema::DataType::Uint32);
impl_model_get_set_primitive!(uint64, u64, schema::DataType::Uint64);
impl<M: Model> ModelGetSet<M> for String {
const FIELD_COUNT: usize = 1;
fn get_string(
&self,
vr: binding::fmi3ValueReference,
values: &mut [std::ffi::CString],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
if vr == 0 && !values.is_empty() {
values[0] = std::ffi::CString::new(self.as_str()).unwrap();
Ok(1)
} else {
Err(Fmi3Error::Error)
}
}
fn set_string(
&mut self,
vr: binding::fmi3ValueReference,
values: &[std::ffi::CString],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
if vr == 0 && !values.is_empty() {
*self = values[0]
.to_str()
.map_err(|_| Fmi3Error::Error)?
.to_string();
Ok(1)
} else {
Err(Fmi3Error::Error)
}
}
}
impl<M: Model> ModelGetSet<M> for Clock {
const FIELD_COUNT: usize = 1;
fn get_clock(
&mut self,
vr: binding::fmi3ValueReference,
value: &mut binding::fmi3Clock,
_context: &dyn Context<M>,
) -> Result<(), Fmi3Error> {
if vr == 0 {
*value = self.0;
self.0 = false;
Ok(())
} else {
Err(Fmi3Error::Error)
}
}
fn set_clock(
&mut self,
vr: binding::fmi3ValueReference,
value: &binding::fmi3Clock,
_context: &dyn Context<M>,
) -> Result<(), Fmi3Error> {
if vr == 0 {
self.0 = *value;
Ok(())
} else {
Err(Fmi3Error::Error)
}
}
}
impl<M: Model> ModelGetSet<M> for Binary {
const FIELD_COUNT: usize = 1;
fn get_binary(
&self,
vr: binding::fmi3ValueReference,
values: &mut [&mut [u8]],
_context: &dyn Context<M>,
) -> Result<Vec<usize>, Fmi3Error> {
if vr == 0 && !values.is_empty() {
let len = std::cmp::min(self.0.len(), values[0].len());
values[0][..len].copy_from_slice(&self.0[..len]);
Ok(vec![len])
} else {
Err(Fmi3Error::Error)
}
}
fn set_binary(
&mut self,
vr: binding::fmi3ValueReference,
values: &[&[u8]],
_context: &dyn Context<M>,
) -> Result<usize, Fmi3Error> {
if vr == 0 && !values.is_empty() {
self.0.clear();
self.0.extend_from_slice(values[0]);
Ok(1)
} else {
Err(Fmi3Error::Error)
}
}
}
pub trait ModelGetSetStates {
const NUM_STATES: usize;
fn get_continuous_states(&self, states: &mut [f64]) -> Result<(), Fmi3Error>;
fn set_continuous_states(&mut self, states: &[f64]) -> Result<(), Fmi3Error>;
fn get_continuous_state_derivatives(
&mut self,
derivatives: &mut [f64],
) -> Result<(), Fmi3Error>;
}
impl ModelGetSetStates for f64 {
const NUM_STATES: usize = 1;
fn get_continuous_states(&self, states: &mut [f64]) -> Result<(), Fmi3Error> {
if states.is_empty() {
Err(Fmi3Error::Error)
} else {
states[0] = *self;
Ok(())
}
}
fn set_continuous_states(&mut self, states: &[f64]) -> Result<(), Fmi3Error> {
if states.is_empty() {
Err(Fmi3Error::Error)
} else {
*self = states[0];
Ok(())
}
}
fn get_continuous_state_derivatives(
&mut self,
derivatives: &mut [f64],
) -> Result<(), Fmi3Error> {
if derivatives.is_empty() {
Err(Fmi3Error::Error)
} else {
derivatives[0] = *self;
Ok(())
}
}
}
impl<const N: usize> ModelGetSetStates for [f64; N] {
const NUM_STATES: usize = N;
fn get_continuous_states(&self, states: &mut [f64]) -> Result<(), Fmi3Error> {
if states.len() < Self::NUM_STATES {
Err(Fmi3Error::Error)
} else {
states[0..N].copy_from_slice(self);
Ok(())
}
}
fn set_continuous_states(&mut self, states: &[f64]) -> Result<(), Fmi3Error> {
if states.len() < Self::NUM_STATES {
Err(Fmi3Error::Error)
} else {
self.copy_from_slice(&states[0..N]);
Ok(())
}
}
fn get_continuous_state_derivatives(
&mut self,
derivatives: &mut [f64],
) -> Result<(), Fmi3Error> {
if derivatives.len() < Self::NUM_STATES {
Err(Fmi3Error::Error)
} else {
derivatives[0..N].copy_from_slice(self);
Ok(())
}
}
}