use crate::error::{BenchError, Result};
use crate::scenarios::BenchmarkScenario;
use std::collections::HashMap;
use std::path::PathBuf;
pub struct GeoTiffReadScenario {
input_path: PathBuf,
tile_size: Option<(usize, usize)>,
#[allow(dead_code)]
metadata: HashMap<String, String>,
}
impl GeoTiffReadScenario {
pub fn new<P: Into<PathBuf>>(input_path: P) -> Self {
Self {
input_path: input_path.into(),
tile_size: None,
metadata: HashMap::new(),
}
}
pub fn with_tile_size(mut self, width: usize, height: usize) -> Self {
self.tile_size = Some((width, height));
self
}
}
impl BenchmarkScenario for GeoTiffReadScenario {
fn name(&self) -> &str {
"geotiff_read"
}
fn description(&self) -> &str {
"Benchmark GeoTIFF file reading performance"
}
fn setup(&mut self) -> Result<()> {
if !self.input_path.exists() {
return Err(BenchError::scenario_failed(
self.name(),
format!("Input file does not exist: {}", self.input_path.display()),
));
}
Ok(())
}
fn execute(&mut self) -> Result<()> {
#[cfg(feature = "raster")]
{
use oxigdal_core::io::FileDataSource;
use oxigdal_geotiff::GeoTiffReader;
let data_source = FileDataSource::open(&self.input_path).map_err(|e| {
BenchError::scenario_failed(self.name(), format!("Failed to open file: {e}"))
})?;
let _reader = GeoTiffReader::open(data_source).map_err(|e| {
BenchError::scenario_failed(self.name(), format!("Failed to open GeoTIFF: {e}"))
})?;
}
#[cfg(not(feature = "raster"))]
{
return Err(BenchError::missing_dependency("oxigdal-geotiff", "raster"));
}
Ok(())
}
fn teardown(&mut self) -> Result<()> {
Ok(())
}
}
pub struct GeoTiffWriteScenario {
output_path: PathBuf,
#[allow(dead_code)]
width: usize,
#[allow(dead_code)]
height: usize,
compression: String,
created: bool,
}
impl GeoTiffWriteScenario {
pub fn new<P: Into<PathBuf>>(output_path: P, width: usize, height: usize) -> Self {
Self {
output_path: output_path.into(),
width,
height,
compression: "none".to_string(),
created: false,
}
}
pub fn with_compression<S: Into<String>>(mut self, compression: S) -> Self {
self.compression = compression.into();
self
}
}
impl BenchmarkScenario for GeoTiffWriteScenario {
fn name(&self) -> &str {
"geotiff_write"
}
fn description(&self) -> &str {
"Benchmark GeoTIFF file writing performance"
}
fn setup(&mut self) -> Result<()> {
if let Some(parent) = self.output_path.parent() {
std::fs::create_dir_all(parent)?;
}
Ok(())
}
fn execute(&mut self) -> Result<()> {
#[cfg(feature = "raster")]
{
self.created = true;
}
#[cfg(not(feature = "raster"))]
{
return Err(BenchError::missing_dependency("oxigdal-geotiff", "raster"));
}
Ok(())
}
fn teardown(&mut self) -> Result<()> {
if self.created && self.output_path.exists() {
std::fs::remove_file(&self.output_path)?;
}
Ok(())
}
}
pub struct RasterReprojectionScenario {
input_path: PathBuf,
output_path: PathBuf,
#[allow(dead_code)]
target_crs: String,
created: bool,
}
impl RasterReprojectionScenario {
pub fn new<P1, P2, S>(input_path: P1, output_path: P2, target_crs: S) -> Self
where
P1: Into<PathBuf>,
P2: Into<PathBuf>,
S: Into<String>,
{
Self {
input_path: input_path.into(),
output_path: output_path.into(),
target_crs: target_crs.into(),
created: false,
}
}
}
impl BenchmarkScenario for RasterReprojectionScenario {
fn name(&self) -> &str {
"raster_reprojection"
}
fn description(&self) -> &str {
"Benchmark raster reprojection performance"
}
fn setup(&mut self) -> Result<()> {
if !self.input_path.exists() {
return Err(BenchError::scenario_failed(
self.name(),
format!("Input file does not exist: {}", self.input_path.display()),
));
}
if let Some(parent) = self.output_path.parent() {
std::fs::create_dir_all(parent)?;
}
Ok(())
}
#[allow(unreachable_code)]
fn execute(&mut self) -> Result<()> {
#[cfg(all(feature = "raster", feature = "algorithms"))]
{
self.created = true;
}
#[cfg(not(all(feature = "raster", feature = "algorithms")))]
{
return Err(BenchError::missing_dependency(
"oxigdal reprojection",
"raster and algorithms",
));
}
#[allow(unreachable_code)]
Ok(())
}
fn teardown(&mut self) -> Result<()> {
if self.created && self.output_path.exists() {
std::fs::remove_file(&self.output_path)?;
}
Ok(())
}
}
pub struct CogValidationScenario {
input_path: PathBuf,
}
impl CogValidationScenario {
pub fn new<P: Into<PathBuf>>(input_path: P) -> Self {
Self {
input_path: input_path.into(),
}
}
}
impl BenchmarkScenario for CogValidationScenario {
fn name(&self) -> &str {
"cog_validation"
}
fn description(&self) -> &str {
"Benchmark Cloud-Optimized GeoTIFF validation performance"
}
fn setup(&mut self) -> Result<()> {
if !self.input_path.exists() {
return Err(BenchError::scenario_failed(
self.name(),
format!("Input file does not exist: {}", self.input_path.display()),
));
}
Ok(())
}
fn execute(&mut self) -> Result<()> {
#[cfg(feature = "raster")]
{
}
#[cfg(not(feature = "raster"))]
{
return Err(BenchError::missing_dependency(
"oxigdal-geotiff COG",
"raster",
));
}
Ok(())
}
fn teardown(&mut self) -> Result<()> {
Ok(())
}
}
pub struct CompressionBenchmarkScenario {
input_path: PathBuf,
output_dir: PathBuf,
compression_methods: Vec<String>,
created_files: Vec<PathBuf>,
}
impl CompressionBenchmarkScenario {
pub fn new<P1, P2>(input_path: P1, output_dir: P2) -> Self
where
P1: Into<PathBuf>,
P2: Into<PathBuf>,
{
Self {
input_path: input_path.into(),
output_dir: output_dir.into(),
compression_methods: vec![
"none".to_string(),
"lzw".to_string(),
"deflate".to_string(),
"zstd".to_string(),
],
created_files: Vec::new(),
}
}
pub fn with_methods(mut self, methods: Vec<String>) -> Self {
self.compression_methods = methods;
self
}
}
impl BenchmarkScenario for CompressionBenchmarkScenario {
fn name(&self) -> &str {
"raster_compression"
}
fn description(&self) -> &str {
"Benchmark different raster compression methods"
}
fn setup(&mut self) -> Result<()> {
if !self.input_path.exists() {
return Err(BenchError::scenario_failed(
self.name(),
format!("Input file does not exist: {}", self.input_path.display()),
));
}
std::fs::create_dir_all(&self.output_dir)?;
Ok(())
}
fn execute(&mut self) -> Result<()> {
#[cfg(feature = "raster")]
{
for method in &self.compression_methods {
let output_path = self.output_dir.join(format!("compressed_{method}.tif"));
self.created_files.push(output_path);
}
}
#[cfg(not(feature = "raster"))]
{
return Err(BenchError::missing_dependency("oxigdal-geotiff", "raster"));
}
Ok(())
}
fn teardown(&mut self) -> Result<()> {
for path in &self.created_files {
if path.exists() {
let _ = std::fs::remove_file(path);
}
}
self.created_files.clear();
Ok(())
}
}
pub struct BandStatisticsScenario {
input_path: PathBuf,
band_count: usize,
}
impl BandStatisticsScenario {
pub fn new<P: Into<PathBuf>>(input_path: P) -> Self {
Self {
input_path: input_path.into(),
band_count: 1,
}
}
pub fn with_band_count(mut self, count: usize) -> Self {
self.band_count = count;
self
}
}
impl BenchmarkScenario for BandStatisticsScenario {
fn name(&self) -> &str {
"band_statistics"
}
fn description(&self) -> &str {
"Benchmark raster band statistics calculation"
}
fn setup(&mut self) -> Result<()> {
if !self.input_path.exists() {
return Err(BenchError::scenario_failed(
self.name(),
format!("Input file does not exist: {}", self.input_path.display()),
));
}
Ok(())
}
fn execute(&mut self) -> Result<()> {
#[cfg(feature = "raster")]
{
}
#[cfg(not(feature = "raster"))]
{
return Err(BenchError::missing_dependency("oxigdal-geotiff", "raster"));
}
Ok(())
}
fn teardown(&mut self) -> Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_geotiff_read_scenario_creation() {
let scenario = GeoTiffReadScenario::new("/tmp/test.tif").with_tile_size(256, 256);
assert_eq!(scenario.name(), "geotiff_read");
assert_eq!(scenario.tile_size, Some((256, 256)));
}
#[test]
fn test_geotiff_write_scenario_creation() {
let scenario =
GeoTiffWriteScenario::new("/tmp/output.tif", 512, 512).with_compression("lzw");
assert_eq!(scenario.name(), "geotiff_write");
assert_eq!(scenario.compression, "lzw");
}
#[test]
fn test_compression_benchmark_creation() {
let scenario = CompressionBenchmarkScenario::new("/tmp/input.tif", "/tmp/output");
assert_eq!(scenario.name(), "raster_compression");
assert!(!scenario.compression_methods.is_empty());
}
}