Avoid custom Iterator type for IntoIterator?

[nostd]

Is is possible to avoid having to define a custom type implementing Iterator for a type that wants to implement IntoIterator?

To give an example say I have this enum:

enum Example {
  One,
  Two(u8),
}

What I want from .into_iter() is something like

fn into_iter(self) -> ??? {
  use core::iter::once;

  match self {
    Example::One => once(1u8),
    Example::Two(param) => once(2u8).chain(once(param)),
  }
}

Do I have to have a placeholder iterator type here for IntoIter of the IntoIterator trait or can I somehow keep it "generic" for chaining like this?

Since once and chain return different types (both functions return the identically-named iterator adaptor), you can't return either an Once or a Chain from a function.

In these cases, I usually try to come up with some internal cleverness so that the types do end up being the same, e.g.:

use std::iter::{ once, Once, Chain };

impl IntoIterator for Example {
    type Item = u8;
    type IntoIter = Chain<Once<u8>, std::option::IntoIter<u8>>;

    fn into_iter(self) -> Self::IntoIter {
        match self {
            Example::One => once(1u8).chain(None),
            Example::Two(param) => once(2u8).chain(Some(param)),
        }
    }
}

If not, there's always the possibility to go full trait object and box the iterators if you really want to avoid writing a custom iterator type. However, creating a custom iterator type is the most "correct" solution in these kinds of situations.

1 Like

If you can't find common ground, another option is the either crate -- Either implements Iterator when the types of both sides do.

1 Like

Thanks, I think I'll have to make a new type here. Note that this is a no-std/no-alloc case so I can't even Box.

Probably not a good idea, but just for fun:

#![no_std]
extern crate alloc;
use alloc::boxed::Box;
use core::iter::{once, Iterator, IntoIterator};

enum Example {
    One,
    Two(u8),
}
impl Example {
    fn into_iter(self) -> impl IntoIterator<Item=u8, IntoIter=Box<dyn Iterator<Item=u8>>> {
        let x: Box<dyn Iterator<Item=u8>> = match self {
            Self::One => Box::new(once(1u8)),
            Self::Two(v) => Box::new(once(1u8).chain(once(v))),
        };
        x.into_iter()
    }    
}

If you had Box with an external allocator...

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.