un_algebra 0.9.0

Simple implementations of selected abstract algebraic structures--including groups, rings, and fields. Intended for self-study of abstract algebra concepts and not for production use.
//!
//! Sequence trait for homogeneous structures.
//!
//! The `sequence` module provides a simple `sequence` trait for ordered
//! homogeneous structure types (similar in principle to common iterator
//! methods).
//!
//! This trait should only be implemented where the relevant Rust
//! iterator trait is not implemented (e.g. for homogeneous tuples).
//!

///
/// A simple ordered, homogeneous structure trait.
///
pub trait Sequence<T> {

  /// Count of sequence in items
  fn count(&self) -> usize;


  /// Map `f` over sequence items.
  fn map(&self, f: &dyn Fn(&T) -> T) -> Self;


  /// Map `f` over sequence pair values.
  fn map_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> T) -> Self;


  /// Are all sequence `f` return values true?
  fn all(&self, f: &dyn Fn(&T) -> bool) -> bool;


  /// Are all sequence pair `f` return values true?
  fn all_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool;


  /// Are any sequence `f` return values true?
  fn any(&self, f: &dyn Fn(&T) -> bool) -> bool;


  /// Are any sequence pair `f` return values true?
  fn any_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool;
}


///
/// 0-tuples form sequences with trivial results.
///
impl<T> Sequence<T> for () {

  /// Count is always zero.
  fn count(&self) -> usize {
    0
  }


  /// Mapping can only return `()`.
  fn map(&self, _f: &dyn Fn(&T) -> T) -> Self {
    ()
  }


  /// Blending pairs can only return `()`.
  fn map_with(&self, _xs: &Self, _f: &dyn Fn(&T, &T) -> T) -> Self {
    ()
  }


  /// All-true testing can only be `true`.
  fn all(&self, _f: &dyn Fn(&T) -> bool) -> bool {
    true
  }


  /// All-pairs-true testing can only be `true`.
  fn all_with(&self, _other: &Self, _f: &dyn Fn(&T, &T) -> bool) -> bool {
    true
  }


  /// Any-true testing can only be `true`.
  fn any(&self, _f: &dyn Fn(&T) -> bool) -> bool {
    true
  }


  /// Any-pairs-true testing can only be `true`.
  fn any_with(&self, _other: &Self, _f: &dyn Fn(&T, &T) -> bool) -> bool {
    true
  }
}


///
/// 1-tuples form sequences by matching item.
///
impl<T> Sequence<T> for (T,) {

  /// Tuple count is the tuple arity.
  fn count(&self) -> usize {
    1
  }


  /// Mapping is over matching items.
  fn map(&self, f: &dyn Fn(&T) -> T) -> Self {
    (f(&self.0),)
  }


  /// Mapping pairs is over matching items.
  fn map_with(&self, xs: &Self, f: &dyn Fn(&T, &T) -> T) -> Self {
    (f(&self.0, &xs.0),)
  }


  /// All-true testing is over matching items.
  fn all(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0)
  }


  /// All-pairs-true testing is over matching items.
  fn all_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    f(&self.0, &other.0)
  }


  /// Any-true testing is over matching items.
  fn any(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0)
  }


  /// Any-pairs-true testing is over matching items.
  fn any_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    f(&self.0, &other.0)
  }
}


///
/// 2-tuples form sequences by matching item.
///
impl<T> Sequence<T> for (T, T) {

  /// Tuple count is the tuple arity.
  fn count(&self) -> usize {
    2
  }


  /// Mapping is over matching items.
  fn map(&self, f: &dyn Fn(&T) -> T) -> Self {
    (f(&self.0), f(&self.1))
  }


  /// Mapping pairs is over matching items.
  fn map_with(&self, xs: &Self, f: &dyn Fn(&T, &T) -> T) -> Self {
    (f(&self.0, &xs.0), f(&self.1, &xs.1))
  }


  /// All-true testing is over matching items.
  fn all(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0) && f(&self.1)
  }


  /// All-pairs-true testing is over matching items.
  fn all_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    f(&self.0, &other.0) && f(&self.1, &other.1)
  }


  /// Any-true testing is over matching items.
  fn any(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0) || f(&self.1)
  }


  /// Any-pairs-true testing is over matching items.
  fn any_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    f(&self.0, &other.0) || f(&self.1, &other.1)
  }
}


///
/// 3-tuples form sequences by matching item.
///
impl<T> Sequence<T> for (T, T, T) {

