Crates.io | omniswap |
lib.rs | omniswap |
version | 0.1.0 |
source | src |
created_at | 2022-08-20 09:37:27.589079 |
updated_at | 2022-08-20 09:37:27.589079 |
description | swap values between possibly-overlapping references |
homepage | https://github.com/qnighy/omniswap |
repository | https://github.com/qnighy/omniswap |
max_upload_size | |
id | 649111 |
size | 25,895 |
You cannot simply use std::mem::swap
to replace values within an array:
let mut a = [1, 2, 3];
// You cannot prove their disjointness!
std::mem::swap(&mut a[0], &mut a[2]);
You get the following message:
error[E0499]: cannot borrow `a[_]` as mutable more than once at a time
--> src/main.rs:4:31
|
4 | std::mem::swap(&mut a[0], &mut a[2]);
| -------------- --------- ^^^^^^^^^ second mutable borrow occurs here
| | |
| | first mutable borrow occurs here
| first borrow later used by call
|
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
You can use the dedicated <[T]>::swap
instead:
let mut a = [1, 2, 3];
a.swap(0, 2);
But how about two-dimensional arrays?
let mut a = [[1, 2], [3, 4]];
// You cannot prove their disjointness!
std::mem::swap(&mut a[0][0], &mut a[1][1]);
This is not as simple as the first one.
This crate solves the problem by providing a generic framework for sentinel-based swapping.
The idea is simple: it leaves a dummy value behind to safely move values around:
let mut a = [[1, 2], [3, 4]];
let tmp = std::mem::replace(&mut a[0][0], 0);
let tmp = std::mem::replace(&mut a[1][1], tmp);
a[0][0] = tmp;
# assert_eq!(a, [[4, 2], [3, 1]]);
However, in Rust, the best sentinel value differs between types.
The macro swap!
automatically chooses the best sentinel and
provides the same interface as std::mem::swap
:
let mut a = [[1, 2], [3, 4]];
omniswap::swap!(&mut a[0][0], &mut a[1][1]);
# assert_eq!(a, [[4, 2], [3, 1]]);
Simply use swap!
where you want to use std::mem::swap
:
let mut x = 42;
let mut y = 84;
omniswap::swap!(&mut x, &mut y);
See swap!
for detailed usages.
The crate provides the following variants:
rotate!
-- swaps more than two values at once
The crate also exposes take!
and Replace
.
These are primitives used in swap!
and rotate!
.