Warning
This post was published 39 days ago. The information described in this article may have changed.
I am trying to create an enum to return from a function.
My input is a wrapped Vec (there are other properties, but they are irrelevant).
Types are as follows (simplified, I am actually using ecow::EcoString
s instead of String
s):
enum Part {
Static(String),
Field(FieldDefinition),
OptionalGroup(String, Vec<Part>)
}
struct FieldDefinition {
name: String,
pattern: String,
// ...other irrelevant fields
}
I am trying to create an implementation to convert my Vec<Part>
into an Iterator<Item = String>
with the following logic:
impl Part {
fn pattern_segments(&self) -> PatternSegmentIterator<'_> {
match self {
Part::Static(s) => PatternSegmentIter::Single(regex::escape(s).to_owned()),
Part::Field(def) => {
PatternSegmentIter::Single(format!("(?P<{}>{})", def.name, def.pattern))
}
Part::OptionalGroup(key, subparts) => PatternSegmentIter::Prefixed {
prefix: match key {
Some(k) => format!("(?P<{k}>").into(),
None => "(?:".into(),
},
subparts,
suffix: ")?".into(),
},
}
}
}
My issue is with the type of PatternSegmentIter
:
enum PatternSegmentIter<'a> {
Empty,
Single(String),
Prefixed {
prefix: String,
subparts: &'a Vec<Part>,
suffix: String,
},
Subparts {
iter: std::iter::FlatMap<
std::slice::Iter<'a, Part>,
PatternSegmentIter<'a>,
fn(&'a Part) -> Self,
>,
suffix: String,
},
}
impl<'a> Iterator for PatternSegmentIter<'a> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
match core::mem::replace(self, Self::Empty) {
PatternSegmentIter::Empty => None,
PatternSegmentIter::Single(s) => Some(s),
PatternSegmentIter::Prefixed {
prefix,
subparts,
suffix,
} => {
*self = Self::Subparts {
iter: subparts.iter().flat_map(Part::pattern_segments),
suffix,
};
Some(prefix)
}
PatternSegmentIter::Subparts { mut iter, suffix } => match iter.next() {
Some(item) => {
*self = Self::Subparts { iter, suffix };
Some(item)
}
None => Some(suffix),
},
}
}
}
My issue is that the PatternSegmentIter Subparts iterator type is cyclical.
I tried to add the iterator type as a type parameter (I: Iterator<Item = String>
) my build hung when attempting to specify the return type of pattern_segments
as impl Iterator<Item = String>
, and requiring the Iterator type to be specified is impossible (PatternSegmentIterator<'_, PatternSegmentIterator<'_, ...>>
).
Is there any solution to this or do I need to switch to dynamic dispatch (return Box<dyn Iterator<Item = String>
and get rid of PatternSegmentIterator
)? I assumed (perhaps naiively) that creating an iterator enum would be better than just returning a boxed iterator, but maybe I'm wrong about that?
1 post - 1 participant
🏷️ rust_feed