Skip to content

Commit c283989

Browse files
authored
Merge pull request #155 from dmarteau/gdal-open-flags
Support extended flags for open_ex
2 parents ed97cfe + fb619b1 commit c283989

File tree

3 files changed

+162
-37
lines changed

3 files changed

+162
-37
lines changed

CHANGES.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
# Changes
22

33
## Unreleased
4+
* **Breaking**: Use `DatasetOptions` to pass as `Dataset::open_ex` parameters and
5+
add support for extended open flags.
6+
7+
```rust
8+
use gdal::{ Dataset, DatasetOptions }
9+
10+
let dataset = Dataset::open_ex(
11+
"roads.geojson",
12+
DatasetOptions {
13+
open_flags: GdalOpenFlags::GDAL_OF_UPDATE|GdalOpenFlags::GDAL_OF_VECTOR,
14+
..DatasetOptions::default()
15+
}
16+
)
17+
.unwrap();
18+
```
19+
20+
`GDALAccess` values are supported usinf [`From`] implementation
21+
22+
```rust
23+
Dataset::open_ex(
24+
"roads.geojson",
25+
DatasetOptions {
26+
open_flags: GDALAccess::GA_Update.into(),
27+
..DatasetOptions::default()
28+
},
29+
)
30+
.unwrap();
31+
```
32+
433
* Add more functions to SpatialRef implementation
534
* <https://github.com/georust/gdal/pull/145>
635
* **Breaking**: Change `Feature::field` return type from

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ geo-types = { version = "0.7.0" }
2323
gdal-sys = { path = "gdal-sys", version = "^0.3"}
2424
ndarray = {version = "0.14", optional = true }
2525
chrono = { version = "0.4", optional = true }
26+
bitflags = "1.2"
2627

2728
[build-dependencies]
2829
gdal-sys = { path = "gdal-sys", version="^0.3"}

src/dataset.rs

Lines changed: 132 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ use crate::{
88
use gdal_sys::{
99
self, CPLErr, GDALAccess, GDALDatasetH, GDALMajorObjectH, OGRErr, OGRLayerH, OGRwkbGeometryType,
1010
};
11-
use libc::{c_double, c_int};
11+
use libc::{c_double, c_int, c_uint};
1212
use ptr::null_mut;
1313

1414
use crate::errors::*;
1515
use std::convert::TryInto;
1616

17+
use bitflags::bitflags;
18+
1719
pub type GeoTransform = [c_double; 6];
1820
static START: Once = Once::new();
1921

@@ -30,6 +32,73 @@ pub fn _register_drivers() {
3032
}
3133
}
3234

35+
// GDal extended open flags, skipped by bindgen
36+
//
37+
// Note that the `GDAL_OF_SHARED` option is removed from the set
38+
// of allowed option because it subverts the [`Send`] implementation
39+
// that allow passing the dataset the another thread.
40+
// See https://github.com/georust/gdal/issues/154.
41+
#[cfg(major_ge_2)]
42+
bitflags! {
43+
pub struct GdalOpenFlags: c_uint {
44+
const GDAL_OF_READONLY = 0x00;
45+
// Open in update mode.
46+
const GDAL_OF_UPDATE = 0x01;
47+
// Allow raster and vector drivers to be used.
48+
const GDAL_OF_ALL = 0x00;
49+
// Allow raster drivers to be used.
50+
const GDAL_OF_RASTER = 0x02;
51+
// Allow vector drivers to be used.
52+
const GDAL_OF_VECTOR = 0x04;
53+
// Allow gnm drivers to be used.
54+
#[cfg(all(major_ge_2,minor_ge_1))]
55+
const GDAL_OF_GNM = 0x08;
56+
// Allow multidimensional raster drivers to be used.
57+
#[cfg(all(major_ge_3,minor_ge_1))]
58+
const GDAL_OF_MULTIDIM_RASTER = 0x10;
59+
// Emit error message in case of failed open.
60+
const GDAL_OF_VERBOSE_ERROR = 0x40;
61+
// Open as internal dataset. Such dataset isn't registered in the global list
62+
// of opened dataset. Cannot be used with GDAL_OF_SHARED.
63+
const GDAL_OF_INTERNAL = 0x80;
64+
// Let GDAL decide if a array-based or hashset-based storage strategy for
65+
// cached blocks must be used.
66+
// GDAL_OF_DEFAULT_BLOCK_ACCESS, GDAL_OF_ARRAY_BLOCK_ACCESS and
67+
// GDAL_OF_HASHSET_BLOCK_ACCESS are mutually exclusive.
68+
#[cfg(all(major_ge_2,minor_ge_1))]
69+
const GDAL_OF_DEFAULT_BLOCK_ACCESS = 0;
70+
#[cfg(all(major_ge_2,minor_ge_1))]
71+
const GDAL_OF_ARRAY_BLOCK_ACCESS = 0x100;
72+
#[cfg(all(major_ge_2,minor_ge_1))]
73+
const GDAL_OF_HASHSET_BLOCK_ACCESS = 0x200;
74+
}
75+
}
76+
77+
impl Default for GdalOpenFlags {
78+
fn default() -> GdalOpenFlags {
79+
GdalOpenFlags::GDAL_OF_READONLY
80+
}
81+
}
82+
83+
impl From<GDALAccess::Type> for GdalOpenFlags {
84+
fn from(val: GDALAccess::Type) -> GdalOpenFlags {
85+
if val == GDALAccess::GA_Update {
86+
GdalOpenFlags::GDAL_OF_UPDATE
87+
} else {
88+
GdalOpenFlags::GDAL_OF_READONLY
89+
}
90+
}
91+
}
92+
93+
// Open parameters
94+
#[derive(Debug, Default)]
95+
pub struct DatasetOptions<'a> {
96+
pub open_flags: GdalOpenFlags,
97+
pub allowed_drivers: Option<&'a [&'a str]>,
98+
pub open_options: Option<&'a [&'a str]>,
99+
pub sibling_files: Option<&'a [&'a str]>,
100+
}
101+
33102
// GDAL Docs state: The returned dataset should only be accessed by one thread at a time.
34103
// See: https://gdal.org/api/raster_c_api.html#_CPPv48GDALOpenPKc10GDALAccess
35104
// Additionally, VRT Datasets are not safe before GDAL 2.3.
@@ -47,24 +116,18 @@ impl Dataset {
47116
}
48117

