use std::fmt::Debug;

pub fn pivot<T: PartialOrd>(input: &mut [T]) -> usize {
  let mut p = 0;

  for i in 1..input.len() {
    if input[i] < input[p] {
      input.swap(p + 1, i);
      input.swap(p, p + 1);
      p += 1;
    }
  }

  p
}

pub fn quick_sort<T: PartialOrd + Debug>(input: &mut [T]) {
  if input.len() <= 1 {
    return;
  }

  let p = pivot(input);
  let (a, b) = input.split_at_mut(p);

  quick_sort(a);
  quick_sort(&mut b[1..]);
}

pub fn quick_sort_rayon<T: Send + PartialOrd + Debug>(input: &mut [T]) {
  if input.len() <= 1 {
    return;
  }

  let p = pivot(input);
  let (a, b) = input.split_at_mut(p);

  rayon::join(|| quick_sort(a), || quick_sort(&mut b[1..]));
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_pivot() {
    let mut v = vec![1, 2, 6, 3, 9, 0];
    let p = pivot(&mut v);

    for x in 0..v.len() {
      assert_eq!(v[x] < v[p], x < p);
    }
  }

  #[test]
  fn test_quick_sort() {
    let mut v = vec![1, 2, 6, 3, 9, 0];
    quick_sort(&mut v);
    assert_eq!(v, vec![0, 1, 2, 3, 6, 9])
  }

  #[test]
  fn test_quick_sort_rayon() {
    let mut v = vec![1, 2, 6, 3, 9, 0, 25, 34, 10];
    quick_sort_rayon(&mut v);
    assert_eq!(v, vec![0, 1, 2, 3, 6, 9, 10, 25, 34])
  }
}
