#![cfg_attr(feature = "unsafe", allow(unsafe_code))]
#![cfg_attr(not(feature = "unsafe"), forbid(unsafe_code))]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod prelude {
pub use crate::Swap3;
}
pub fn swap3_bca<T>(a: &mut T, b: &mut T, c: &mut T) {
std::mem::swap(a, b);
std::mem::swap(b, c);
}
pub fn swap3_cab<T>(a: &mut T, b: &mut T, c: &mut T) {
std::mem::swap(a, c);
std::mem::swap(b, c);
}
#[inline(always)]
pub fn swap3_bca_slice<T>(data: &mut [T], a: usize, b: usize, c: usize) {
#[cfg(feature = "unsafe")]
slice::bca_unsafe(data, a, b, c);
#[cfg(not(feature = "unsafe"))]
slice::bca_safe(data, a, b, c);
}
#[inline(always)]
pub fn swap3_cab_slice<T>(data: &mut [T], a: usize, b: usize, c: usize) {
#[cfg(feature = "unsafe")]
slice::cab_unsafe(data, a, b, c);
#[cfg(not(feature = "unsafe"))]
slice::cab_safe(data, a, b, c);
}
pub trait Swap3<I = usize> {
fn swap3_bca(&mut self, a: I, b: I, c: I);
fn swap3_cab(&mut self, a: I, b: I, c: I);
}
impl<T> Swap3<usize> for [T] {
fn swap3_bca(&mut self, a: usize, b: usize, c: usize) {
swap3_bca_slice(self, a, b, c)
}
fn swap3_cab(&mut self, a: usize, b: usize, c: usize) {
swap3_cab_slice(self, a, b, c)
}
}
pub mod slice {
#[inline(always)]
pub fn bca_safe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
data.swap(a, b);
data.swap(b, c);
}
#[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
#[cfg(feature = "unsafe")]
#[inline(always)]
pub fn bca_unsafe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
use std::ptr;
let pa = ptr::addr_of_mut!(data[a]);
let pb = ptr::addr_of_mut!(data[b]);
let pc = ptr::addr_of_mut!(data[c]);
unsafe {
ptr::swap(pa, pb);
ptr::swap(pb, pc);
}
}
#[inline(always)]
pub fn cab_safe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
data.swap(a, c);
data.swap(b, c);
}
#[cfg_attr(docsrs, doc(cfg(feature = "unsafe")))]
#[cfg(feature = "unsafe")]
#[inline(always)]
pub fn cab_unsafe<T>(data: &mut [T], a: usize, b: usize, c: usize) {
use std::ptr;
let pa = ptr::addr_of_mut!(data[a]);
let pb = ptr::addr_of_mut!(data[b]);
let pc = ptr::addr_of_mut!(data[c]);
unsafe {
ptr::swap(pa, pc);
ptr::swap(pb, pc);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_swap3_bca() {
let mut a = 65;
let mut b = 66;
let mut c = 67;
swap3_bca(&mut a, &mut b, &mut c);
assert_eq!([a, b, c], [66, 67, 65]);
}
#[test]
fn test_swap3_cab() {
let mut a = 65;
let mut b = 66;
let mut c = 67;
swap3_cab(&mut a, &mut b, &mut c);
assert_eq!([a, b, c], [67, 65, 66]);
}
#[test]
fn test_swap3_bca_vec() {
let mut vec = vec![50, 10, 90, 25, 30, 75];
slice::bca_safe(&mut vec, 0, 1, 4);
assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
}
#[test]
#[cfg(feature = "unsafe")]
fn test_swap3_bca_vec_unsafe() {
let mut vec = vec![50, 10, 90, 25, 30, 75];
slice::bca_unsafe(&mut vec, 0, 1, 4);
assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
}
#[test]
fn test_swap3_cab_vec() {
let mut vec = vec![50, 10, 90, 25, 30, 75];
slice::cab_safe(&mut vec, 0, 1, 4);
assert_eq!(vec, &[30, 50, 90, 25, 10, 75]);
}
#[test]
#[cfg(feature = "unsafe")]
fn test_swap3_cab_vec_unsafe() {
let mut vec = vec![50, 10, 90, 25, 30, 75];
slice::cab_unsafe(&mut vec, 0, 1, 4);
assert_eq!(vec, &[30, 50, 90, 25, 10, 75]);
}
#[test]
fn test_vec_trait_bca() {
let mut vec = vec![50, 10, 90, 25, 30, 75];
vec.swap3_bca(0, 1, 4);
assert_eq!(vec, &[10, 30, 90, 25, 50, 75]);
}
#[test]
fn test_array_trait_cab() {
let mut vec = [50, 10, 90, 25, 30, 75];
vec.swap3_cab(0, 1, 4);
assert_eq!(vec, [30, 50, 90, 25, 10, 75]);
}
}