I was wondering about this already a long time. Actually I wonder even more that this has not been asked here in the last 18 months since I am watching Rust closely. Maybe it is just me who has problems to see a good Rust solution. Well most people here are really smart, but maybe for some the answer might be useful, so I will post it here as a "weekend" question, see below.
I think one solution is using an additional generic closure parameter, which is then inlined by the compiler. That was proposed by an AI some months ago, and Claude 3.7 just confirmed it. First I had some doubts, and I consider it still a bit funny, but it seems to make sense. I will not post a link to the full Claude solution, as some people do not like AI that much, but the core of the suggestion was
fn walk_rook<F>(g: &Game, kk: KK, s: &mut KKS, filter: F)
where
F: Fn(KK) -> bool,
Is this the best solution, or are there other ways to solve it? Here is the actual question:
I have the two Rust functions below, which are very similar.
The first one has the test "if wanted(kk)". When I know that this test
will evaluate to true, I call walk_rook2() for utmost performance.
This is fine, but the code duplication is a bit ugly. How can I avoid
the dublication and somehow join the two functions, while still obtaining
optimal performance?
fn walk_rook1(g: &Game, kk: KK, s: &mut KKS) {
let mut i: usize = 0;
let mut kk = kk;
while {
kk.di = g.rook_path[kk.si as usize][i].pos;
kk.di
} >= 0
{
if {
kk.df = g.board[kk.di as usize];
kk.df
} == 0
{
i += 1;
} else {
i = g.rook_path[kk.si as usize][i].nxt_dir_idx;
}
if wanted(kk) {
s.push(kk)
}
}
}
fn walk_rook2(g: &Game, kk: KK, s: &mut KKS) {
let mut i: usize = 0;
let mut kk = kk;
while {
kk.di = g.rook_path[kk.si as usize][i].pos;
kk.di
} >= 0
{
if {
kk.df = g.board[kk.di as usize];
kk.df
} == 0
{
i += 1;
} else {
i = g.rook_path[kk.si as usize][i].nxt_dir_idx;
}
s.push(kk)
}
}