Skip to content

Commit 01ec338

Browse files
committed
remove fallible streaming iterator for using keyedmessage with phantomdata, all tests pass except doctests
1 parent a7fb913 commit 01ec338

12 files changed

Lines changed: 178 additions & 146 deletions

File tree

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ errno = { version = "0.3", default-features = false }
2626
num-derive = { version = "0.4", default-features = false }
2727
num-traits = { version = "0.2", default-features = false }
2828
fallible-iterator = { version = "0.3", default-features = false }
29-
fallible-streaming-iterator = { version = "0.1.9", default-features = false }
3029
ndarray = { version = "0.16", default-features = false, optional = true, features = [
3130
"std",
3231
] }

benches/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use criterion::{Criterion, criterion_group, criterion_main};
2-
use eccodes::FallibleStreamingIterator;
2+
use eccodes::FallibleIterator;
33
use eccodes::codes_handle::{CodesHandle, ProductKind};
44
use std::hint::black_box;
55
use std::path::Path;
@@ -11,7 +11,7 @@ pub fn key_reading(c: &mut Criterion) {
1111

1212
let mut handle = CodesHandle::new_from_file(file_path, product_kind).unwrap();
1313

14-
let msg = handle.next().unwrap().unwrap();
14+
let msg = handle.message_generator().next().unwrap().unwrap();
1515

1616
c.bench_function("long reading", |b| {
1717
b.iter(|| msg.read_key_dynamic(black_box("dataDate")).unwrap())

src/codes_handle/iterator.rs

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,48 @@
1+
use fallible_iterator::FallibleIterator;
2+
13
use crate::{CodesHandle, KeyedMessage, codes_handle::HandleGenerator, errors::CodesError};
2-
use fallible_streaming_iterator::FallibleStreamingIterator;
3-
use std::fmt::Debug;
4+
use std::marker::PhantomData;
5+
6+
#[derive(Debug)]
7+
pub struct KeyedMessageGenerator<'a, S: HandleGenerator> {
8+
codes_handle: &'a mut CodesHandle<S>,
9+
}
10+
11+
impl<S: HandleGenerator> CodesHandle<S> {
12+
pub fn message_generator<'a>(&'a mut self) -> KeyedMessageGenerator<'a, S> {
13+
KeyedMessageGenerator { codes_handle: self }
14+
}
15+
}
416

