Reputation: 5534
I have a static array of chrono::format::strftime
formats that my application supports.
I'd like to avoid parsing them during run time, so I defined a lazy_static!
block that parses them to a collection of chrono::format::Item
.
However, when I try to iterate over the parsed collection, I'm getting an error:
the trait bound `&chrono::format::StrftimeItems<'_>: std::iter::Iterator` is not satisfied
Here's a short reproduction:
#[macro_use]
extern crate lazy_static;
extern crate chrono;
use chrono::DateTime;
use chrono::offset::FixedOffset;
use chrono::format::{Parsed, parse};
use chrono::format::strftime::StrftimeItems;
static FORMATS : &[&'static str] = &["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S%.f"];
lazy_static! {
static ref PARSED_FORMATS : Vec<StrftimeItems<'static>> = FORMATS
.iter()
.map(|format| StrftimeItems::new(format))
.collect();
}
fn parse_datetime(s: &str) -> Option<DateTime<FixedOffset>> {
for format in PARSED_FORMATS.iter() {
let mut parsed = Parsed::new();
let dt = parse(&mut parsed, &s, format)
.and_then(|_| parsed.to_datetime() );
if dt.is_ok() {
return dt.ok()
}
}
return None
}
Attempting to de-reference format
in the loop gives this error:
error[E0507]: cannot move out of borrowed content
--> src\main.rs:21:35
|
21 | let dt = parse(&mut parsed, &s, *format)
| ^^^^^^^ cannot move out of borrowed content
error: aborting due to previous error
Attempting to clone format
seems to work, however cloning seems redundant here and I'd like to avoid it.
Is this the right approach here? or perhaps using a macro is better option?
Upvotes: 3
Views: 688
Reputation: 65657
StrftimeItems
is an iterator, not an iterable container (like Vec
is). When you advance an iterator, you can't rewind it. parse
must receive an iterator by value, which means that you must take a StrftimeItems
our of your vector (which means you can't reuse it afterwards) or clone the StrftimeItems
stored in the vector. By cloning the StrftimeItems
, you can produce a new iterator whose state is distinct from the original (i.e. advancing one doesn't advance the other).
I'd like to avoid parsing them during run time
However, StrftimeItems
doesn't let you achieve your goal, because StrftimeItems
lazily parses the format string as the iterator advances.
Instead, I would suggest that you collect the results from that iterator to a Vec<Item<'static>>
.
#[macro_use]
extern crate lazy_static;
extern crate chrono;
use chrono::DateTime;
use chrono::offset::FixedOffset;
use chrono::format::{Item, Parsed, parse};
use chrono::format::strftime::StrftimeItems;
static FORMATS : &[&'static str] = &["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S%.f"];
lazy_static! {
static ref PARSED_FORMATS : Vec<Vec<Item<'static>>> = FORMATS
.iter()
.map(|format| StrftimeItems::new(format).collect())
.collect();
}
fn parse_datetime(s: &str) -> Option<DateTime<FixedOffset>> {
for format in PARSED_FORMATS.iter() {
let mut parsed = Parsed::new();
let dt = parse(&mut parsed, &s, format.iter().cloned())
.and_then(|_| parsed.to_datetime() );
if dt.is_ok() {
return dt.ok()
}
}
return None
}
Now, when we call parse
, we pass format.iter().cloned()
. format
is a Vec<Item<'static>>
, iter()
produces a fresh iterator over references to the Item
s, and cloned()
adapts the iterator so that each Item
is returned by value (achieved by cloning them) rather than by reference (because parse
expects an iterator over Item
values, not Item
references).
Upvotes: 2