use std::ptr;
use fallible_streaming_iterator::FallibleStreamingIterator;
use crate::{
errors::CodesError,
intermediate_bindings::{codes_handle_delete, codes_handle_new_from_file},
CodesHandle, KeyedMessage,
};
#[cfg(feature = "experimental_index")]
use crate::{intermediate_bindings::codes_handle_new_from_index, CodesIndex};
use super::GribFile;
impl FallibleStreamingIterator for CodesHandle<GribFile> {
type Item = KeyedMessage;
type Error = CodesError;
fn advance(&mut self) -> Result<(), Self::Error> {
unsafe {
codes_handle_delete(self.unsafe_message.message_handle)?;
}
self.unsafe_message.message_handle = ptr::null_mut();
let new_eccodes_handle =
unsafe { codes_handle_new_from_file(self.source.pointer, self.product_kind)? };
self.unsafe_message = KeyedMessage {
message_handle: new_eccodes_handle,
};
Ok(())
}
fn get(&self) -> Option<&Self::Item> {
if self.unsafe_message.message_handle.is_null() {
None
} else {
Some(&self.unsafe_message)
}
}
}
#[cfg(feature = "experimental_index")]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental_index")))]
impl FallibleStreamingIterator for CodesHandle<CodesIndex> {
type Item = KeyedMessage;
type Error = CodesError;
fn advance(&mut self) -> Result<(), Self::Error> {
unsafe {
codes_handle_delete(self.unsafe_message.message_handle)?;
}
self.unsafe_message.message_handle = ptr::null_mut();
let new_eccodes_handle = unsafe { codes_handle_new_from_index(self.source.pointer)? };
self.unsafe_message = KeyedMessage {
message_handle: new_eccodes_handle,
};
Ok(())
}
fn get(&self) -> Option<&Self::Item> {
if self.unsafe_message.message_handle.is_null() {
None
} else {
Some(&self.unsafe_message)
}
}
}
#[cfg(test)]
mod tests {
use crate::{
codes_handle::{CodesHandle, ProductKind},
KeyType,
};
use anyhow::{Context, Ok, Result};
use fallible_streaming_iterator::FallibleStreamingIterator;
use std::path::Path;
#[test]
fn iterator_lifetimes() -> Result<()> {
let file_path = Path::new("./data/iceland-levels.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
let msg1 = handle.next()?.context("Message not some")?;
let key1 = msg1.read_key("typeOfLevel")?;
let msg2 = handle.next()?.context("Message not some")?;
let key2 = msg2.read_key("typeOfLevel")?;
let msg3 = handle.next()?.context("Message not some")?;
let key3 = msg3.read_key("typeOfLevel")?;
assert_eq!(key1.value, KeyType::Str("isobaricInhPa".to_string()));
assert_eq!(key2.value, KeyType::Str("isobaricInhPa".to_string()));
assert_eq!(key3.value, KeyType::Str("isobaricInhPa".to_string()));
Ok(())
}
#[test]
fn iterator_fn() -> Result<()> {
let file_path = Path::new("./data/iceland-surface.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
while let Some(msg) = handle.next()? {
let key = msg.read_key("shortName")?;
match key.value {
KeyType::Str(_) => {}
_ => panic!("Incorrect variant of string key"),
}
}
Ok(())
}
#[test]
fn iterator_collected() -> Result<()> {
let file_path = Path::new("./data/iceland-surface.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
let mut handle_collected = vec![];
while let Some(msg) = handle.next()? {
handle_collected.push(msg.try_clone()?);
}
for msg in handle_collected {
let key = msg.read_key("name")?;
match key.value {
KeyType::Str(_) => {}
_ => panic!("Incorrect variant of string key"),
}
}
Ok(())
}
#[test]
fn iterator_return() -> Result<()> {
let file_path = Path::new("./data/iceland-surface.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
let current_message = handle.next()?.context("Message not some")?;
assert!(!current_message.message_handle.is_null());
Ok(())
}
#[test]
fn iterator_beyond_none() -> Result<()> {
let file_path = Path::new("./data/iceland-surface.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
assert!(handle.next()?.is_some());
assert!(handle.next()?.is_some());
assert!(handle.next()?.is_some());
assert!(handle.next()?.is_some());
assert!(handle.next()?.is_some());
assert!(handle.next()?.is_none());
assert!(handle.next()?.is_none());
assert!(handle.next()?.is_none());
assert!(handle.next()?.is_none());
Ok(())
}
#[test]
fn iterator_filter() -> Result<()> {
let file_path = Path::new("./data/iceland.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
let mut level = vec![];
while let Some(msg) = handle.next()? {
if msg.read_key("shortName")?.value == KeyType::Str("msl".to_string())
&& msg.read_key("typeOfLevel")?.value == KeyType::Str("surface".to_string())
{
level.push(msg.try_clone()?);
}
}
let level = &level[0];
println!("{:?}", level.read_key("shortName"));
let nearest_gridpoints = level.codes_nearest()?.find_nearest(64.13, -21.89)?;
println!(
"value: {}, distance: {}",
nearest_gridpoints[3].value, nearest_gridpoints[3].distance
);
Ok(())
}
}