Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a driver manager wrapper #324

Merged
merged 5 commits into from Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 7 additions & 3 deletions CHANGES.md
Expand Up @@ -23,15 +23,19 @@

- <https://github.com/georust/gdal/pull/308>

- Added quality-of-life features to `CslStringList`: `len`, `is_empty`, `Debug` and `Iterator` implementations.
- Added quality-of-life features to `CslStringList`: `len`, `is_empty`, `Debug` and `Iterator` implementations.

- <https://github.com/georust/gdal/pull/311>

- Added ability to set color table for bands with palette color interpretation.
- Added ability to set color table for bands with palette color interpretation.
Added ability to create a color ramp (interpolated) color table.

- <https://github.com/georust/gdal/pull/314>

- Added a wrapper for the `DriverManager`

- <https://github.com/georust/gdal/pull/324>

## 0.13

- Add prebuild bindings for GDAL 3.5
Expand Down Expand Up @@ -110,7 +114,7 @@

- Added `Geometry::to_geo` method for GDAL to geo-types Geometry conversions.

- <https://github.com/georust/gdal/pull/295>
- <https://github.com/georust/gdal/pull/295>

- Add `Rasterband::set_scale` and `Rasterband::set_offset` methods

Expand Down
2 changes: 1 addition & 1 deletion examples/metadata.rs
Expand Up @@ -2,7 +2,7 @@ fn main() {
use gdal::{Dataset, Metadata};
use std::path::Path;

let driver = gdal::Driver::get_by_name("mem").unwrap();
let driver = gdal::DriverManager::get_driver_by_name("mem").unwrap();
println!("driver description: {:?}", driver.description());

let path = Path::new("./fixtures/tinymarble.png");
Expand Down
6 changes: 3 additions & 3 deletions examples/read_write_ogr.rs
@@ -1,7 +1,7 @@
use gdal::errors::Result;
use gdal::spatial_ref::{CoordTransform, SpatialRef};
use gdal::vector::*;
use gdal::{Dataset, Driver};
use gdal::Dataset;
use gdal::{vector::*, DriverManager};
use std::fs;
use std::path::Path;

Expand All @@ -17,7 +17,7 @@ fn run() -> Result<()> {
// Create a new dataset:
let path = std::env::temp_dir().join("abcde.shp");
let _ = fs::remove_file(&path);
let drv = Driver::get_by_name("ESRI Shapefile")?;
let drv = DriverManager::get_driver_by_name("ESRI Shapefile")?;
let mut ds = drv.create_vector_only(path.to_str().unwrap())?;
let lyr = ds.create_layer(Default::default())?;

Expand Down
6 changes: 3 additions & 3 deletions examples/read_write_ogr_datetime.rs
@@ -1,9 +1,9 @@
use gdal::vector::LayerAccess;
use gdal::{vector::LayerAccess, DriverManager};

fn run() -> gdal::errors::Result<()> {
use chrono::Duration;
use gdal::vector::{Defn, Feature, FieldDefn, FieldValue};
use gdal::{Dataset, Driver};
use gdal::Dataset;
use std::ops::Add;
use std::path::Path;

Expand All @@ -15,7 +15,7 @@ fn run() -> gdal::errors::Result<()> {
// Create a new dataset:
let path = std::env::temp_dir().join("later.geojson");
let _ = std::fs::remove_file(&path);
let drv = Driver::get_by_name("GeoJSON")?;
let drv = DriverManager::get_driver_by_name("GeoJSON")?;
let mut ds = drv.create_vector_only(path.to_str().unwrap())?;
let lyr = ds.create_layer(Default::default())?;

Expand Down
6 changes: 3 additions & 3 deletions examples/write_ogr.rs
@@ -1,13 +1,13 @@
use gdal::errors::Result;
use gdal::vector::{Defn, Feature, FieldDefn, FieldValue, Geometry, LayerAccess, OGRFieldType};
use gdal::Driver;
use gdal::DriverManager;
use std::fs;

/// Example 1, the detailed way:
fn example_1() -> Result<()> {
let path = std::env::temp_dir().join("output1.geojson");
let _ = fs::remove_file(&path);
let drv = Driver::get_by_name("GeoJSON")?;
let drv = DriverManager::get_driver_by_name("GeoJSON")?;
let mut ds = drv.create_vector_only(path.to_str().unwrap())?;

let lyr = ds.create_layer(Default::default())?;
Expand Down Expand Up @@ -52,7 +52,7 @@ fn example_1() -> Result<()> {
fn example_2() -> Result<()> {
let path = std::env::temp_dir().join("output2.geojson");
let _ = fs::remove_file(&path);
let driver = Driver::get_by_name("GeoJSON")?;
let driver = DriverManager::get_driver_by_name("GeoJSON")?;
let mut ds = driver.create_vector_only(path.to_str().unwrap())?;
let mut layer = ds.create_layer(Default::default())?;

Expand Down
165 changes: 144 additions & 21 deletions src/driver.rs
Expand Up @@ -17,11 +17,7 @@ use crate::errors::*;
static START: Once = Once::new();

pub fn _register_drivers() {
unsafe {
START.call_once(|| {
gdal_sys::GDALAllRegister();
});
}
START.call_once(DriverManager::register_all);
}

/// # Raster and Vector Driver API
Expand Down Expand Up @@ -63,14 +59,9 @@ impl Driver {
/// ```text
/// Cloud optimized GeoTIFF generator
/// ```
#[deprecated(note = "Please use `DriverManager::get_driver_by_name()` instead")]
pub fn get_by_name(name: &str) -> Result<Driver> {
_register_drivers();
let c_name = CString::new(name)?;
let c_driver = unsafe { gdal_sys::GDALGetDriverByName(c_name.as_ptr()) };
if c_driver.is_null() {
return Err(_last_null_pointer_err("GDALGetDriverByName"));
};
Ok(Driver { c_driver })
DriverManager::get_driver_by_name(name)
}

/// Returns the driver with the given index, which must be less than the value returned by
Expand All @@ -92,13 +83,9 @@ impl Driver {
/// ```text
/// 'VRT' is 'Virtual Raster'
/// ```
#[deprecated(note = "Please use `DriverManager::get_driver()` instead")]
pub fn get(index: usize) -> Result<Driver> {
_register_drivers();
let c_driver = unsafe { gdal_sys::GDALGetDriver(index.try_into().unwrap()) };
if c_driver.is_null() {
return Err(_last_null_pointer_err("GDALGetDriver"));
}
Ok(Driver { c_driver })
DriverManager::get_driver(index)
}

/// Returns the number of registered drivers.
Expand All @@ -112,10 +99,9 @@ impl Driver {
/// ```text
/// 203 drivers are registered
/// ```
#[deprecated(note = "Please use `DriverManager::count()` instead")]
pub fn count() -> usize {
_register_drivers();
let count = unsafe { gdal_sys::GDALGetDriverCount() };
count.try_into().unwrap()
DriverManager::count()
}

/// Return the short name of a driver.
Expand Down Expand Up @@ -366,3 +352,140 @@ impl MajorObject for Driver {
}

impl Metadata for Driver {}

/// A wrapper around `GDALDriverManager`.
/// This struct helps listing and registering [`Driver`]s.
pub struct DriverManager;

impl DriverManager {
/// Returns the number of registered drivers.
///
/// # Example
///
/// ```rust, no_run
/// use gdal::Driver;
/// println!("{} drivers are registered", Driver::count());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Driver is to be deprecated, should these examples be updated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/// ```
/// ```text
/// 203 drivers are registered
/// ```
pub fn count() -> usize {
_register_drivers();
let count = unsafe { gdal_sys::GDALGetDriverCount() };
count
.try_into()
.expect("The returned count should be zero or positive")
}

/// Returns the driver with the given index, which must be less than the value returned by
/// `Driver::count()`.
///
/// See also: [`count`](Self::count)
///
/// # Example
///
/// ```rust, no_run
/// use gdal::Driver;
/// # fn main() -> gdal::errors::Result<()> {
/// assert!(Driver::count() > 0);
/// let d = Driver::get(0)?;
/// println!("'{}' is '{}'", d.short_name(), d.long_name());
/// # Ok(())
/// # }
/// ```
/// ```text
/// 'VRT' is 'Virtual Raster'
/// ```
pub fn get_driver(index: usize) -> Result<Driver> {
_register_drivers();
let c_driver = unsafe { gdal_sys::GDALGetDriver(index.try_into().unwrap()) };
if c_driver.is_null() {
Copy link
Member

@lnicola lnicola Oct 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think GDALGetDriver sets the last error: https://github.com/OSGeo/gdal/blob/master/gcore/gdal_priv.h#L1734. _last_null_pointer_err might return a bogus error here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return Err(_last_null_pointer_err("GDALGetDriver"));
}
Ok(Driver { c_driver })
}

/// Returns the driver with the given short name or [`Err`] if not found.
///
/// See also: [`count`](Self::count), [`get`](Self::get)
///
/// # Example
///
/// ```rust, no_run
/// use gdal::Driver;
/// # fn main() -> gdal::errors::Result<()> {
/// let cog_driver = Driver::get_by_name("COG")?;
/// println!("{}", cog_driver.long_name());
/// # Ok(())
/// # }
/// ```
/// ```text
/// Cloud optimized GeoTIFF generator
/// ```
pub fn get_driver_by_name(name: &str) -> Result<Driver> {
_register_drivers();
let c_name = CString::new(name)?;
let c_driver = unsafe { gdal_sys::GDALGetDriverByName(c_name.as_ptr()) };
if c_driver.is_null() {
return Err(_last_null_pointer_err("GDALGetDriverByName"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

};
Ok(Driver { c_driver })
}

/// Register a driver for use.
///
/// Wraps [`GDALRegisterDriver()`](https://gdal.org/api/raster_c_api.html#_CPPv418GDALRegisterDriver11GDALDriverH)
pub fn register_driver(driver: &Driver) -> usize {
let index = unsafe { gdal_sys::GDALRegisterDriver(driver.c_driver) };
Copy link
Member

@lnicola lnicola Oct 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not impossible, but it's pretty hard to end up needing to call this (because we do _register_drivers in Get*). But we should have it, of course.

index
.try_into()
.expect("The returned index should be zero or positive")
}

/// Deregister the passed driver.
///
/// Wraps [`GDALDeregisterDriver()`](https://gdal.org/api/raster_c_api.html#_CPPv420GDALDeregisterDriver11GDALDriverH)
pub fn deregister_driver(driver: &Driver) {
unsafe {
gdal_sys::GDALDeregisterDriver(driver.c_driver);
}
}

/// Register all known GDAL drivers.
///
/// Wraps [`GDALAllRegister()`](https://gdal.org/api/raster_c_api.html#gdal_8h_1a9d40bc998bd6ed07ccde96028e85ae26)
pub fn register_all() {
unsafe {
gdal_sys::GDALAllRegister();
}
}

/// Prevents the automatic registration of all known GDAL drivers when first calling create, open, etc.
pub fn prevent_auto_registration() {
START.call_once(|| {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

}

/// Destroys the driver manager, i.e., unloads all drivers.
///
/// Wraps [`GDALDestroyDriverManager()`](https://gdal.org/api/raster_c_api.html#_CPPv417GDALDestroyDriver11GDALDriverH)
pub fn destroy() {
unsafe {
gdal_sys::GDALDestroyDriverManager();
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_driver_access() {
let driver = DriverManager::get_driver_by_name("GTiff").unwrap();
assert_eq!(driver.short_name(), "GTiff");
assert_eq!(driver.long_name(), "GeoTIFF");

assert!(DriverManager::count() > 0);
assert!(DriverManager::get_driver(0).is_ok());
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Expand Up @@ -121,7 +121,7 @@ pub use dataset::{
Dataset, DatasetOptions, GdalOpenFlags, GeoTransform, GeoTransformEx, LayerIterator,
LayerOptions, Transaction,
};
pub use driver::Driver;
pub use driver::{Driver, DriverManager};
pub use metadata::Metadata;

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions src/programs/raster/mdimtranslate.rs
Expand Up @@ -230,7 +230,7 @@ mod tests {

use super::*;

use crate::{DatasetOptions, Driver, GdalOpenFlags};
use crate::{DatasetOptions, DriverManager, GdalOpenFlags};

#[test]
#[cfg_attr(not(all(major_ge_3, minor_ge_4)), ignore)]
Expand Down Expand Up @@ -277,7 +277,7 @@ mod tests {
};
let dataset = Dataset::open_ex(&fixture, dataset_options).unwrap();

let driver = Driver::get_by_name("MEM").unwrap();
let driver = DriverManager::get_driver_by_name("MEM").unwrap();
let output_dataset = driver.create("", 5, 7, 1).unwrap();

let error = multi_dim_translate(
Expand Down