  /// Tuple count is the tuple arity.
  fn count(&self) -> usize {
    3
  }


  /// Mapping is over matching items.
  fn map(&self, f: &dyn Fn(&T) -> T) -> Self {
    (f(&self.0), f(&self.1), f(&self.2))
  }


  /// Mapping pairs is over matching items.
  fn map_with(&self, xs: &Self, f: &dyn Fn(&T, &T) -> T) -> Self {
    (f(&self.0, &xs.0), f(&self.1, &xs.1), f(&self.2, &xs.2))
  }


  /// All-true testing is over matching items.
  fn all(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0) && f(&self.1) && f(&self.2)
  }


  /// All-pairs-true testing is over matching items.
  fn all_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    let (x, y) = (self, other);

    f(&x.0, &y.0) && f(&x.1, &y.1) && f(&x.2, &y.2)
  }


  /// Any-true testing is over matching items.
  fn any(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0) || f(&self.1) || f(&self.2)
  }


  /// Any-pairs-true testing is over matching items.
  fn any_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    let (x, y) = (self, other);

    f(&x.0, &y.0) || f(&x.1, &y.1) || f(&x.2, &y.2)
  }
}


///
/// 4-tuples form sequences by matching item.
///
impl<T> Sequence<T> for (T, T, T, T) {

  /// Tuple count is the tuple arity.
  fn count(&self) -> usize {
    4
  }


  /// Mapping is over matching items.
  fn map(&self, f: &dyn Fn(&T) -> T) -> Self {
    (f(&self.0), f(&self.1), f(&self.2), f(&self.3))
  }


  /// Mapping pairs is over matching items.
  fn map_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> T) -> Self {
    let (x, y) = (self, other);

    (f(&x.0, &y.0), f(&x.1, &y.1), f(&x.2, &y.2), f(&x.3, &y.3))
  }


  /// All-true testing is over matching items.
  fn all(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0) && f(&self.1) && f(&self.2) && f(&self.3)
  }


  /// All-pairs-true testing is over matching items.
  fn all_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    let (x, y) = (self, other);

    f(&x.0, &y.0) && f(&x.1, &y.1) && f(&x.2, &y.2) && f(&x.3, &y.3)
  }


  /// Any-true testing is over matching items.
  fn any(&self, f: &dyn Fn(&T) -> bool) -> bool {
    f(&self.0) || f(&self.1) || f(&self.2) || f(&self.3)
  }


  /// Any-pairs-true testing is over matching items.
  fn any_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
    let (x, y) = (self, other);

    f(&x.0, &y.0) || f(&x.1, &y.1) || f(&x.2, &y.2) || f(&x.3, &y.3)
  }
}


///
/// Define `Sequence` implementations for arrays. Maybe not needed if
/// Rust had _const_ _generics_.
///
macro_rules! array_sequence {
  ($size:expr) => {
    impl<T: Copy> Sequence<T> for [T; $size] {

      /// Array count is the array length.
      fn count(&self) -> usize {
        $size
      }


      // Clunky but idiomatic use of iterators and return array.
      fn map(&self, f: &dyn Fn(&T) -> T) -> Self {
        let mut result: [T; $size] = *self;

        for (i, x) in self.iter().enumerate() {
          result[i] = f(x);
        }

        result
      }


      // Clunky but idiomatic use of iterators and return array.
      fn map_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> T) -> Self {
        let mut result: [T; $size] = *self;

        for (i, xs) in self.iter().zip(other).enumerate() {
          result[i] = f(xs.0, xs.1);
        }

        result
      }


      // Defer to the standard library `all` method.
      fn all(&self, f: &dyn Fn(&T) -> bool) -> bool {
        self.into_iter().all(f)
      }


      // Defer to the standard library `all` method.
      fn all_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
        self.into_iter().zip(other).all(|(x, y)| f(x, y))
      }


      // Defer to the standard library `any` method.
      fn any(&self, f: &dyn Fn(&T) -> bool) -> bool {
        self.into_iter().any(f)
      }


      // Defer to the standard library `any` method.
      fn any_with(&self, other: &Self, f: &dyn Fn(&T, &T) -> bool) -> bool {
        self.into_iter().zip(other).any(|(x, y)| f(x, y))
      }
    }
  };

  ($size:expr, $($others:expr),+) => {
    array_sequence! {$size}
    array_sequence! {$($others),+}
  };
}


// Array map types.
array_sequence! {
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
}