gdal/programs/raster/
vrt.rs

1use std::{
2    borrow::Borrow,
3    ffi::{c_char, c_int, CString},
4    path::Path,
5    ptr::{null, null_mut},
6};
7
8use gdal_sys::GDALBuildVRTOptions;
9
10use crate::{
11    errors::*,
12    utils::{_last_null_pointer_err, _path_to_c_string},
13    Dataset,
14};
15
16/// Wraps a [GDALBuildVRTOptions] object.
17///
18/// [GDALBuildVRTOptions]: https://gdal.org/api/gdal_utils.html#_CPPv419GDALBuildVRTOptions
19pub struct BuildVRTOptions {
20    c_options: *mut GDALBuildVRTOptions,
21}
22
23impl BuildVRTOptions {
24    /// See [GDALBuildVRTOptionsNew].
25    ///
26    /// [GDALBuildVRTOptionsNew]: https://gdal.org/api/gdal_utils.html#_CPPv422GDALBuildVRTOptionsNewPPcP28GDALBuildVRTOptionsForBinary
27    pub fn new<S: Into<Vec<u8>>, I: IntoIterator<Item = S>>(args: I) -> Result<Self> {
28        // Convert args to CStrings to add terminating null bytes
29        let cstr_args = args
30            .into_iter()
31            .map(CString::new)
32            .collect::<std::result::Result<Vec<_>, _>>()?;
33
34        // Get pointers to the strings
35        // These strings don't actually get modified, the C API is just not const-correct
36        // Null-terminate the list
37        let mut c_args = cstr_args
38            .iter()
39            .map(|x| x.as_ptr() as *mut c_char)
40            .chain(std::iter::once(null_mut()))
41            .collect::<Vec<_>>();
42
43        unsafe {
44            Ok(Self {
45                c_options: gdal_sys::GDALBuildVRTOptionsNew(c_args.as_mut_ptr(), null_mut()),
46            })
47        }
48    }
49
50    /// Returns the wrapped C pointer
51    ///
52    /// # Safety
53    /// This method returns a raw C pointer
54    pub unsafe fn c_options(&self) -> *mut GDALBuildVRTOptions {
55        self.c_options
56    }
57}
58
59impl Drop for BuildVRTOptions {
60    fn drop(&mut self) {
61        unsafe {
62            gdal_sys::GDALBuildVRTOptionsFree(self.c_options);
63        }
64    }
65}
66
67/// Build a VRT from a list of datasets.
68/// Wraps [GDALBuildVRT].
69/// See the [program docs] for more details.
70///
71/// [GDALBuildVRT]: https://gdal.org/api/gdal_utils.html#gdal__utils_8h_1a057aaea8b0ed0476809a781ffa377ea4
72/// [program docs]: https://gdal.org/programs/gdalbuildvrt.html
73pub fn build_vrt<D: Borrow<Dataset>>(
74    dest: Option<&Path>,
75    datasets: &[D],
76    options: Option<BuildVRTOptions>,
77) -> Result<Dataset> {
78    _build_vrt(
79        dest,
80        &datasets
81            .iter()
82            .map(|x| x.borrow())
83            .collect::<Vec<&Dataset>>(),
84        options,
85    )
86}
87
88fn _build_vrt(
89    dest: Option<&Path>,
90    datasets: &[&Dataset],
91    options: Option<BuildVRTOptions>,
92) -> Result<Dataset> {
93    // Convert dest to CString
94    let dest = dest.map(_path_to_c_string).transpose()?;
95    let c_dest = dest.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
96
97    let c_options = options
98        .as_ref()
99        .map(|x| x.c_options as *const GDALBuildVRTOptions)
100        .unwrap_or(null());
101
102    let dataset_out = unsafe {
103        // Get raw handles to the datasets
104        let mut datasets_raw: Vec<gdal_sys::GDALDatasetH> =
105            datasets.iter().map(|x| x.c_dataset()).collect();
106
107        gdal_sys::GDALBuildVRT(
108            c_dest,
109            datasets_raw.len() as c_int,
110            datasets_raw.as_mut_ptr(),
111            null(),
112            c_options,
113            null_mut(),
114        )
115    };
116
117    if dataset_out.is_null() {
118        return Err(_last_null_pointer_err("GDALBuildVRT"));
119    }
120
121    let result = unsafe { Dataset::from_c_dataset(dataset_out) };
122
123    Ok(result)
124}