Crate rotate_enum

Source
Expand description

§rotate-enum crate

This crate provides simple macros that implements prev() and next() methods to an enum.

§Motivation

Sometimes you define an enum like this

enum Direction {
    Up,
    Left,
    Down,
    Right,
}

and you want to rotate them in some logic,

let up = Direction::Up;
let left = Direction::Left;
let down = Direction::Down;
let right = Direction::Right;

assert!(up.next() == left);
assert!(left.next() == down);
assert!(down.next() == right);
assert!(right.next() == up);

assert!(up.prev() == right);
assert!(left.prev() == up);
assert!(down.prev() == left);
assert!(right.prev() == down);

You can of course implement these methods manually, but it’s repetitive and error prone. Don’t you think it should be automated? This crate provides a RotateEnum derive macro to just do this.

§Shifting

This crate also provides ShiftEnum, which will exhaust at the end of the enum list, rather than rotating.

let up = Direction::Up;
let left = Direction::Left;
let down = Direction::Down;
let right = Direction::Right;

assert!(up.next() == Some(left));
assert!(left.next() == Some(down));
assert!(down.next() == Some(right));
assert!(right.next() == None);

assert!(up.prev() == None);
assert!(left.prev() == Some(up));
assert!(down.prev() == Some(left));
assert!(right.prev() == Some(down));

Note that you can only derive either one of RotateEnum or ShiftEnum, but not both, because their semantics conflict.

§Iterating

This crate also provides IterEnum, which will implement Iterator object that yields enum variants in sequence. The first yield result will be the same variant as the one started the iterator, i.e. Direction::Up.iter().next() == Some(Direction::Up).

let up = Direction::Up;
let left = Direction::Left;
let down = Direction::Down;
let right = Direction::Right;

let mut iter = up.iter();
assert!(iter.next() == Some(up));
assert!(iter.next() == Some(left));
assert!(iter.next() == Some(down));
assert!(iter.next() == Some(right));
assert!(iter.next() == None);

assert_eq!(up.iter().collect::<Vec<_>>(), vec![up, left, down, right]);

Or, you could start from "YourEnum"Iterator::new().

assert_eq!(DirectionIterator::new().collect::<Vec<_>>(), vec![
    Direction::Up, Direction::Left, Direction::Down, Direction::Right,
]);

Note that it is not the same as ShiftEnum in the sense that the iterator is one-directional, which means you can go only forward and not prev(). It can also be used with iterator methods like collect().

IterEnum also requires deriving Clone.

§Usage

Use #[derive(...)] macro to annotate your enum.

use rotate_enum::RotateEnum;

#[derive(RotateEnum)]
enum Direction {
    Up,
    Left,
    Down,
    Right,
}

§Note

These macros seem trivial, but it’s only possible with procedural macros!

Derive Macros§

  • This derive macro will implement iter() method to the annotated enum that sequentially yield the variant of the enum.
  • This derive macro will implement next() and prev() methods that rotates the variant to the annotated enum.
  • This derive macro will implement next() and prev() methods that shifts the variant to the annotated enum.