Iterator filter design

I have a design question, but while trying to write this down I realize I'm having a hard time explaining it, partially because I think I lack the proper terms. I'll try my best, but the tl;dr is: I want to be able to insert something into a chain of iterators to transform from one type of iterator-of-items to different iterator-of-items; in fact, the output may contain more items than the input.

I have a library which can be used to declare menus; basically a set of menu items which can have parent/child relationships. This library doesn't concern itself with rendering of any sort. While it doesn't handle rendering it does have a helper iterator which generates "events" which are meant to assist in rendering. So given a simple menu:

Root Menu
  +- Sub Menu

This iterator generates the events:

  1. Enter scope
  2. Menu Item: Root Menu
  3. Enter scope
  4. Menu Item: Sub Menu
  5. Leave scope
  6. Leave scope

An application rendering to HTML can use the enter/leave scopes to generate <ul>/</ul> or whatever nesting mechanism it uses.

Anyway, menu items are generic over a custom type, typically a struct which can be used by the application to attach application-specific data to each menu item. For instance an URL field or permissions needed to render the menu item.

The problem I'm having is that the iterator traverses the menu and generates these events, but if one adds a .filter() to the iterator it will be in control of filtering of the events (see numbered list above), rather than the menu items; this is conceptually wrong -- the event should not be filtered; by the time the events are generated it has already been determined that those entries should be included. As stated; the filtering should be done prior to that, when it's just the menu items. What I would like to do is to express it as a two-step process.

Currently it works like this:

for ev in menu.rec_iter() {
  // Generate menu using events here
}

But I want something like this:

for ev in menu.iter().transform_to_events() {
}

This way I could do something along the line of:

for ev in menu.iter().filter(|mi| mi.appctx().enabled == true).transform_to_events() {
}

But for this I need to create this transform_to_events() .. thing, and I'm not sure how one would go about doing that, so that it integrates seamlessly into iterator chains.

Just to be clear, the menu doesn't contain these "scope events" -- those are generated by the iterator when it detects that it is stepping into / out of a scope. But the reason the filtering needs to be done before this is that that filtering a parent menu item out means that the scope will never be entered.

(I'm aware that splitting the functions up is slightly more complicated, and it basically means that I have to pass the scoping over to the transform_to_events() processor .. but let's for the sake of argument say I have done that).

Well that's obviously highly confusing. I hope it makes sense to someone. :slight_smile:

If I'm reading the description right, it sounds a lot like you're looking for flat_map(). It can transform an iterator of items into an iterator of different items which may have more items than the original based on the sub-iterators you're mapping over.