diff --git a/src/raster/processing/dem/aspect.rs b/src/raster/processing/dem/aspect.rs index a787cc57..20cd9f9f 100644 --- a/src/raster/processing/dem/aspect.rs +++ b/src/raster/processing/dem/aspect.rs @@ -1,13 +1,15 @@ +use std::num::NonZeroUsize; + use super::options::common_dem_options; use crate::cpl::CslStringList; +use crate::errors; use crate::raster::processing::dem::DemSlopeAlg; -use std::num::NonZeroUsize; /// Configuration options for [`aspect()`][super::aspect()]. #[derive(Debug, Clone, Default)] pub struct AspectOptions { input_band: Option, - compute_edges: bool, + compute_edges: Option, output_format: Option, additional_options: CslStringList, algorithm: Option, @@ -45,25 +47,25 @@ impl AspectOptions { /// Render relevant common options into [`CslStringList`] values, as compatible with /// [`gdal_sys::GDALDEMProcessing`]. - pub fn to_options_list(&self) -> CslStringList { + pub fn to_options_list(&self) -> errors::Result { let mut opts = CslStringList::default(); - self.store_common_options_to(&mut opts); + self.store_common_options_to(&mut opts)?; if let Some(alg) = self.algorithm { - opts.add_string("-alg").unwrap(); - opts.add_string(&alg.to_string()).unwrap(); + opts.add_string("-alg")?; + opts.add_string(alg.to_gdal_option())?; } if self.zero_for_flat == Some(true) { - opts.add_string("-zero_for_flat").unwrap(); + opts.add_string("-zero_for_flat")?; } if self.trigonometric == Some(true) { - opts.add_string("-trigonometric").unwrap(); + opts.add_string("-trigonometric")?; } - opts + Ok(opts) } } @@ -93,7 +95,7 @@ mod tests { let expected: CslStringList = "-compute_edges -b 2 -of GTiff CPL_DEBUG=ON -alg ZevenbergenThorne -zero_for_flat -trigonometric" .parse()?; - assert_eq!(expected.to_string(), proc.to_options_list().to_string()); + assert_eq!(expected.to_string(), proc.to_options_list()?.to_string()); Ok(()) } diff --git a/src/raster/processing/dem/color_relief.rs b/src/raster/processing/dem/color_relief.rs index 230a8c9c..7597c6f8 100644 --- a/src/raster/processing/dem/color_relief.rs +++ b/src/raster/processing/dem/color_relief.rs @@ -2,13 +2,14 @@ use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; use crate::cpl::CslStringList; +use crate::errors; use crate::raster::processing::dem::options::common_dem_options; /// Configuration options for [`color_relief()`][super::color_relief()]. #[derive(Debug, Clone)] pub struct ColorReliefOptions { input_band: Option, - compute_edges: bool, + compute_edges: Option, output_format: Option, additional_options: CslStringList, color_config: PathBuf, @@ -43,7 +44,7 @@ impl ColorReliefOptions { /// /// # Example /// Here's an example `.clr` file showing a number of the features described above. - /// + /// /// ```text /// 2600 white /// 2000 235 220 175 @@ -57,7 +58,7 @@ impl ColorReliefOptions { pub fn new>(color_config: P) -> Self { Self { input_band: None, - compute_edges: false, + compute_edges: None, output_format: None, additional_options: Default::default(), color_config: color_config.as_ref().to_path_buf(), @@ -74,11 +75,6 @@ impl ColorReliefOptions { self } - /// Get path to the color relief configuration file. - pub fn color_config(&self) -> PathBuf { - self.color_config.to_owned() - } - /// Specify the color matching mode. /// /// See [`ColorMatchingMode`] for details. @@ -87,31 +83,28 @@ impl ColorReliefOptions { self } - /// Get the color matching mode to be used. - pub fn color_matching_mode(&self) -> ColorMatchingMode { - self.color_matching_mode + pub(crate) fn color_config(&self) -> &Path { + &self.color_config } /// Render relevant common options into [`CslStringList`] values, as compatible with /// [`gdal_sys::GDALDEMProcessing`]. - pub fn to_options_list(&self) -> CslStringList { + pub fn to_options_list(&self) -> errors::Result { let mut opts = CslStringList::default(); - self.store_common_options_to(&mut opts); + self.store_common_options_to(&mut opts)?; if self.alpha == Some(true) { - opts.add_string("-alpha").unwrap(); + opts.add_string("-alpha")?; } match self.color_matching_mode { - ColorMatchingMode::ExactColorEntry => opts.add_string("-exact_color_entry").unwrap(), - ColorMatchingMode::NearestColorEntry => { - opts.add_string("-nearest_color_entry").unwrap() - } + ColorMatchingMode::ExactColorEntry => opts.add_string("-exact_color_entry")?, + ColorMatchingMode::NearestColorEntry => opts.add_string("-nearest_color_entry")?, _ => {} } - opts + Ok(opts) } } @@ -155,7 +148,7 @@ mod tests { let expected: CslStringList = "-compute_edges -b 2 -of GTiff CPL_DEBUG=ON -alpha -nearest_color_entry".parse()?; - assert_eq!(expected.to_string(), proc.to_options_list().to_string()); + assert_eq!(expected.to_string(), proc.to_options_list()?.to_string()); Ok(()) } diff --git a/src/raster/processing/dem/hillshade.rs b/src/raster/processing/dem/hillshade.rs index 44e771d9..a72db0bc 100644 --- a/src/raster/processing/dem/hillshade.rs +++ b/src/raster/processing/dem/hillshade.rs @@ -1,14 +1,15 @@ +use std::num::NonZeroUsize; + use crate::cpl::CslStringList; +use crate::errors; use crate::raster::processing::dem::options::common_dem_options; use crate::raster::processing::dem::DemSlopeAlg; -use std::fmt::{Display, Formatter}; -use std::num::NonZeroUsize; /// Configuration options for [`hillshade()`][super::hillshade()]. #[derive(Debug, Clone, Default)] pub struct HillshadeOptions { input_band: Option, - compute_edges: bool, + compute_edges: Option, output_format: Option, additional_options: CslStringList, algorithm: Option, @@ -33,11 +34,6 @@ impl HillshadeOptions { self } - /// Fetch the specified slope computation algorithm - pub fn algorithm(&self) -> Option { - self.algorithm - } - /// Specify the altitude of the light, in degrees. /// /// `90` if the light comes from above the DEM, `0` if it is raking light. @@ -46,11 +42,6 @@ impl HillshadeOptions { self } - /// Fetch the specified light altitude, in degrees. - pub fn altitude(&self) -> Option { - self.altitude - } - /// Specify the azimuth of the light, in degrees: /// /// * `0` if it comes from the top of the raster, @@ -82,13 +73,6 @@ impl HillshadeOptions { self } - /// Fetch the specified scaling factor. - /// - /// Returns `None` if one has not been previously set vai [`Self::with_scale`]. - pub fn scale(&self) -> Option { - self.scale - } - /// Specify the shading mode to render with. /// /// See [`ShadingMode`] for mode descriptions. @@ -97,59 +81,49 @@ impl HillshadeOptions { self } - /// Fetch the specified shading mode. - pub fn shading_mode(&self) -> Option { - self.shading - } - /// Vertical exaggeration used to pre-multiply the elevations pub fn with_z_factor(&mut self, z_factor: f64) -> &mut Self { self.z_factor = Some(z_factor); self } - /// Fetch the applied z-factor value. - pub fn z_factor(&self) -> Option { - self.z_factor - } - /// Render relevant common options into [`CslStringList`] values, as compatible with /// [`gdal_sys::GDALDEMProcessing`]. - pub fn to_options_list(&self) -> CslStringList { + pub fn to_options_list(&self) -> errors::Result { let mut opts = CslStringList::default(); - self.store_common_options_to(&mut opts); + self.store_common_options_to(&mut opts)?; if let Some(alg) = self.algorithm { - opts.add_string("-alg").unwrap(); - opts.add_string(&alg.to_string()).unwrap(); + opts.add_string("-alg")?; + opts.add_string(alg.to_gdal_option())?; } if let Some(scale) = self.scale { - opts.add_string("-s").unwrap(); - opts.add_string(&scale.to_string()).unwrap(); + opts.add_string("-s")?; + opts.add_string(&scale.to_string())?; } if let Some(mode) = self.shading { - opts.add_string(&format!("-{mode}")).unwrap(); + opts.add_string(mode.to_gdal_option())?; } if let Some(factor) = self.z_factor { - opts.add_string("-z").unwrap(); - opts.add_string(&factor.to_string()).unwrap(); + opts.add_string("-z")?; + opts.add_string(&factor.to_string())?; } if let Some(altitude) = self.altitude { - opts.add_string("-alt").unwrap(); - opts.add_string(&altitude.to_string()).unwrap(); + opts.add_string("-alt")?; + opts.add_string(&altitude.to_string())?; } if let Some(azimuth) = self.azimuth { - opts.add_string("-az").unwrap(); - opts.add_string(&azimuth.to_string()).unwrap(); + opts.add_string("-az")?; + opts.add_string(&azimuth.to_string())?; } - opts + Ok(opts) } } @@ -172,10 +146,13 @@ pub enum ShadingMode { Igor, } -impl Display for ShadingMode { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let s = format!("{self:?}"); - f.write_str(&s.to_lowercase()) +impl ShadingMode { + fn to_gdal_option(self) -> &'static str { + match self { + ShadingMode::Combined => "-combined", + ShadingMode::Multidirectional => "-multidirectional", + ShadingMode::Igor => "-igor", + } } } @@ -208,7 +185,7 @@ mod tests { let expected: CslStringList = "-compute_edges -b 2 -of GTiff CPL_DEBUG=ON -alg ZevenbergenThorne -s 98473 -igor -z 2 -alt 45 -az 330" .parse()?; - assert_eq!(expected.to_string(), proc.to_options_list().to_string()); + assert_eq!(expected.to_string(), proc.to_options_list()?.to_string()); Ok(()) } diff --git a/src/raster/processing/dem/mod.rs b/src/raster/processing/dem/mod.rs index 12bdb199..3b02a72c 100644 --- a/src/raster/processing/dem/mod.rs +++ b/src/raster/processing/dem/mod.rs @@ -23,7 +23,7 @@ //! use std::ffi::{CStr, CString}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::ptr; use libc::c_int; @@ -106,7 +106,7 @@ pub fn aspect>( ds, dest_file.as_ref(), DemAlg::Aspect, - &options.to_options_list(), + &options.to_options_list()?, None, ) } @@ -166,7 +166,7 @@ pub fn color_relief>( ds, dest_file.as_ref(), DemAlg::ColorRelief, - &options.to_options_list(), + &options.to_options_list()?, Some(colors), ) } @@ -224,7 +224,7 @@ pub fn hillshade>( ds, dest_file.as_ref(), DemAlg::Hillshade, - &options.to_options_list(), + &options.to_options_list()?, None, ) } @@ -274,7 +274,7 @@ pub fn roughness>( ds, dest_file.as_ref(), DemAlg::Roughness, - &options.to_options_list(), + &options.to_options_list()?, None, ) } @@ -333,7 +333,7 @@ pub fn slope>( ds, dest_file.as_ref(), DemAlg::Slope, - &options.to_options_list(), + &options.to_options_list()?, None, ) } @@ -372,7 +372,7 @@ pub fn slope>( /// std_dev: 0.48943078832474257, /// } /// ``` -/// +/// /// See: [`gdaldem tpi`](https://gdal.org/programs/gdaldem.html#tpi) for details. pub fn topographic_position_index>( ds: &Dataset, @@ -383,7 +383,7 @@ pub fn topographic_position_index>( ds, dest_file.as_ref(), DemAlg::Tpi, - &options.to_options_list(), + &options.to_options_list()?, None, ) } @@ -433,7 +433,7 @@ pub fn terrain_ruggedness_index>( ds, dest_file.as_ref(), DemAlg::Tri, - &options.to_options_list(), + &options.to_options_list()?, None, ) } @@ -444,10 +444,10 @@ fn dem_eval( dst_file: &Path, alg: DemAlg, options: &CslStringList, - color_relief_config: Option, + color_relief_config: Option<&Path>, ) -> Result { let popts = options::GdalDEMProcessingOptions::new(options)?; - let mode = CString::new(alg.to_string())?; + let mode = CString::new(alg.to_gdal_option())?; let dest = _path_to_c_string(dst_file)?; let cfile = color_relief_config.and_then(|p| _path_to_c_string(&p).ok()); let cfile_ptr = cfile.as_deref().map(CStr::as_ptr).unwrap_or(ptr::null()); diff --git a/src/raster/processing/dem/options.rs b/src/raster/processing/dem/options.rs index 76b33113..b56fa647 100644 --- a/src/raster/processing/dem/options.rs +++ b/src/raster/processing/dem/options.rs @@ -1,5 +1,3 @@ -use std::fmt::{Display, Formatter}; -use std::marker::PhantomData; use std::ptr; use std::ptr::NonNull; @@ -12,18 +10,17 @@ use crate::errors; use crate::utils::_last_null_pointer_err; /// Payload for [`GDALDEMProcessing`]. Intended for internal use only. -pub struct GdalDEMProcessingOptions<'opts>( - NonNull, - PhantomData<&'opts CslStringList>, -); +pub struct GdalDEMProcessingOptions(NonNull); -impl<'opts> GdalDEMProcessingOptions<'opts> { - pub fn new(opts: &'opts CslStringList) -> errors::Result { +impl GdalDEMProcessingOptions { + pub fn new(opts: &CslStringList) -> errors::Result { + // GDAL copies the relevant value out of `opts`, we don't need to keep them alive: + // https://github.com/OSGeo/gdal/blob/59eaaed3168f49e8a7a3821730277aff68a86d16/apps/gdaldem_lib.cpp#L3770 let popts = unsafe { GDALDEMProcessingOptionsNew(opts.as_ptr(), ptr::null_mut()) }; - if popts.is_null() { - return Err(_last_null_pointer_err("GDALDEMProcessingOptionsNew")); + match NonNull::new(popts) { + Some(popts) => Ok(Self(popts)), + None => Err(_last_null_pointer_err("GDALDEMProcessingOptionsNew")), } - Ok(Self(unsafe { NonNull::new_unchecked(popts) }, PhantomData)) } pub fn as_ptr(&self) -> *const GDALDEMProcessingOptions { @@ -31,7 +28,7 @@ impl<'opts> GdalDEMProcessingOptions<'opts> { } } -impl Drop for GdalDEMProcessingOptions<'_> { +impl Drop for GdalDEMProcessingOptions { fn drop(&mut self) { unsafe { GDALDEMProcessingOptionsFree(self.0.as_ptr()) }; } @@ -49,14 +46,16 @@ pub enum DemAlg { Tri, } -impl Display for DemAlg { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { +impl DemAlg { + pub(super) fn to_gdal_option(self) -> &'static str { match self { - Self::ColorRelief => f.write_str("color-relief"), - _ => { - let s = format!("{self:?}").to_lowercase(); - f.write_str(&s) - } + DemAlg::Aspect => "aspect", + DemAlg::ColorRelief => "color-relief", + DemAlg::Hillshade => "hillshade", + DemAlg::Roughness => "roughness", + DemAlg::Slope => "slope", + DemAlg::Tpi => "TPI", + DemAlg::Tri => "TRI", } } } @@ -71,9 +70,12 @@ pub enum DemSlopeAlg { ZevenbergenThorne, } -impl Display for DemSlopeAlg { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("{self:?}")) +impl DemSlopeAlg { + pub(super) fn to_gdal_option(self) -> &'static str { + match self { + DemSlopeAlg::Horn => "Horn", + DemSlopeAlg::ZevenbergenThorne => "ZevenbergenThorne", + } } } @@ -87,11 +89,6 @@ macro_rules! common_dem_options { self } - /// Fetch the specified input band to read from. - pub fn input_band(&self) -> Option { - self.input_band - } - /// Explicitly specify output raster format. /// /// This is equivalent to the `-of ` CLI flag accepted by many GDAL tools. @@ -116,55 +113,42 @@ macro_rules! common_dem_options { self } - /// Fetch the specified output format driver identifier. - pub fn output_format(&self) -> Option { - self.output_format.clone() - } - /// Compute values at image edges. /// /// If true, causes interpolation of values at image edges or if a no-data value is found /// in the 3x3 processing window. pub fn with_compute_edges(&mut self, state: bool) -> &mut Self { - self.compute_edges = state; + self.compute_edges = Some(state); self } - /// Fetch the compute edges mode. - pub fn compute_edges(&self) -> bool { - self.compute_edges - } - /// Additional generic options to be included. pub fn with_additional_options(&mut self, extra_options: CslStringList) -> &mut Self { self.additional_options.extend(&extra_options); self } - /// Fetch additional options. - pub fn additional_options(&self) -> &CslStringList { - &self.additional_options - } - /// Private utility to convert common options into [`CslStringList`] options. - fn store_common_options_to(&self, opts: &mut CslStringList) { - if self.compute_edges { - opts.add_string("-compute_edges").unwrap(); + fn store_common_options_to(&self, opts: &mut CslStringList) -> errors::Result<()> { + if matches!(self.compute_edges, Some(true)) { + opts.add_string("-compute_edges")?; } if let Some(band) = self.input_band { - opts.add_string("-b").unwrap(); - opts.add_string(&band.to_string()).unwrap(); + opts.add_string("-b")?; + opts.add_string(&band.to_string())?; } if let Some(of) = &self.output_format { - opts.add_string("-of").unwrap(); - opts.add_string(of).unwrap(); + opts.add_string("-of")?; + opts.add_string(of)?; } if !self.additional_options.is_empty() { opts.extend(&self.additional_options); } + + Ok(()) } }; } diff --git a/src/raster/processing/dem/roughness.rs b/src/raster/processing/dem/roughness.rs index 089c8418..64d9332a 100644 --- a/src/raster/processing/dem/roughness.rs +++ b/src/raster/processing/dem/roughness.rs @@ -1,13 +1,15 @@ +use std::num::NonZeroUsize; + use crate::cpl::CslStringList; +use crate::errors; use crate::raster::processing::dem::options::common_dem_options; -use std::num::NonZeroUsize; /// Configuration options for [`roughness()`][super::roughness()]. #[derive(Debug, Clone, Default)] pub struct RoughnessOptions { input_band: Option, - compute_edges: bool, + compute_edges: Option, output_format: Option, additional_options: CslStringList, } @@ -22,10 +24,10 @@ impl RoughnessOptions { /// Render relevant options into [`CslStringList`] values, as compatible with /// [`gdal_sys::GDALDEMProcessing`]. - pub fn to_options_list(&self) -> CslStringList { + pub fn to_options_list(&self) -> errors::Result { let mut opts = CslStringList::new(); - self.store_common_options_to(&mut opts); - opts + self.store_common_options_to(&mut opts)?; + Ok(opts) } } @@ -49,7 +51,7 @@ mod tests { .with_additional_options("CPL_DEBUG=ON".parse()?); let expected: CslStringList = "-compute_edges -b 2 -of GTiff CPL_DEBUG=ON".parse()?; - assert_eq!(expected.to_string(), proc.to_options_list().to_string()); + assert_eq!(expected.to_string(), proc.to_options_list()?.to_string()); Ok(()) } diff --git a/src/raster/processing/dem/slope.rs b/src/raster/processing/dem/slope.rs index f1e8b8fd..bb9890b5 100644 --- a/src/raster/processing/dem/slope.rs +++ b/src/raster/processing/dem/slope.rs @@ -1,13 +1,15 @@ +use std::num::NonZeroUsize; + use crate::cpl::CslStringList; +use crate::errors; use crate::raster::processing::dem::options::common_dem_options; use crate::raster::processing::dem::DemSlopeAlg; -use std::num::NonZeroUsize; /// Configuration options for [`slope()`][super::slope()]. #[derive(Debug, Clone, Default)] pub struct SlopeOptions { input_band: Option, - compute_edges: bool, + compute_edges: Option, output_format: Option, additional_options: CslStringList, algorithm: Option, @@ -29,11 +31,6 @@ impl SlopeOptions { self } - /// Fetch the specified slope computation algorithm. - pub fn algorithm(&self) -> Option { - self.algorithm - } - /// Apply a elevation scaling factor. /// /// Routine assumes x, y and z units are identical. @@ -52,13 +49,6 @@ impl SlopeOptions { self } - /// Fetch the specified scaling factor. - /// - /// Returns `None` if one has not been previously set via [`Self::with_scale`]. - pub fn scale(&self) -> Option { - self.scale - } - /// If `state` is `true`, the slope will be expressed as percent slope. /// /// Otherwise, it is expressed as degrees @@ -69,26 +59,26 @@ impl SlopeOptions { /// Render relevant common options into [`CslStringList`] values, as compatible with /// [`gdal_sys::GDALDEMProcessing`]. - pub fn to_options_list(&self) -> CslStringList { + pub fn to_options_list(&self) -> errors::Result { let mut opts = CslStringList::default(); - self.store_common_options_to(&mut opts); + self.store_common_options_to(&mut opts)?; if let Some(alg) = self.algorithm { - opts.add_string("-alg").unwrap(); - opts.add_string(&alg.to_string()).unwrap(); + opts.add_string("-alg")?; + opts.add_string(alg.to_gdal_option())?; } if let Some(scale) = self.scale { - opts.add_string("-s").unwrap(); - opts.add_string(&scale.to_string()).unwrap(); + opts.add_string("-s")?; + opts.add_string(&scale.to_string())?; } if self.percentage_results == Some(true) { - opts.add_string("-p").unwrap(); + opts.add_string("-p")?; } - opts + Ok(opts) } } @@ -118,7 +108,7 @@ mod tests { let expected: CslStringList = "-compute_edges -b 2 -of GTiff CPL_DEBUG=ON -alg ZevenbergenThorne -s 98473 -p" .parse()?; - assert_eq!(expected.to_string(), proc.to_options_list().to_string()); + assert_eq!(expected.to_string(), proc.to_options_list()?.to_string()); Ok(()) } diff --git a/src/raster/processing/dem/tpi.rs b/src/raster/processing/dem/tpi.rs index 574a846e..d5218762 100644 --- a/src/raster/processing/dem/tpi.rs +++ b/src/raster/processing/dem/tpi.rs @@ -1,12 +1,14 @@ +use std::num::NonZeroUsize; + use crate::cpl::CslStringList; +use crate::errors; use crate::raster::processing::dem::options::common_dem_options; -use std::num::NonZeroUsize; /// Configuration options for [`topographic_position_index()`][super::topographic_position_index()]. #[derive(Debug, Clone, Default)] pub struct TpiOptions { input_band: Option, - compute_edges: bool, + compute_edges: Option, output_format: Option, additional_options: CslStringList, } @@ -21,10 +23,10 @@ impl TpiOptions { /// Render options into [`CslStringList`] values, as compatible with /// [`gdal_sys::GDALDEMProcessing`]. - pub fn to_options_list(&self) -> CslStringList { + pub fn to_options_list(&self) -> errors::Result { let mut opts = CslStringList::new(); - self.store_common_options_to(&mut opts); - opts + self.store_common_options_to(&mut opts)?; + Ok(opts) } } @@ -48,7 +50,7 @@ mod tests { .with_additional_options("CPL_DEBUG=ON".parse()?); let expected: CslStringList = "-compute_edges -b 2 -of GTiff CPL_DEBUG=ON".parse()?; - assert_eq!(expected.to_string(), proc.to_options_list().to_string()); + assert_eq!(expected.to_string(), proc.to_options_list()?.to_string()); Ok(()) } diff --git a/src/raster/processing/dem/tri.rs b/src/raster/processing/dem/tri.rs index 57242fd8..a7ba31ec 100644 --- a/src/raster/processing/dem/tri.rs +++ b/src/raster/processing/dem/tri.rs @@ -1,14 +1,14 @@ -use std::fmt::{Display, Formatter}; use std::num::NonZeroUsize; use crate::cpl::CslStringList; +use crate::errors; use crate::raster::processing::dem::options::common_dem_options; /// Configuration options for [`terrain_ruggedness_index()`][super::terrain_ruggedness_index()]. #[derive(Debug, Clone, Default)] pub struct TriOptions { input_band: Option, - compute_edges: bool, + compute_edges: Option, output_format: Option, additional_options: CslStringList, algorithm: Option, @@ -30,21 +30,21 @@ impl TriOptions { /// Render relevant common options into [`CslStringList`] values, as compatible with /// [`gdal_sys::GDALDEMProcessing`]. - pub fn to_options_list(&self) -> CslStringList { + pub fn to_options_list(&self) -> errors::Result { let mut opts = CslStringList::default(); - self.store_common_options_to(&mut opts); + self.store_common_options_to(&mut opts)?; // Before 3.3, Wilson is the only algorithm and therefore there's no - // selection option. Rust caller can still specify Wilson, but - // we don't pass it along. + // selection option. + // Callers can still specify Wilson, but we don't pass it along. #[cfg(all(major_is_3, minor_ge_3))] if let Some(alg) = self.algorithm { - opts.add_string("-alg").unwrap(); - opts.add_string(&alg.to_string()).unwrap(); + opts.add_string("-alg")?; + opts.add_string(alg.to_gdal_option())?; } - opts + Ok(opts) } } @@ -66,9 +66,13 @@ pub enum DemTriAlg { Riley, } -impl Display for DemTriAlg { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("{self:?}")) +impl DemTriAlg { + fn to_gdal_option(self) -> &'static str { + match self { + DemTriAlg::Wilson => "Wilson", + #[cfg(all(major_is_3, minor_ge_3))] + DemTriAlg::Riley => "Riley", + } } } @@ -96,7 +100,7 @@ mod tests { let expected: CslStringList = "-compute_edges -b 2 -of GTiff CPL_DEBUG=ON -alg Wilson".parse()?; - assert_eq!(expected.to_string(), opts.to_options_list().to_string()); + assert_eq!(expected.to_string(), opts.to_options_list()?.to_string()); Ok(()) }