Skip to main content

oxigdal_core/io/
mod.rs

1//! I/O abstractions for geospatial data access
2//!
3//! This module provides traits and implementations for reading and writing
4//! geospatial data from various sources.
5//!
6//! # Features
7//!
8//! - [`DataSource`] - Synchronous data source trait
9//! - `AsyncDataSource` - Asynchronous data source trait (requires `async` feature)
10//! - [`ByteRange`] - Byte range specification for partial reads
11//! - [`RasterRead`] / [`RasterWrite`] - Raster-specific I/O traits
12//! - [`Dataset`] / [`RasterDataset`] / [`VectorDataset`] - High-level dataset traits
13
14pub mod dataset;
15mod traits;
16
17pub use dataset::{Dataset, FieldType, RasterDataset, VectorDataset};
18
19pub use traits::{
20    ByteRange, CogSupport, DataSink, DataSource, OverviewSupport, RasterRead, RasterWrite,
21};
22
23#[cfg(feature = "async")]
24pub use traits::{AsyncDataSource, AsyncRasterRead};
25
26#[cfg(feature = "std")]
27pub mod mmap;
28
29#[cfg(feature = "std")]
30pub use mmap::{MmapDataSource, MmapDataSourceRw};
31
32#[cfg(feature = "std")]
33mod file {
34    //! File-based data source implementation
35
36    use std::fs::File;
37    use std::io::{Read, Seek, SeekFrom};
38    use std::path::{Path, PathBuf};
39    use std::sync::Mutex;
40
41    use crate::error::{IoError, OxiGdalError, Result};
42    use crate::io::{ByteRange, DataSource};
43
44    /// A file-based data source
45    pub struct FileDataSource {
46        path: PathBuf,
47        file: Mutex<File>,
48        size: u64,
49    }
50
51    impl FileDataSource {
52        /// Opens a file as a data source
53        ///
54        /// # Errors
55        /// Returns an error if the file cannot be opened
56        pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
57            let path = path.as_ref().to_path_buf();
58            let file = File::open(&path).map_err(|e| {
59                OxiGdalError::Io(IoError::Read {
60                    message: format!("Failed to open file '{}': {}", path.display(), e),
61                })
62            })?;
63
64            let metadata = file.metadata().map_err(|e| {
65                OxiGdalError::Io(IoError::Read {
66                    message: format!("Failed to get file metadata: {e}"),
67                })
68            })?;
69
70            Ok(Self {
71                path,
72                file: Mutex::new(file),
73                size: metadata.len(),
74            })
75        }
76
77        /// Returns the file path
78        #[must_use]
79        pub fn path(&self) -> &Path {
80            &self.path
81        }
82    }
83
84    impl DataSource for FileDataSource {
85        fn size(&self) -> Result<u64> {
86            Ok(self.size)
87        }
88
89        fn read_range(&self, range: ByteRange) -> Result<Vec<u8>> {
90            let mut file = self.file.lock().map_err(|e| OxiGdalError::Internal {
91                message: format!("Failed to lock file mutex: {e}"),
92            })?;
93
94            file.seek(SeekFrom::Start(range.start)).map_err(|_| {
95                OxiGdalError::Io(IoError::Seek {
96                    position: range.start,
97                })
98            })?;
99
100            let len = range.len() as usize;
101            let mut buffer = vec![0u8; len];
102            file.read_exact(&mut buffer).map_err(|e| {
103                OxiGdalError::Io(IoError::Read {
104                    message: format!(
105                        "Failed to read {} bytes at offset {}: {}",
106                        len, range.start, e
107                    ),
108                })
109            })?;
110
111            Ok(buffer)
112        }
113    }
114
115    impl std::fmt::Debug for FileDataSource {
116        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117            f.debug_struct("FileDataSource")
118                .field("path", &self.path)
119                .field("size", &self.size)
120                .finish()
121        }
122    }
123}
124
125#[cfg(feature = "std")]
126pub use file::FileDataSource;