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:

  1. If T: Copy it copies the value from the first seference.
  2. Otherwise, if T: Default, it swaps the value with the default value.
  3. 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: