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};