Comment

Comment by onetoo

  > Even more annoying is that I have to duplicate the iterator code: as I often work with frames that may be flipped bottom-up I want to write code like
  >
  >    let mut iterator = if !flipped {
  >       data.chunks_mut(stride)
  >    } else {
  >       data.chunks_mut(stride).rev()
  >    };
  >    for line in iterator { ... }
  >
  > but I can’t since objects have different type (and probably size) and there’s no realistic way to coerce them to the same interface.
For this specific case there is a relatively ergonomic solution using dynamic trait objects + temporary lifetime extensions, available since Rust 1.79:

  let iterator: &mut dyn Iterator<Item = _> = if !flipped {
    &mut data.into_iter()
  } else {
    &mut data.into_iter().rev()
  };
  for line in iterator { ... }
Alternatively, if this is not a feasible solution (e.g. we want to return the new iterator to an outer scope, or the overhead of dyn indirection is unacceptable in this context), one can consider using itertools::Either instead:

  use itertools::Either;
  fn conditionally_flip_iter<I: DoubleEndedIterator>(
      data: I,
      flipped: bool,
  ) -> impl Iterator<Item = I::Item> {
      if !flipped {
          Either::Left(data.into_iter())
      } else {
          Either::Right(data.into_iter().rev())
      }
  }
  // ...
  let mut iterator = conditionally_flip_iter(data, flipped);
  for line in iterator { ... }
parent onetoo 1 year ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton