macro_rules! swap {
($x: expr, $y: expr) => { ... };
($x: expr, $y: expr,) => { ... };
}
Expand description
Swaps values of two references.
This is a sentinel-based swapping.
Therefore, unlike [std::mem::swap
],
it can be applied to possibly overlapping references.
Basic usage
It has the same syntax as [std::mem::swap
].
let mut x = 'a';
let mut y = 'b';
omniswap::swap!(&mut x, &mut y);
assert_eq!((x, y), ('b', 'a'));
Swapping with cells
It also supports [std::cell::Cell
] and [std::cell::RefCell
].
let x = Cell::new('a');
let y = Cell::new('b');
omniswap::swap!(&x, &y);
assert_eq!((x.get(), y.get()), ('b', 'a'));
The two references need not of the same type;
for example, you may swap values between &mut T
and &Cell<T>
.
let mut x = 'a';
let y = Cell::new('b');
omniswap::swap!(&mut x, &y);
assert_eq!((x, y.get()), ('b', 'a'));
Sentinel requirements
In order for swap!
to work this way, it requires the value type
to satisfy Default
or Clone
.
If multiple traits can apply, the behavior is determined in the following order:
- If
T: Copy
it copies the value from the first seference. - Otherwise, if
T: Default
, it swaps the value with the default value. - Otherwise, if
T: Clone
, it clones out the value from the first reference.
Additionally, if the first reference is &Cell<T>
, T
must satisfy
Default
or Copy
. Clone
alone does not suffice.
Evaluation order
It evaluates the arguments in the order of appearance, and then the first argument again to put the value back.
Alternatives
If the type does not have a good sentinel, you may need to use the following alternatives that does not need a sentinel:
- [
std::mem::swap
] <[T]>::swap
Cell::swap
RefCell::swap