use std::{path::PathBuf, str::FromStr};
use super::{binding, instance::Instance};
use crate::{CS, Error, ME, traits::FmiImport};
use fmi_schema::{MajorVersion, fmi2 as schema};
#[derive(Debug)]
pub struct Fmi2Import {
dir: tempfile::TempDir,
model_description: schema::Fmi2ModelDescription,
}
impl FmiImport for Fmi2Import {
const MAJOR_VERSION: MajorVersion = MajorVersion::FMI2;
type ModelDescription = schema::Fmi2ModelDescription;
type Binding = binding::Fmi2Binding;
type ValueRef = binding::fmi2ValueReference;
fn new(dir: tempfile::TempDir, schema_xml: &str) -> Result<Self, Error> {
let schema = schema::Fmi2ModelDescription::from_str(schema_xml)?;
Ok(Self {
dir,
model_description: schema,
})
}
#[inline]
fn archive_path(&self) -> &std::path::Path {
self.dir.path()
}
fn shared_lib_path(&self, model_identifier: &str) -> Result<PathBuf, Error> {
let platform_folder = match (std::env::consts::OS, std::env::consts::ARCH) {
("windows", "x86_64") => "win64",
("windows", "x86") => "win32",
("linux", "x86_64") => "linux64",
("linux", "x86") => "linux32",
("macos", "x86_64") => "darwin64",
("macos", "x86") => "darwin32",
_ => {
return Err(Error::UnsupportedPlatform {
os: std::env::consts::OS.to_string(),
arch: std::env::consts::ARCH.to_string(),
});
}
};
let fname = format!("{model_identifier}{}", std::env::consts::DLL_SUFFIX);
Ok(std::path::PathBuf::from("binaries")
.join(platform_folder)
.join(fname))
}
fn model_description(&self) -> &Self::ModelDescription {
&self.model_description
}
fn binding(&self, model_identifier: &str) -> Result<Self::Binding, Error> {
let lib_path = self
.dir
.path()
.join(self.shared_lib_path(model_identifier)?);
log::trace!("Loading shared library {lib_path:?}");
unsafe { binding::Fmi2Binding::new(lib_path).map_err(Error::from) }
}
fn canonical_resource_path_string(&self) -> String {
let resource_path =
std::path::absolute(self.resource_path()).expect("Invalid resource path");
url::Url::from_file_path(resource_path)
.map(|url| url.as_str().to_owned())
.expect("Error converting path to URL")
}
}
impl Fmi2Import {
pub fn instantiate_me(
&self,
instance_name: &str,
visible: bool,
logging_on: bool,
) -> Result<Instance<ME>, Error> {
Instance::<ME>::new(self, instance_name, visible, logging_on)
}
pub fn instantiate_cs(
&self,
instance_name: &str,
visible: bool,
logging_on: bool,
) -> Result<Instance<CS>, Error> {
Instance::<CS>::new(self, instance_name, visible, logging_on)
}
}