use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use crate::core::{Error, Result};
use crate::formats::msh;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Format {
Bdf,
Vtu,
Vtk,
Msh,
Inp,
Frd,
Op2,
Pch,
Stl,
Su2,
Unv,
Exodus,
}
impl Format {
pub const ALL: [Self; 12] = [
Self::Bdf,
Self::Vtu,
Self::Vtk,
Self::Msh,
Self::Inp,
Self::Frd,
Self::Op2,
Self::Pch,
Self::Stl,
Self::Su2,
Self::Unv,
Self::Exodus,
];
#[must_use]
pub fn name(self) -> &'static str {
match self {
Self::Bdf => "bdf",
Self::Vtu => "vtu",
Self::Vtk => "vtk",
Self::Msh => "msh",
Self::Inp => "inp",
Self::Frd => "frd",
Self::Op2 => "op2",
Self::Pch => "pch",
Self::Stl => "stl",
Self::Su2 => "su2",
Self::Unv => "unv",
Self::Exodus => "exodus",
}
}
pub fn parse(name: &str) -> Result<Self> {
Self::ALL
.into_iter()
.find(|format| format.name().eq_ignore_ascii_case(name))
.ok_or_else(|| Error::new("E_FORMAT", format!("unknown input format {name}")))
}
pub fn from_input_path(path: &Path) -> Result<Self> {
let extension = extension(path);
match extension.as_str() {
"nas" | "dat" => Ok(Self::Bdf),
"exo" | "e" => Ok(Self::Exodus),
_ => Self::parse(&extension).map_err(|_| {
Error::new(
"E_FORMAT",
format!("no reader for extension {extension:?}; use --from"),
)
}),
}
}
pub fn from_output_path(path: &Path) -> Result<Self> {
let extension = extension(path);
let format = match extension.as_str() {
"nas" => Some(Self::Bdf),
"exo" | "e" => Some(Self::Exodus),
_ => Self::parse(&extension).ok(),
};
format
.filter(|format| *format != Self::Pch)
.ok_or_else(|| Error::new("E_FORMAT", format!("no writer for extension {extension:?}")))
}
}
fn extension(path: &Path) -> String {
path.extension()
.and_then(OsStr::to_str)
.unwrap_or("")
.to_ascii_lowercase()
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(clippy::struct_excessive_bools)] pub struct Options {
pub input_format: Option<Format>,
pub mesh: Option<PathBuf>,
pub assume_basic_frame: bool,
pub subcase: Option<i64>,
pub step: Option<usize>,
pub max_bytes: usize,
pub msh_version: Option<msh::Version>,
pub zero_missing_rotations: bool,
pub accept_omissions: bool,
pub accept_synthetic_zero: bool,
pub mesh_output: Option<PathBuf>,
pub strict: bool,
pub accept_all: bool,
}
impl Default for Options {
fn default() -> Self {
Self {
input_format: None,
mesh: None,
assume_basic_frame: false,
subcase: None,
step: None,
max_bytes: 256 * 1024 * 1024,
msh_version: None,
zero_missing_rotations: false,
accept_omissions: false,
accept_synthetic_zero: false,
mesh_output: None,
strict: false,
accept_all: false,
}
}
}