#![cfg_attr(
all(not(feature = "tetration-hdf5"), not(feature = "tetration-netcdf")),
allow(dead_code, unused_imports)
)]
use std::path::Path;
use serde::Serialize;
use crate::catalog::CatalogError;
mod cf;
#[cfg(feature = "tetration-hdf5")]
mod hdf5;
#[cfg(feature = "tetration-hdf5")]
mod hdf5_shared;
mod import_metadata;
#[cfg(feature = "tetration-netcdf")]
mod netcdf;
mod parallel;
mod shared;
mod sniff;
mod tile_io;
mod zarr;
pub use parallel::{default_parallel_jobs, resolve_parallel_jobs};
#[cfg(feature = "tetration-hdf5")]
pub use hdf5::{convert_h5_to_tet, convert_h5_to_tet_with_progress};
#[cfg(feature = "tetration-netcdf")]
pub use netcdf::{convert_netcdf_to_tet, convert_netcdf_to_tet_with_progress};
pub use zarr::{convert_zarr_to_tet, convert_zarr_to_tet_with_progress, is_zarr_v3_directory};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConvertInputFormat {
H5,
Netcdf,
Zarr,
}
impl ConvertInputFormat {
#[must_use]
pub const fn history_source(self) -> &'static str {
match self {
Self::H5 => "h5",
Self::Netcdf => "nc",
Self::Zarr => "zarr",
}
}
}
pub use sniff::{
ConvertCompressionSuffixes, Hdf5ConvertInput, NetcdfConvertInput, ZarrConvertInput,
detect_convert_format,
};
pub fn convert_to_tet(input: &Path, output: &Path) -> Result<ConvertReport, ConvertError> {
convert_to_tet_with_progress(input, output, 0, None::<fn(ConvertProgress)>)
}
pub fn convert_to_tet_with_progress(
input: &Path,
output: &Path,
parallel_jobs: usize,
progress: Option<impl FnMut(ConvertProgress)>,
) -> Result<ConvertReport, ConvertError> {
match detect_convert_format(input)? {
ConvertInputFormat::H5 => convert_h5_dispatch(input, output, parallel_jobs, progress),
ConvertInputFormat::Netcdf => {
convert_netcdf_dispatch(input, output, parallel_jobs, progress)
}
ConvertInputFormat::Zarr => {
convert_zarr_to_tet_with_progress(input, output, parallel_jobs, progress)
}
}
}
#[cfg(feature = "tetration-hdf5")]
fn convert_h5_dispatch(
input: &Path,
output: &Path,
parallel_jobs: usize,
progress: Option<impl FnMut(ConvertProgress)>,
) -> Result<ConvertReport, ConvertError> {
convert_h5_to_tet_with_progress(input, output, parallel_jobs, progress)
}
#[cfg(not(feature = "tetration-hdf5"))]
fn convert_h5_dispatch(
_input: &Path,
_output: &Path,
_parallel_jobs: usize,
_progress: Option<impl FnMut(ConvertProgress)>,
) -> Result<ConvertReport, ConvertError> {
Err(ConvertError::ConvertFeatureDisabled {
format: ConvertInputFormat::H5,
feature: "tetration-hdf5",
})
}
#[cfg(feature = "tetration-netcdf")]
fn convert_netcdf_dispatch(
input: &Path,
output: &Path,
parallel_jobs: usize,
progress: Option<impl FnMut(ConvertProgress)>,
) -> Result<ConvertReport, ConvertError> {
convert_netcdf_to_tet_with_progress(input, output, parallel_jobs, progress)
}
#[cfg(not(feature = "tetration-netcdf"))]
fn convert_netcdf_dispatch(
_input: &Path,
_output: &Path,
_parallel_jobs: usize,
_progress: Option<impl FnMut(ConvertProgress)>,
) -> Result<ConvertReport, ConvertError> {
Err(ConvertError::ConvertFeatureDisabled {
format: ConvertInputFormat::Netcdf,
feature: "tetration-netcdf",
})
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct ConvertProgress {
pub chunks_done: u64,
pub chunks_total: u64,
pub dataset: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct ConvertDatasetSummary {
pub name: String,
pub ndim: usize,
pub dims: Vec<u64>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct ConvertReport {
pub input: String,
pub output: String,
pub dataset_count: usize,
pub dataset_names: Vec<String>,
pub datasets: Vec<ConvertDatasetSummary>,
pub history: Vec<crate::catalog::HistoryEvent>,
pub elapsed_secs: f64,
}
#[derive(Debug, thiserror::Error)]
pub enum ConvertError {
#[error(transparent)]
Catalog(#[from] CatalogError),
#[error("no supported numeric datasets found in {path}")]
NoDatasets { path: String },
#[cfg(feature = "tetration-netcdf")]
#[error("NetCDF open/read failed: {0}")]
Netcdf(String),
#[cfg(feature = "tetration-hdf5")]
#[error("HDF5 open/read failed: {0}")]
Hdf5(String),
#[error("Zarr open/read failed: {0}")]
Zarr(String),
#[error("unsupported element type in variable `{name}`: {detail}")]
UnsupportedDtype { name: String, detail: String },
#[error(
"unsupported convert input `{path}`: extension `{ext}` (supported extensions: {h5_ext}; {nc_ext}; {zarr_ext}; or recognizable HDF5 / NetCDF-3 file signature / Zarr v3 directory store)"
)]
UnsupportedInputExtension {
path: String,
ext: String,
h5_ext: &'static str,
nc_ext: &'static str,
zarr_ext: &'static str,
},
#[error("{format:?} convert requires Cargo feature `{feature}`")]
ConvertFeatureDisabled {
format: ConvertInputFormat,
feature: &'static str,
},
}
fn report(
path_in: &Path,
path_out: &Path,
plans: &[shared::ImportPlan],
history: Vec<crate::catalog::HistoryEvent>,
elapsed_secs: f64,
) -> ConvertReport {
let datasets: Vec<ConvertDatasetSummary> = plans
.iter()
.map(|p| ConvertDatasetSummary {
name: p.name.clone(),
ndim: p.shape.len(),
dims: p.shape.clone(),
})
.collect();
let dataset_names: Vec<String> = datasets.iter().map(|d| d.name.clone()).collect();
ConvertReport {
input: path_in.display().to_string(),
output: path_out.display().to_string(),
dataset_count: datasets.len(),
dataset_names,
datasets,
history,
elapsed_secs,
}
}