diff --git a/src/codes_handle/iterator.rs b/src/codes_handle/iterator.rs index 3f196b4..1960412 100644 --- a/src/codes_handle/iterator.rs +++ b/src/codes_handle/iterator.rs @@ -6,10 +6,11 @@ use crate::{ errors::CodesError, intermediate_bindings::{ codes_get_message_copy, codes_handle_delete, codes_handle_new_from_file, - codes_handle_new_from_message_copy, codes_index::codes_iter_next_from_index, + codes_handle_new_from_message_copy, }, - CodesIndex, }; +#[cfg(feature = "ec_index")] +use crate::{intermediate_bindings::codes_index::codes_handle_new_from_index, CodesIndex}; use super::GribFile; @@ -108,6 +109,7 @@ impl FallibleIterator for CodesHandle { } } +#[cfg(feature = "ec_index")] impl FallibleIterator for CodesHandle { type Item = KeyedMessage; @@ -117,7 +119,7 @@ impl FallibleIterator for CodesHandle { let new_eccodes_handle; unsafe { codes_handle_delete(self.eccodes_handle)?; - new_eccodes_handle = codes_iter_next_from_index(self.source.pointer); + new_eccodes_handle = codes_handle_new_from_index(self.source.pointer); } match new_eccodes_handle { diff --git a/src/codes_handle/mod.rs b/src/codes_handle/mod.rs index cea45d1..28a653c 100644 --- a/src/codes_handle/mod.rs +++ b/src/codes_handle/mod.rs @@ -2,10 +2,7 @@ //!and all associated functions and data structures #[cfg(feature = "ec_index")] -use crate::{ - codes_index::CodesIndex, - intermediate_bindings::codes_index::{codes_handle_new_from_index, codes_index_delete}, -}; +use crate::{codes_index::CodesIndex, intermediate_bindings::codes_index::codes_index_delete}; use crate::{errors::CodesError, intermediate_bindings::codes_handle_delete}; use bytes::Bytes; use eccodes_sys::{codes_handle, codes_keys_iterator, codes_nearest, ProductKind_PRODUCT_GRIB}; @@ -246,11 +243,11 @@ impl CodesHandle { ) -> Result { let file_pointer = open_with_fmemopen(&file_data)?; - let file_handle = null_mut(); + let eccodes_handle = null_mut(); Ok(CodesHandle { _data: (DataContainer::FileBytes(file_data)), - eccodes_handle: file_handle, + eccodes_handle, source: GribFile { pointer: file_pointer, }, @@ -266,15 +263,11 @@ impl CodesHandle { index: CodesIndex, product_kind: ProductKind, ) -> Result { - let handle: *mut codes_handle; - - unsafe { - handle = codes_handle_new_from_index(index.pointer)?; - } + let eccodes_handle = null_mut(); let new_handle = CodesHandle { _data: DataContainer::Empty(), //unused, index owns data - eccodes_handle: handle, + eccodes_handle, source: index, product_kind, }; @@ -327,8 +320,6 @@ pub trait SpecialDrop { impl SpecialDrop for GribFile { fn spec_drop(&mut self) { - dbg!("GribFile drop"); - //fclose() can fail in several different cases, however there is not much //that we can nor we should do about it. the promise of fclose() is that //the stream will be disassociated from the file after the call, therefore @@ -355,8 +346,6 @@ impl SpecialDrop for GribFile { #[cfg(feature = "ec_index")] impl SpecialDrop for CodesIndex { fn spec_drop(&mut self) { - dbg!("CodesIndex drop"); - unsafe { codes_index_delete(self.pointer); } @@ -377,8 +366,6 @@ impl Drop for CodesHandle { ///If any function called in the destructor returns an error warning will appear in log. ///If bugs occurs during `CodesHandle` drop please enable log output and post issue on [Github](https://github.com/ScaleWeather/eccodes). fn drop(&mut self) { - dbg!("CodesHandle drop"); - unsafe { codes_handle_delete(self.eccodes_handle).unwrap_or_else(|error| { warn!("codes_handle_delete() returned an error: {:?}", &error); @@ -395,11 +382,9 @@ impl Drop for CodesHandle { mod tests { use eccodes_sys::ProductKind_PRODUCT_GRIB; - use crate::{ - codes_handle::{CodesHandle, DataContainer, ProductKind}, - codes_index::Select, - CodesIndex, - }; + use crate::codes_handle::{CodesHandle, DataContainer, ProductKind}; + #[cfg(feature = "ec_index")] + use crate::codes_index::{CodesIndex, Select}; use log::Level; use std::path::Path; @@ -446,6 +431,7 @@ mod tests { } #[test] + #[cfg(feature = "ec_index")] fn index_constructor_and_destructor() { let file_path = Path::new("./data/iceland-surface.idx"); let index = CodesIndex::read_from_file(file_path) @@ -464,7 +450,7 @@ mod tests { let handle = CodesHandle::new_from_index(index, ProductKind::GRIB).unwrap(); assert_eq!(handle.source.pointer, i_ptr); - assert!(!handle.eccodes_handle.is_null()); + assert!(handle.eccodes_handle.is_null()); } #[tokio::test] @@ -479,11 +465,6 @@ mod tests { drop(handle); testing_logger::validate(|captured_logs| { - for cl in captured_logs { - let b = &cl.body; - - println!("{:?}", b); - } assert_eq!(captured_logs.len(), 0); }); } diff --git a/src/codes_index/mod.rs b/src/codes_index/mod.rs index f96f70d..805fb50 100644 --- a/src/codes_index/mod.rs +++ b/src/codes_index/mod.rs @@ -5,13 +5,12 @@ use crate::{ codes_handle::SpecialDrop, errors::CodesError, intermediate_bindings::codes_index::{ - codes_index_add_file, codes_index_new, codes_index_read, - codes_index_select_double, codes_index_select_long, codes_index_select_string, + codes_index_add_file, codes_index_new, codes_index_read, codes_index_select_double, + codes_index_select_long, codes_index_select_string, }, }; use eccodes_sys::codes_index; -use fs2::FileExt; -use std::{fs::OpenOptions, path::Path}; +use std::path::Path; #[derive(Debug)] #[cfg_attr(docsrs, doc(cfg(feature = "ec_index")))] @@ -55,6 +54,8 @@ impl CodesIndex { }) } + /// **WARNING: Trying to add GRIB file to a CodesIndex while GRIB's index file (or GRIB itself) + /// is in use can cause segfault, panic or error.** #[cfg_attr(docsrs, doc(cfg(feature = "ec_index")))] pub fn add_grib_file(self, index_file_path: &Path) -> Result { let file_path = index_file_path.to_str().ok_or_else(|| { @@ -112,10 +113,10 @@ mod tests { use crate::{ codes_index::{CodesIndex, Select}, - CodesHandle, KeyedMessage, + CodesHandle, }; use crate::{KeyType, ProductKind}; - use std::{borrow::Borrow, path::Path}; + use std::path::Path; #[test] fn index_constructors() { { @@ -139,11 +140,10 @@ mod tests { } #[test] - #[ignore] fn add_file() { let keys = vec!["shortName", "typeOfLevel", "level", "stepType"]; let index = CodesIndex::new_from_keys(&keys).unwrap(); - let grib_path = Path::new("./data/iceland-surface.grib"); + let grib_path = Path::new("./data/iceland.grib"); let index = index.add_grib_file(grib_path).unwrap(); assert!(!index.pointer.is_null()); @@ -184,33 +184,60 @@ mod tests { let counter = handle.count().unwrap(); - println!("Counter: {:?}", counter); + assert_eq!(counter, 1); } - // { - // let short_name = current_message.read_key("shortName").unwrap(); - // match short_name.value { - // KeyType::Str(val) => assert!(val == "2t"), - // _ => panic!("Unexpected key type"), - // }; - // } - // { - // let level = current_message.read_key("level").unwrap(); - // match level.value { - // KeyType::Int(val) => assert!(val == 0), - // _ => panic!("Unexpected key type"), - // }; - // } - // { - // index.select("shortName", "10v").unwrap(); - // handle = index.borrow().try_into().unwrap(); - // let current_message: KeyedMessage = handle.try_into().unwrap(); - - // let short_name = current_message.read_key("shortName").unwrap(); - // match short_name.value { - // KeyType::Str(val) => assert!(val == "10v"), - // _ => panic!("Unexpected key type"), - // }; - // } - // } + #[test] + fn read_index_messages() { + let file_path = Path::new("./data/iceland-surface.idx"); + let index = CodesIndex::read_from_file(file_path) + .unwrap() + .select("shortName", "2t") + .unwrap() + .select("typeOfLevel", "surface") + .unwrap() + .select("level", 0) + .unwrap() + .select("stepType", "instant") + .unwrap(); + + let mut handle = CodesHandle::new_from_index(index, ProductKind::GRIB).unwrap(); + let current_message = handle.next().unwrap().unwrap(); + + { + let short_name = current_message.read_key("shortName").unwrap(); + match short_name.value { + KeyType::Str(val) => assert!(val == "2t"), + _ => panic!("Unexpected key type"), + }; + } + { + let level = current_message.read_key("level").unwrap(); + match level.value { + KeyType::Int(val) => assert!(val == 0), + _ => panic!("Unexpected key type"), + }; + } + } + + #[test] + fn collect_index_iterator() { + let keys = vec!["shortName", "typeOfLevel", "level", "stepType"]; + let index = CodesIndex::new_from_keys(&keys).unwrap(); + let grib_path = Path::new("./data/iceland-levels.grib"); + + let index = index + .add_grib_file(grib_path) + .unwrap() + .select("typeOfLevel", "isobaricInhPa") + .unwrap() + .select("level", 700) + .unwrap(); + + let handle = CodesHandle::new_from_index(index, ProductKind::GRIB).unwrap(); + + let level = handle.collect::>().unwrap(); + + assert_eq!(level.len(), 1); + } } diff --git a/src/intermediate_bindings/codes_index.rs b/src/intermediate_bindings/codes_index.rs index cb4f6d9..35b2d4f 100644 --- a/src/intermediate_bindings/codes_index.rs +++ b/src/intermediate_bindings/codes_index.rs @@ -116,20 +116,8 @@ pub unsafe fn codes_handle_new_from_index( let codes_handle = eccodes_sys::codes_handle_new_from_index(index, &mut error_code); - if error_code != 0 { - let err: CodesInternal = FromPrimitive::from_i32(error_code).unwrap(); - return Err(err.into()); - } - Ok(codes_handle) -} - -pub unsafe fn codes_iter_next_from_index( - index: *mut codes_index, -) -> Result<*mut codes_handle, CodesError> { - let mut error_code: i32 = 0; - - let codes_handle = eccodes_sys::codes_handle_new_from_index(index, &mut error_code); - + // special case! codes_handle_new_from_index returns -43 when there are no messages in the index + // but it's also indicated by a null pointer if error_code == -43 { return Ok(codes_handle); } @@ -140,3 +128,4 @@ pub unsafe fn codes_iter_next_from_index( } Ok(codes_handle) } +