ogc_cql2/ds/
csv.rs

1// SPDX-License-Identifier: Apache-2.0
2
3#![warn(missing_docs)]
4
5//! Geospatial data stored in CSV files.
6//!
7
8use crate::ds::DataSource;
9use std::path::PathBuf;
10
11/// [DataSource] of Features and [Resource][1]s mapped from CSV rows/records.
12///
13/// [1]: type.Resource.html
14#[derive(Debug)]
15pub struct CSVDataSource {
16    path: PathBuf,
17}
18
19impl DataSource for CSVDataSource {}
20
21impl CSVDataSource {
22    /// Constructor given the file system location of an accessible CSV file.
23    pub fn from(s: &str) -> Self {
24        Self { path: s.into() }
25    }
26
27    /// Return this CSV data source path.
28    pub fn path(&self) -> &PathBuf {
29        &self.path
30    }
31}
32
33/// Macro to generate a concrete [CSVDataSource].
34///
35/// Caller must provide the following parameters:
36/// * $vis: Visibility specifier of the generated artifacts.
37/// * $name: Prefix of the concrete data source structure name to materialize.
38///   The final name will have a 'CSV' suffix appended; eg. `Foo` -> `FooCSV`.
39/// * $path: Path to a readable CSV file.
40/// * $feature: `serde` deserializable structure that maps rows to Features.
41#[macro_export]
42macro_rules! gen_csv_ds {
43    ($vis:vis, $name:expr, $path:expr, $feature:expr) => {
44        paste::paste! {
45            /// Concrete data source.
46            #[derive(Debug)]
47            $vis struct [<$name CSV>](CSVDataSource);
48
49            impl [<$name CSV>] {
50                /// Construct a new CSV data source.
51                $vis fn new() -> Self {
52                    Self(CSVDataSource::from($path))
53                }
54
55                /// Return a file reader that deserializes rows into features.
56                $vis fn reader(&self) -> Result<::csv::Reader<File>, MyError> {
57                    let file = File::open(self.0.path())?;
58                    Ok(::csv::Reader::from_reader(file))
59                }
60            }
61
62            impl ::core::fmt::Display for [<$name CSV>] {
63                fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
64                    write!(f, "{}CSV({})", $name, $path)
65                }
66            }
67
68            impl IterableDS for [<$name CSV>] {
69                type Item = $feature;
70                type Err = MyError;
71
72                fn iter(&self) -> Result<impl Iterator<Item = Result<$feature, Self::Err>>, Self::Err> {
73                    let file = File::open(&self.0.path())?;
74                    let rdr = ::csv::Reader::from_reader(file);
75                    let it = rdr.into_deserialize().map(|res| res.map_err(MyError::from));
76                    Ok(it)
77                }
78            }
79        }
80    }
81}