1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//!# Unofficial high-level safe Rust bindings to ecCodes library
//!
//!This crate contains safe high-level bindings for ecCodes library.
//!Bindings can be considered safe mainly because all crate structures
//!will take ownership of the data in memory before passing the raw pointer to ecCodes.
//!**Currently only reading of GRIB files is supported.**
//!
//!Because of the ecCodes library API characteristics theses bindings are
//!rather thick wrapper to make this crate safe and convenient to use.
//!
//!Because ecCodes supports mainly Linux platforms, this crate is not tested on other architectures.
//!
//!If you want to see more features released quicker do not hesitate
//!to contribute and check out [Github repository](https://github.com/ScaleWeather/eccodes).
//!
//![ecCodes](https://confluence.ecmwf.int/display/ECC/ecCodes+Home) is an open-source library
//!for reading and writing GRIB and BUFR files developed by [European Centre for Medium-Range Weather Forecasts](https://www.ecmwf.int/).
//!
//!## Usage
//!
//!### Accessing GRIB files
//!
//!This crate provides an access to GRIB file by creating a
//![`CodesHandle`](codes_handle::CodesHandle) and reading messages from the file with it.
//!
//!The [`CodesHandle`](codes_handle::CodesHandle) can be constructed in two ways:
//!
//!- The main option is to use [`new_from_file()`](codes_handle::CodesHandle::new_from_file) function
//!to open a file under provided [`path`](`std::path::Path`) with filesystem,
//!when copying whole file into memory is not desired or not necessary.
//!
//!- Alternatively [`new_from_memory()`](codes_handle::CodesHandle::new_from_memory) function can be used
//!to access a file that is already in memory. For example, when file is downloaded from the internet
//!and does not need to be saved on hard drive.
//!The file must be stored in [`bytes::Bytes`](https://docs.rs/bytes/1.1.0/bytes/struct.Bytes.html).
//!
//!Data (messages) inside the GRIB file can be accessed using the [`FallibleIterator`](`codes_handle::CodesHandle#impl-FallibleIterator`)
//!by iterating over the `CodesHandle`.
//!
//!The `FallibleIterator` returns a [`KeyedMessage`](codes_handle::KeyedMessage) structure which implements some
//!methods to access data values. The data inside `KeyedMessage` is provided directly as [`Key`](codes_handle::Key)
//!or as more specific data type.
//!
//!#### Example
//!
//!```
//!// We are reading the mean sea level pressure for 4 gridpoints
//!// nearest to Reykjavik (64.13N, -21.89E) for 1st June 2021 00:00 UTC 
//!// from ERA5 Climate Reanalysis
//!
//!// Open the GRIB file and create the CodesHandle
//!# use eccodes::codes_handle::{ProductKind, CodesHandle, KeyedMessage};
//!# use eccodes::errors::{CodesError};
//!# use std::path::Path;
//!# use eccodes::codes_handle::KeyType::Str;
//!# use eccodes::FallibleIterator;
//!#
//!# fn main() -> Result<(), CodesError> {
//!let file_path = Path::new("./data/iceland.grib");
//!let product_kind = ProductKind::GRIB;
//!
//!let handle = CodesHandle::new_from_file(file_path, product_kind)?;
//!
//!// Use iterator to get a Keyed message with shortName "msl" and typeOfLevel "surface"
//!// First, filter and collect the messages to get those that we want
//!let mut level: Vec<KeyedMessage> = handle
//!    .filter(|msg| {
//!
//!    Ok(msg.read_key("shortName")?.value == Str("msl".to_string())
//!        && msg.read_key("typeOfLevel")?.value == Str("surface".to_string()))
//!    })
//!    .collect()?;
//!
//!// Now unwrap and access the first and only element of resulting vector
//!// Find nearest modifies internal KeyedMessage fields so we need mutable reference
//!let level = &mut level[0];
//!
//!// Get the four nearest gridpoints of Reykjavik
//!let nearest_gridpoints = level.find_nearest(64.13, -21.89)?;
//!
//!// Print value and distance of the nearest gridpoint
//!println!("value: {}, distance: {}", 
//!    nearest_gridpoints[3].value, 
//!    nearest_gridpoints[3].distance);
//!# Ok(())
//!# }
//!```
//!
//!### Writing GRIB files
//!
//!The crate provides a basic support for setting `KeyedMessage` keys 
//!and writing GRIB files. The easiests (and safest) way to create a 
//!new custom message is to copy exisitng one from other GRIB file,
//!modify the keys and write to new file.
//!
//!#### Example
//!
//!```rust
//!# use eccodes::{
//!#     codes_handle::{
//!#         CodesHandle, Key,
//!#         KeyType::{self, FloatArray, Int, Str},
//!#         KeyedMessage,
//!#         ProductKind::{self, GRIB},
//!#     },
//!#     FallibleIterator,
//!# };
//!# use std::{fs::remove_file, path::Path};
//!# use eccodes::errors::CodesError;
//!#
//!# fn main() -> Result<(), CodesError> {
//!// We are computing the temperature at 850hPa as an average
//!// of 900hPa and 800hPa and writing it to a new file.
//!let file_path = Path::new("./data/iceland-levels.grib");
//!let handle = CodesHandle::new_from_file(file_path, GRIB)?;
//!
//!// Get messages with temperature levels
//!let t_levels: Vec<KeyedMessage> = handle
//!    .filter(|msg| Ok(msg.read_key("shortName")?.value == Str("t".to_string())))
//!    .collect()?;
//!
//!// Get any message to edit it later
//!let mut new_msg = t_levels[0].clone();
//!
//!// Get temperatures at 800hPa and 900hPa
//!let mut t800 = vec![];
//!let mut t900 = vec![];
//!
//!for msg in t_levels {
//!    if msg.read_key("level")?.value == Int(800) {
//!        if let FloatArray(vals) = msg.read_key("values")?.value {
//!            t800 = vals;
//!        }
//!    }
//!
//!    if msg.read_key("level")?.value == Int(900) {
//!        if let FloatArray(vals) = msg.read_key("values")?.value {
//!            t900 = vals;
//!        }
//!    }
//!}
//!
//!// Compute temperature at 850hPa
//!let t850: Vec<f64> = t800
//!    .iter()
//!    .zip(t900.iter())
//!    .map(|t| (t.0 + t.1) / 2.0)
//!    .collect();
//!
//!// Edit appropriate keys in the editable message
//!new_msg
//!    .write_key(Key {
//!        name: "level".to_string(),
//!        value: Int(850),
//!    })?;
//!new_msg
//!    .write_key(Key {
//!        name: "values".to_string(),
//!        value: FloatArray(t850),
//!    })?;
//!
//!// Save the message to a new file without appending
//!new_msg
//!    .write_to_file(Path::new("iceland-850.grib"), false)?;
//!#
//!# remove_file(Path::new("iceland-850.grib")).unwrap();
//!# Ok(())
//!# }
//!```
//!
//!### ecCodes installation
//!
//!This crate uses [eccodes-sys](https://crates.io/crates/eccodes-sys) with default options to link ecCodes.
//!Check `eccodes-sys` website for more details on how it links the library.
//!
//!The recommended way to install ecCodes on your computer is using your package manager.
//!For example, on Ubuntu you can use `apt-get`:
//!
//!```text
//!$ sudo apt-get install libeccodes-dev
//!```
//!
//!Alternatively, you can install the library manually from source in suitable directory
//!following [this instructions](https://confluence.ecmwf.int/display/ECC/ecCodes+installation).
//!
//!Then add the `lib/pkgconfig` directory from your ecCodes installation directory
//!to the `PKG_CONFIG_PATH` environmental variable. If ecCodes have been compiled
//!as shared library you will also need to specify `LD_LIBRARY_PATH`.
//!For example:
//!
//!```text
//!$ export PKG_CONFIG_PATH=<your_eccodes_path>/lib/pkgconfig
//!$ export LD_LIBRARY_PATH=<your_eccodes_path>/lib
//!```
//!
//!### Features
//!
//!- `docs` - builds the crate without linking ecCodes, particularly useful when building the documentation
//!on [docs.rs](https://docs.rs/). For more details check documentation of [eccodes-sys](https://crates.io/crates/eccodes-sys).
//!
//!To build your own crate with this crate as dependency on docs.rs without linking ecCodes add following lines to your `Cargo.toml`
//!
//!```text
//![package.metadata.docs.rs]
//!features = ["eccodes/docs"]
//!```
//!

pub mod codes_handle;
pub mod errors;
mod intermediate_bindings;

pub use fallible_iterator::{FallibleIterator, IntoFallibleIterator, FromFallibleIterator};