517
/// # Errors
618
///
7-
/// The `advance()` and `next()` methods will return [`CodesInternal`](crate::errors::CodesInternal)
19+
/// The `next()` will return [`CodesInternal`](crate::errors::CodesInternal)
820
/// when internal ecCodes function returns non-zero code.
9-
impl<S: HandleGenerator + Debug> FallibleStreamingIterator for CodesHandle<S> {
10-
type Item = KeyedMessage;
11-
21+
impl<'ch, S: HandleGenerator> FallibleIterator for KeyedMessageGenerator<'ch, S> {
22+
type Item = KeyedMessage<'ch>;
1223
type Error = CodesError;
1324

14-
fn advance(&mut self) -> Result<(), Self::Error> {
15-
// destructor of KeyedMessage calls ecCodes
25+
fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
26+
let new_eccodes_handle = self.codes_handle.source.gen_codes_handle()?;
1627

17-
let new_eccodes_handle = self.source.gen_codes_handle()?;
18-
19-
self.current_message = if new_eccodes_handle.is_null() {
20-
None
28+
if new_eccodes_handle.is_null() {
29+
Ok(None)
2130
} else {
22-
Some(KeyedMessage {
31+
Ok(Some(KeyedMessage {
32+
parent_message: PhantomData,
2333
message_handle: new_eccodes_handle,
24-
})
25-
};
26-
27-
Ok(())
28-
}
29-
30-
fn get(&self) -> Option<&Self::Item> {
31-
self.current_message.as_ref()
34+
}))
35+
}
3236
}
3337
}
3438

3539
#[cfg(test)]
3640
mod tests {
3741
use crate::{
38-
DynamicKeyType,
42+
DynamicKeyType, FallibleIterator,
3943
codes_handle::{CodesHandle, ProductKind},
4044
};
4145
use anyhow::{Context, Ok, Result};
42-
use fallible_streaming_iterator::FallibleStreamingIterator;
4346
use std::path::Path;
4447

4548
#[test]
@@ -48,14 +51,26 @@ mod tests {
4851
let product_kind = ProductKind::GRIB;
4952
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
5053

51-
let msg1 = handle.next()?.context("Message not some")?;
54+
let msg1 = handle
55+
.message_generator()
56+
.next()?
57+
.context("Message not some")?;
5258
let key1 = msg1.read_key_dynamic("typeOfLevel")?;
59+
drop(msg1);
5360

54-
let msg2 = handle.next()?.context("Message not some")?;
61+
let msg2 = handle
62+
.message_generator()
63+
.next()?
64+
.context("Message not some")?;
5565
let key2 = msg2.read_key_dynamic("typeOfLevel")?;
66+
drop(msg2);
5667

57-
let msg3 = handle.next()?.context("Message not some")?;
68+
let msg3 = handle
69+
.message_generator()
70+
.next()?
71+
.context("Message not some")?;
5872
let key3 = msg3.read_key_dynamic("typeOfLevel")?;
73+
drop(msg3);
5974

6075
assert_eq!(key1, DynamicKeyType::Str("isobaricInhPa".to_string()));
6176
assert_eq!(key2, DynamicKeyType::Str("isobaricInhPa".to_string()));
@@ -71,7 +86,7 @@ mod tests {
7186

7287
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
7388

74-
while let Some(msg) = handle.next()? {
89+
while let Some(msg) = handle.message_generator().next()? {
7590
let key = msg.read_key_dynamic("shortName")?;
7691

7792
match key {
@@ -91,7 +106,7 @@ mod tests {
91106

92107
let mut handle_collected = vec![];
93108

94-
while let Some(msg) = handle.next()? {
109+
while let Some(msg) = handle.message_generator().next()? {
95110
handle_collected.push(msg.try_clone()?);
96111
}
97112

@@ -112,7 +127,7 @@ mod tests {
112127
let product_kind = ProductKind::GRIB;
113128

114129
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
115-
let current_message = handle.next()?.context("Message not some")?;
130+
let current_message = handle.message_generator().next()?.context("Message not some")?;
116131

117132
assert!(!current_message.message_handle.is_null());
118133

@@ -125,17 +140,18 @@ mod tests {
125140
let product_kind = ProductKind::GRIB;
126141

127142
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
143+
let mut mgen = handle.message_generator();
128144

129-
assert!(handle.next()?.is_some());
130-
assert!(handle.next()?.is_some());
131-
assert!(handle.next()?.is_some());
132-
assert!(handle.next()?.is_some());
133-
assert!(handle.next()?.is_some());
145+
assert!(mgen.next()?.is_some());
146+
assert!(mgen.next()?.is_some());
147+
assert!(mgen.next()?.is_some());
148+
assert!(mgen.next()?.is_some());
149+
assert!(mgen.next()?.is_some());
134150

135-
assert!(handle.next()?.is_none());
136-
assert!(handle.next()?.is_none());
137-
assert!(handle.next()?.is_none());
138-
assert!(handle.next()?.is_none());
151+
assert!(mgen.next()?.is_none());
152+
assert!(mgen.next()?.is_none());
153+
assert!(mgen.next()?.is_none());
154+
assert!(mgen.next()?.is_none());
139155

140156
Ok(())
141157
}
@@ -151,7 +167,7 @@ mod tests {
151167
// First, filter and collect the messages to get those that we want
152168
let mut level = vec![];
153169

154-
while let Some(msg) = handle.next()? {
170+
while let Some(msg) = handle.message_generator().next()? {
155171
if msg.read_key_dynamic("shortName")? == DynamicKeyType::Str("msl".to_string())
156172
&& msg.read_key_dynamic("typeOfLevel")?
157173
== DynamicKeyType::Str("surface".to_string())

src/codes_handle/mod.rs

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
44
#[cfg(feature = "experimental_index")]
55
use crate::codes_index::CodesIndex;
6-
use crate::{
7-
CodesError, KeyedMessage, intermediate_bindings::codes_handle_new_from_file, pointer_guard,
8-
};
6+
use crate::{CodesError, intermediate_bindings::codes_handle_new_from_file, pointer_guard};
97
use eccodes_sys::{ProductKind_PRODUCT_GRIB, codes_handle};
108
use errno::errno;
119
use libc::{FILE, c_char, c_void, size_t};
@@ -24,7 +22,7 @@ mod iterator;
2422
/// It is not intended to be used directly by the user.
2523
#[doc(hidden)]
2624
#[derive(Debug)]
27-
pub struct CodesFile<D> {
25+
pub struct CodesFile<D: Debug> {
2826
// fields dropped from top
2927
pointer: *mut FILE,
3028
product_kind: ProductKind,
@@ -33,11 +31,11 @@ pub struct CodesFile<D> {
3331

3432
/// Internal trait implemented for types that can be called to generate `*mut codes_handle`.
3533
#[doc(hidden)]
36-
pub trait HandleGenerator {
34+
pub trait HandleGenerator: Debug {
3735
fn gen_codes_handle(&self) -> Result<*mut codes_handle, CodesError>;
3836
}
3937

40-
impl<D> HandleGenerator for CodesFile<D> {
38+
impl<D: Debug> HandleGenerator for CodesFile<D> {
4139
fn gen_codes_handle(&self) -> Result<*mut codes_handle, CodesError> {
4240
unsafe { codes_handle_new_from_file(self.pointer, self.product_kind) }
4341
}
@@ -52,25 +50,17 @@ impl<D> HandleGenerator for CodesFile<D> {
5250
/// - From GRIB index using [`new_from_index()`](CodesHandle::new_from_index) (with `experimental_index` feature enabled)
5351
///
5452
/// Destructor for this structure does not panic, but some internal functions may rarely fail
55-
/// leading to bugs. Errors encountered in the destructor are logged with [`log`].
53+
/// leading to bugs. Errors encountered in the destructor are logged with [`tracing`].
5654
///
57-
/// # `FallibleStreamingIterator`
55+
/// # `FallibleIterator`
5856
///
59-
/// This structure implements [`FallibleStreamingIterator`](crate::FallibleStreamingIterator) trait which allows to access GRIB messages.
57+
/// This structure implements [`FallibleIterator`](crate::FallibleStreamingIterator) trait which allows to access GRIB messages.
6058
///
6159
/// To access GRIB messages the ecCodes library uses a method similar to a C-style iterator.
6260
/// It digests the `* FILE` multiple times, each time returning the `*mut codes_handle`
63-
/// to a message inside the file. The behavior of previous `*mut codes_handle` after next one is generated is undefined
64-
/// and we assume here that it is unsafe to use "old" `*mut codes_handle`.
65-
///
66-
/// In Rust, such pattern is best represented by a streaming iterator which returns a reference to the message,
67-
/// that is valid only until the next iteration. If you need to prolong the lifetime of the message, you can clone it.
68-
/// Internal ecCodes functions can fail, necessitating the streaming iterator to be implemented with
69-
/// [`FallibleStreamingIterator`](crate::FallibleStreamingIterator) trait.
61+
/// to a message inside the file.
7062
///
71-
/// As of `0.10` release, none of the available streaming iterator crates utilises already stabilized GATs.
72-
/// This unfortunately significantly limits the number of methods available for `CodesHandle` iterator.
73-
/// Therefore the probably most versatile way to iterate over the messages is to use `while let` loop.
63+
/// This behaviour is represented in this crate by `FallibleIterator`, because generating `KeyedMessage` can fail.
7464
///
7565
/// ```
7666
/// use eccodes::{ProductKind, CodesHandle, KeyRead};
@@ -120,9 +110,7 @@ impl<D> HandleGenerator for CodesFile<D> {
120110
///
121111
/// All available methods for `CodesHandle` iterator can be found in [`FallibleStreamingIterator`](crate::FallibleStreamingIterator) trait.
122112
#[derive(Debug)]
123-
pub struct CodesHandle<S: Debug + HandleGenerator> {
124-
// fields are dropped from top to bottom
125-
current_message: Option<KeyedMessage>,
113+
pub struct CodesHandle<S: HandleGenerator> {
126114
source: S,
127115
}
128116

@@ -198,7 +186,6 @@ impl CodesHandle<CodesFile<File>> {
198186
pointer: file_pointer,
199187
product_kind,
200188
},
201-
current_message: None,
202189
})
203190
}
204191
}
@@ -250,7 +237,6 @@ impl CodesHandle<CodesFile<Vec<u8>>> {
250237
product_kind,
251238
pointer: file_pointer,
252239
},
253-
current_message: None,
254240
})
255241
}
256242
}
@@ -340,7 +326,7 @@ mod tests {
340326
use crate::codes_index::{CodesIndex, Select};
341327
use anyhow::{Context, Result};
342328
use eccodes_sys::{ProductKind_PRODUCT_GRIB, grib_handle};
343-
use fallible_streaming_iterator::FallibleStreamingIterator;
329+
use fallible_iterator::FallibleIterator;
344330
use std::{
345331
fs::File,
346332
io::Read,
@@ -356,7 +342,6 @@ mod tests {
356342
let handle = CodesHandle::new_from_file(file_path, product_kind)?;
357343

358344
assert!(!handle.source.pointer.is_null());
359-
assert!(handle.current_message.is_none());
360345
assert_eq!(handle.source.product_kind as u32, {
361346
ProductKind_PRODUCT_GRIB
362347
});
@@ -438,7 +423,6 @@ mod tests {
438423

439424
let handle = CodesHandle::new_from_memory(buf, product_kind)?;
440425
assert!(!handle.source.pointer.is_null());
441-
assert!(handle.current_message.is_none());
442426
assert_eq!(handle.source.product_kind as u32, {
443427
ProductKind_PRODUCT_GRIB
444428
});
@@ -503,9 +487,10 @@ mod tests {
503487

504488
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
505489

506-
let _ref_msg = handle.next()?.context("no message")?;
490+
let _ref_msg = handle.message_generator().next()?.context("no message")?;
507491
let clone_msg = _ref_msg.try_clone()?;
508-
let _oth_ref = handle.next()?.context("no message")?;
492+
drop(_ref_msg);
493+
let _oth_ref = handle.message_generator().next()?.context("no message")?;
509494

510495
let _nrst = clone_msg.codes_nearest()?;
511496
let _kiter = clone_msg.default_keys_iterator()?;

src/codes_nearest.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Definition and associated functions of `CodesNearest`
22
//! used for finding nearest gridpoints in `KeyedMessage`
33
4-
use std::ptr::null_mut;
4+
use std::{fmt::Debug, ptr::null_mut};
55

66
use eccodes_sys::codes_nearest;
77
use tracing::{Level, event, instrument};
@@ -17,7 +17,7 @@ use crate::{
1717
#[derive(Debug)]
1818
pub struct CodesNearest<'a> {
1919
nearest_handle: *mut codes_nearest,
20-
parent_message: &'a KeyedMessage,
20+
parent_message: &'a KeyedMessage<'a>,
2121
}
2222

2323
/// The structure returned by [`CodesNearest::find_nearest()`].
@@ -36,7 +36,7 @@ pub struct NearestGridpoint {
3636
pub value: f64,
3737
}
3838

39-
impl KeyedMessage {
39+
impl KeyedMessage<'_> {
4040
/// Creates a new instance of [`CodesNearest`] for the `KeyedMessage`.
4141
/// [`CodesNearest`] can be used to find nearest gridpoints for given coordinates in the `KeyedMessage`
4242
/// by calling [`find_nearest()`](crate::CodesNearest::find_nearest).
@@ -126,7 +126,7 @@ mod tests {
126126
use std::path::Path;
127127

128128
use anyhow::{Context, Result};
129-
use fallible_streaming_iterator::FallibleStreamingIterator;
129+
use fallible_iterator::FallibleIterator;
130130

131131
use crate::{CodesHandle, ProductKind};
132132

@@ -137,12 +137,18 @@ mod tests {
137137
let product_kind = ProductKind::GRIB;
138138

139139
let mut handle1 = CodesHandle::new_from_file(file_path1, product_kind)?;
140-
let msg1 = handle1.next()?.context("Message not some")?;
140+
let msg1 = handle1
141+
.message_generator()
142+
.next()?
143+
.context("Message not some")?;
141144
let nrst1 = msg1.codes_nearest()?;
142145
let out1 = nrst1.find_nearest(64.13, -21.89)?;
143146

144147
let mut handle2 = CodesHandle::new_from_file(file_path2, product_kind)?;
145-
let msg2 = handle2.next()?.context("Message not some")?;
148+
let msg2 = handle2
149+
.message_generator()
150+
.next()?
151+
.context("Message not some")?;
146152
let nrst2 = msg2.codes_nearest()?;
147153
let out2 = nrst2.find_nearest(64.13, -21.89)?;
148154

@@ -161,13 +167,13 @@ mod tests {
161167
let product_kind = ProductKind::GRIB;
162168

163169
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
164-
let current_message = handle.next()?.context("Message not some")?;
170+
let current_message = handle
171+
.message_generator()
172+
.next()?
173+
.context("Message not some")?;
165174

166175
let _nrst = current_message.codes_nearest()?;
167176

168-
drop(_nrst);
169-
drop(handle);
170-
171177
Ok(())
172178
}
173179
}

0 commit comments

Comments
 (0)