I'm trying to create a HashMap where the key type is a function with a reference paramater.
let mut hm: HashMap<fn(&u32) -> u32, u32> = HashMap::new();
. This works fine, but i cant insert anything into the map. The compiler says it's not legal since trait bounds weren't satisfied
rules.insert(
|v: &u32| v + 1,
0,
);
gives
the method `insert` exists but the following trait bounds were not satisfied:
`for<'r> fn(&'r u32) -> u32: Eq`
`for<'r> fn(&'r u32) -> u32: Hash`
I've read about Lifetimes in the various texts, but i can't figure out how to solve this.
Background: I'm implementing wave function collapse. I want my implementation to be generic in the sense that any "grid" can be used, 1d, 2d, 3d, nd, hexagonal etc. To do this i use a "ruleset" which is a hashmap where the key is a function that takes a cell coordinate and returns its neighbours, and the value is the rule for how to collapse said neighbours' states. The key function takes an index and a reference to the "grid" and returns the index of the neihbour.
If you want to support multiple grid implementations, the most natural approach is to define a Grid
trait that abstracts differences between the grids. Here's one I made up, loosely based on your use case description:
enum CollapseRule {
A,
B,
}
trait Grid {
const COLLAPSE_RULE: CollapseRule;
fn neighbours(&self, index: usize) -> Vec<usize>;
}
#[derive(Clone, Debug, Default)]
struct Grid1d {
vertices: Vec<f64>,
}
impl Grid for Grid1d {
const COLLAPSE_RULE: CollapseRule = CollapseRule::A;
fn neighbours(&self, index: usize) -> Vec<usize> {
let len = self.vertices.len();
match index {
0 => vec![1],
_ if index < len => vec![index - 1, index + 1],
_ if index == len => vec![index - 1],
_ => panic!(),
}
}
}
Whereever your code needs to accept a grid, you can accept a generic type G
with a trait bound G: Grid
, and any interaction with the grid happens via the trait. Your trait will likely need more functions than in my simplistic example.