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,
}
fn platform_folder(os: &str, arch: &str) -> Option<&'static str> {
match (os, arch) {
("windows", "x86_64") => Some("win64"),
("windows", "x86") => Some("win32"),
("linux", "x86_64") => Some("linux64"),
("linux", "x86") => Some("linux32"),
("linux", "aarch64") => Some("linux64"),
("macos", "x86_64") => Some("darwin64"),
("macos", "x86") => Some("darwin32"),
_ => None,
}
}
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 = platform_folder(std::env::consts::OS, std::env::consts::ARCH)
.ok_or_else(|| 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)
}
}
#[cfg(test)]
mod tests {
use super::platform_folder;
#[test]
fn linux_aarch64_uses_linux64_platform_folder() {
assert_eq!(platform_folder("linux", "aarch64"), Some("linux64"));
}
}