Skip to content

Commit

Permalink
make keys iterator names only
Browse files Browse the repository at this point in the history
  • Loading branch information
Quba1 committed Jul 24, 2024
1 parent a22d21e commit b22cd86
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 50 deletions.
42 changes: 22 additions & 20 deletions src/keyed_message/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ use crate::{

impl KeyedMessage {
/// Method to get a [`Key`] with provided name from the `KeyedMessage`, if it exists.
///
///
/// This function check the type of requested key and tries to read it as the native type.
/// That flow adds performance overhead, but makes the function highly unlikely to fail.
///
///
/// This function will try to retrieve the key of native string type as string even
/// when the nul byte is not positioned at the end of key value.
///
///
/// If retrieving the key value in native type fails this function will try to read
/// the requested key as bytes.
///
///
/// # Example
///
///
/// ```
/// use eccodes::{ProductKind, CodesHandle, KeyType};
/// # use std::path::Path;
Expand All @@ -41,19 +41,19 @@ impl KeyedMessage {
/// # Ok(())
/// # }
/// ```
///
///
/// # Errors
///
///
/// Returns [`CodesNotFound`](crate::errors::CodesInternal::CodesNotFound)
/// when a key of given name has not been found in the message.
///
///
/// Returns [`CodesError::MissingKey`] when a given key does not have a specified type.
///
///
/// Returns [`CodesError::Internal`] when one of internal ecCodes functions to read the key fails.
///
///
/// Returns [`CodesError::CstrUTF8`] and [`CodesError::NulChar`] when the string returned by ecCodes
/// library cannot be parsed as valid UTF8 Rust string.
///
///
/// Returns [`CodesError::IncorrectKeySize`] when the size of given key is lower than 1. This indicates corrupted data file,
/// bug in the crate or bug in the ecCodes library. If you encounter this error please check
/// if your file is correct and report it on Github.
Expand Down Expand Up @@ -90,7 +90,7 @@ impl KeyedMessage {
Err(err) => Err(err),
}
} else {
return Err(CodesError::IncorrectKeySize)
return Err(CodesError::IncorrectKeySize);
}
}
NativeKeyType::Double => {
Expand Down Expand Up @@ -118,7 +118,7 @@ impl KeyedMessage {
Err(err) => Err(err),
}
} else {
return Err(CodesError::IncorrectKeySize)
return Err(CodesError::IncorrectKeySize);
}
}
NativeKeyType::Bytes => {
Expand Down Expand Up @@ -170,7 +170,7 @@ mod tests {
use anyhow::{Context, Result};

use crate::codes_handle::{CodesHandle, ProductKind};
use crate::{FallibleIterator, FallibleStreamingIterator, DynamicKeyType};
use crate::{DynamicKeyType, FallibleIterator, FallibleStreamingIterator};
use std::path::Path;

#[test]
Expand Down Expand Up @@ -221,32 +221,34 @@ mod tests {
}

#[test]
fn era5_keys() -> Result<()> {
fn era5_keys_dynamic() -> 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 current_message = handle.next()?.context("Message not some")?;
let mut kiter = current_message.default_keys_iterator()?;

while let Some(key) = kiter.next()? {
assert!(!key.name.is_empty());
while let Some(key_name) = kiter.next()? {
assert!(!key_name.is_empty());
assert!(current_message.read_key_dynamic(&key_name).is_ok())
}

Ok(())
}

#[test]
fn gfs_keys() -> Result<()> {
fn gfs_keys_dynamic() -> Result<()> {
let file_path = Path::new("./data/gfs.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")?;
let mut kiter = current_message.default_keys_iterator()?;

while let Some(key) = kiter.next()? {
assert!(!key.name.is_empty());
while let Some(key_name) = kiter.next()? {
assert!(!key_name.is_empty());
assert!(current_message.read_key_dynamic(&key_name).is_ok())
}

Ok(())
Expand Down
57 changes: 27 additions & 30 deletions src/keys_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,32 @@
use eccodes_sys::codes_keys_iterator;
use fallible_iterator::FallibleIterator;
use log::warn;
use std::ptr::null_mut;
use std::{marker::PhantomData, ptr::null_mut};

use crate::{
errors::CodesError,
intermediate_bindings::{
codes_keys_iterator_delete, codes_keys_iterator_get_name, codes_keys_iterator_new,
codes_keys_iterator_next,
},
DynamicKey, KeyedMessage,
KeyedMessage,
};

/// Structure to iterate through keys in [`KeyedMessage`].
///
///
/// Mainly useful to discover what keys are present inside the message.
///
///
/// Implements [`FallibleIterator`] providing similar functionality to classic `Iterator`.
/// `FallibleIterator` is used because internal ecCodes functions can return internal error in some edge-cases.
/// The usage of `FallibleIterator` is sligthly different than usage of `Iterator`,
/// check the documentation for more details.
///
///
/// The `next()` function internally calls [`read_key()`](KeyedMessage::read_key()) function
/// so it is usually more efficient to call that function directly only for keys you
/// are interested in.
///
///
/// ## Example
///
///
/// ```
/// use eccodes::{ProductKind, CodesHandle, KeyedMessage, KeysIteratorFlags, KeyType};
/// # use std::path::Path;
Expand All @@ -51,15 +51,15 @@ use crate::{
/// # Ok(())
/// # }
/// ```
///
///
/// ## Errors
///
///
/// The `next()` method will return [`CodesInternal`](crate::errors::CodesInternal)
/// when internal ecCodes function returns non-zero code.
#[allow(clippy::module_name_repetitions)]
#[derive(Debug)]
pub struct KeysIterator<'a> {
parent_message: &'a KeyedMessage,
parent_message: PhantomData<&'a KeyedMessage>,
iterator_handle: *mut codes_keys_iterator,
next_item_exists: bool,
}
Expand Down Expand Up @@ -91,15 +91,15 @@ pub enum KeysIteratorFlags {

impl KeyedMessage {
/// Creates new [`KeysIterator`] for the message with specified flags and namespace.
///
///
/// The flags are set by providing any combination of [`KeysIteratorFlags`]
/// inside a slice. Check the documentation for the details of each flag meaning.
///
///
/// Namespace is set simply as string, eg. `"ls"`, `"time"`, `"parameter"`, `"geography"`, `"statistics"`.
/// Invalid namespace will result in empty iterator.
///
///
/// # Example
///
///
/// ```
/// use eccodes::{ProductKind, CodesHandle, KeyedMessage, KeysIteratorFlags, KeyType};
/// # use std::path::Path;
Expand Down Expand Up @@ -131,9 +131,9 @@ impl KeyedMessage {
/// # Ok(())
/// # }
/// ```
///
///
/// # Errors
///
///
/// This function returns [`CodesInternal`](crate::errors::CodesInternal) when
/// internal ecCodes function returns non-zero code.
pub fn new_keys_iterator(
Expand All @@ -148,34 +148,34 @@ impl KeyedMessage {
let next_item_exists = unsafe { codes_keys_iterator_next(iterator_handle)? };

Ok(KeysIterator {
parent_message: self,
parent_message: PhantomData,
iterator_handle,
next_item_exists,
})
}

/// Same as [`new_keys_iterator()`](KeyedMessage::new_keys_iterator) but with default
/// Same as [`new_keys_iterator()`](KeyedMessage::new_keys_iterator) but with default
/// parameters: [`AllKeys`](KeysIteratorFlags::AllKeys) flag and `""` namespace,
/// yeilding iterator over all keys in the message.
///
///
/// # Errors
///
///
/// This function returns [`CodesInternal`](crate::errors::CodesInternal) when
/// internal ecCodes function returns non-zero code.
pub fn default_keys_iterator(&self) -> Result<KeysIterator, CodesError> {
let iterator_handle = unsafe { codes_keys_iterator_new(self.message_handle, 0, "")? };
let next_item_exists = unsafe { codes_keys_iterator_next(iterator_handle)? };

Ok(KeysIterator {
parent_message: self,
parent_message: PhantomData,
iterator_handle,
next_item_exists,
})
}
}

impl FallibleIterator for KeysIterator<'_> {
type Item = DynamicKey;
type Item = String;
type Error = CodesError;

fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
Expand All @@ -188,11 +188,9 @@ impl FallibleIterator for KeysIterator<'_> {
next_item_exists = codes_keys_iterator_next(self.iterator_handle)?;
}

let key = KeyedMessage::read_key_dynamic(self.parent_message, &key_name)?;

self.next_item_exists = next_item_exists;

Ok(Some(key))
Ok(Some(key_name.to_owned()))
} else {
Ok(None)
}
Expand Down Expand Up @@ -239,13 +237,12 @@ mod tests {
KeysIteratorFlags::SkipReadOnly, //1
KeysIteratorFlags::SkipDuplicates, //32
];

let namespace = "geography";

let mut kiter = current_message.new_keys_iterator(&flags, namespace)?;

while let Some(key) = kiter.next()? {
assert!(!key.name.is_empty());
while let Some(key_name) = kiter.next()? {
assert!(!key_name.is_empty());
}

Ok(())
Expand All @@ -267,8 +264,8 @@ mod tests {

let mut kiter = current_message.new_keys_iterator(&flags, namespace)?;

while let Some(key) = kiter.next()? {
assert!(!key.name.is_empty());
while let Some(key_name) = kiter.next()? {
assert!(!key_name.is_empty());
}

Ok(())
Expand Down

0 comments on commit b22cd86

Please sign in to comment.