49118
pub fn open(path: &Path) -> Result<Dataset> {
50-
Self::open_ex(path, None, None, None, None)
119+
Self::open_ex(path, DatasetOptions::default())
51120
}
52121

53-
pub fn open_ex(
54-
path: &Path,
55-
open_flags: Option<GDALAccess::Type>,
56-
allowed_drivers: Option<&[&str]>, // TODO: use parameters
57-
open_options: Option<&[&str]>,
58-
sibling_files: Option<&[&str]>,
59-
) -> Result<Dataset> {
122+
pub fn open_ex(path: &Path, options: DatasetOptions) -> Result<Dataset> {
60123
_register_drivers();
61124
let filename = path.to_string_lossy();
62125
let c_filename = CString::new(filename.as_ref())?;
63-
let c_open_flags = open_flags.unwrap_or(GDALAccess::GA_ReadOnly); // This defaults to GdalAccess::GA_ReadOnly
126+
let c_open_flags = options.open_flags.bits;
64127

65128
// handle driver params:
66129
// we need to keep the CStrings and the pointers around
67-
let c_allowed_drivers = allowed_drivers.map(|d| {
130+
let c_allowed_drivers = options.allowed_drivers.map(|d| {
68131
d.iter()
69132
.map(|&s| CString::new(s))
70133
.collect::<std::result::Result<Vec<CString>, NulError>>()
@@ -77,15 +140,15 @@ impl Dataset {
77140
let mut c_drivers_ptrs = c_drivers_vec.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
78141
c_drivers_ptrs.push(ptr::null());
79142

80-
let c_drivers_ptr = if allowed_drivers.is_some() {
143+
let c_drivers_ptr = if options.allowed_drivers.is_some() {
81144
c_drivers_ptrs.as_ptr()
82145
} else {
83146
ptr::null()
84147
};
85148

86149
// handle open options params:
87150
// we need to keep the CStrings and the pointers around
88-
let c_open_options = open_options.map(|d| {
151+
let c_open_options = options.open_options.map(|d| {
89152
d.iter()
90153
.map(|&s| CString::new(s))
91154
.collect::<std::result::Result<Vec<CString>, NulError>>()
@@ -101,15 +164,15 @@ impl Dataset {
101164
.collect::<Vec<_>>();
102165
c_open_options_ptrs.push(ptr::null());
103166

104-
let c_open_options_ptr = if open_options.is_some() {
167+
let c_open_options_ptr = if options.open_options.is_some() {
105168
c_open_options_ptrs.as_ptr()
106169
} else {
107170
ptr::null()
108171
};
109172

110173
// handle sibling files params:
111174
// we need to keep the CStrings and the pointers around
112-
let c_sibling_files = sibling_files.map(|d| {
175+
let c_sibling_files = options.sibling_files.map(|d| {
113176
d.iter()
114177
.map(|&s| CString::new(s))
115178
.collect::<std::result::Result<Vec<CString>, NulError>>()
@@ -125,7 +188,7 @@ impl Dataset {
125188
.collect::<Vec<_>>();
126189
c_sibling_files_ptrs.push(ptr::null());
127190

128-
let c_sibling_files_ptr = if sibling_files.is_some() {
191+
let c_sibling_files_ptr = if options.sibling_files.is_some() {
129192
c_sibling_files_ptrs.as_ptr()
130193
} else {
131194
ptr::null()
@@ -576,10 +639,11 @@ mod tests {
576639

577640
let ds = Dataset::open_ex(
578641
&temp_path,
579-
Some(GDALAccess::GA_Update),
580-
Some(&["GPKG"]),
581-
None,
582-
None,
642+
DatasetOptions {
643+
open_flags: GDALAccess::GA_Update.into(),
644+
allowed_drivers: Some(&["GPKG"]),
645+
..DatasetOptions::default()
646+
},
583647
)
584648
.unwrap();
585649
(temp_path, ds)
@@ -598,10 +662,10 @@ mod tests {
598662
fn test_open_ex_ro_vector() {
599663
Dataset::open_ex(
600664
fixture!("roads.geojson"),
601-
Some(GDALAccess::GA_ReadOnly),
602-
None,
603-
None,
604-
None,
665+
DatasetOptions {
666+
open_flags: GDALAccess::GA_ReadOnly.into(),
667+
..DatasetOptions::default()
668+
},
605669
)
606670
.unwrap();
607671
}
@@ -610,10 +674,10 @@ mod tests {
610674
fn test_open_ex_update_vector() {
611675
Dataset::open_ex(
612676
fixture!("roads.geojson"),
613-
Some(GDALAccess::GA_Update),
614-
None,
615-
None,
616-
None,
677+
DatasetOptions {
678+
open_flags: GDALAccess::GA_Update.into(),
679+
..DatasetOptions::default()
680+
},
617681
)
618682
.unwrap();
619683
}
@@ -622,31 +686,62 @@ mod tests {
622686
fn test_open_ex_allowed_driver_vector() {
623687
Dataset::open_ex(
624688
fixture!("roads.geojson"),
625-
None,
626-
Some(&["GeoJSON"]),
627-
None,
628-
None,
689+
DatasetOptions {
690+
allowed_drivers: Some(&["GeoJSON"]),
691+
..DatasetOptions::default()
692+
},
629693
)
630694
.unwrap();
631695
}
632696

633697
#[test]
634698
fn test_open_ex_allowed_driver_vector_fail() {
635-
Dataset::open_ex(fixture!("roads.geojson"), None, Some(&["TIFF"]), None, None).unwrap_err();
699+
Dataset::open_ex(
700+
fixture!("roads.geojson"),
701+
DatasetOptions {
702+
allowed_drivers: Some(&["TIFF"]),
703+
..DatasetOptions::default()
704+
},
705+
)
706+
.unwrap_err();
636707
}
637708

638709
#[test]
639710
fn test_open_ex_open_option() {
640711
Dataset::open_ex(
641712
fixture!("roads.geojson"),
642-
None,
643-
None,
644-
Some(&["FLATTEN_NESTED_ATTRIBUTES=YES"]),
645-
None,
713+
DatasetOptions {
714+
open_options: Some(&["FLATTEN_NESTED_ATTRIBUTES=YES"]),
715+
..DatasetOptions::default()
716+
},
646717
)
647718
.unwrap();
648719
}
649720

721+
#[test]
722+
fn test_open_ex_extended_flags_vector() {
723+
Dataset::open_ex(
724+
fixture!("roads.geojson"),
725+
DatasetOptions {
726+
open_flags: GdalOpenFlags::GDAL_OF_UPDATE | GdalOpenFlags::GDAL_OF_VECTOR,
727+
..DatasetOptions::default()
728+
},
729+
)
730+
.unwrap();
731+
}
732+
733+
#[test]
734+
fn test_open_ex_extended_flags_vector_fail() {
735+
Dataset::open_ex(
736+
fixture!("roads.geojson"),
737+
DatasetOptions {
738+
open_flags: GdalOpenFlags::GDAL_OF_UPDATE | GdalOpenFlags::GDAL_OF_RASTER,
739+
..DatasetOptions::default()
740+
},
741+
)
742+
.unwrap_err();
743+
}
744+
650745
#[test]
651746
fn test_layer_count() {
652747
let ds = Dataset::open(fixture!("roads.geojson")).unwrap();

0 commit comments

Comments
 (0)