#![deny(missing_docs)]
extern crate num_traits;
extern crate typenum;
#[cfg_attr(test, macro_use)]
extern crate generic_array;
use std::{cmp, mem, ptr, slice};
use std::mem::ManuallyDrop;
use std::borrow::{Borrow, BorrowMut};
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
use std::ops::{Add, Sub};
use std::iter::FromIterator;
use std::fmt::{Debug, Formatter, Result as FmtResult};
use typenum::*;
use generic_array::{ArrayLength, GenericArray, GenericArrayIter};
pub trait NumericSequence<T> {
type Length: ArrayLength<T>;
}
pub trait Lengthen<T>: NumericSequence<T> {
type Longer: Shorten<T>;
fn lengthen(self, last: T) -> Self::Longer;
}
pub trait Shorten<T>: NumericSequence<T> {
type Shorter: Lengthen<T>;
fn shorten(self) -> (Self::Shorter, T);
}
#[repr(C)]
pub struct NumericArray<T, N: ArrayLength<T>>(GenericArray<T, N>);
#[macro_export]
macro_rules! narr {
($($t:tt)*) => {
$crate::NumericArray::new(arr!($($t)*))
}
}
impl<T, N: ArrayLength<T>> NumericSequence<T> for NumericArray<T, N> {
type Length = N;
}
impl<T, N: ArrayLength<T>> Lengthen<T> for NumericArray<T, N>
where
N: Add<B1>,
Add1<N>: ArrayLength<T>,
Add1<N>: Sub<B1, Output=N>,
Sub1<Add1<N>>: ArrayLength<T>
{
type Longer = NumericArray<T, Add1<N>>;
fn lengthen(self, last: T) -> Self::Longer {
let mut longer: ManuallyDrop<GenericArray<T, Add1<N>>> =
ManuallyDrop::new(unsafe { mem::uninitialized() });
for (dst, src) in longer.iter_mut().zip(self.iter()) {
unsafe {
ptr::write(dst, ptr::read(src));
}
}
unsafe {
ptr::write(&mut longer[N::to_usize()], last);
}
mem::forget(self);
NumericArray(ManuallyDrop::into_inner(longer))
}
}
impl<T, N: ArrayLength<T>> Shorten<T> for NumericArray<T, N>
where
N: Sub<B1>,
Sub1<N>: ArrayLength<T>,
Sub1<N>: Add<B1, Output=N>,
Add1<Sub1<N>>: ArrayLength<T>,
{
type Shorter = NumericArray<T, Sub1<N>>;
fn shorten(self) -> (Self::Shorter, T) {
let mut shorter: ManuallyDrop<GenericArray<T, Sub1<N>>> =
ManuallyDrop::new(unsafe { mem::uninitialized() });
for (dst, src) in shorter.iter_mut().zip(self.iter()) {
unsafe {
ptr::write(dst, ptr::read(src));
}
}
let last = unsafe { ptr::read(&self.0[N::to_usize() - 1]) };
mem::forget(self);
let array = ManuallyDrop::into_inner(shorter);
(NumericArray(array), last)
}
}
#[derive(Debug, Clone, Copy)]
pub struct NumericConstant<T>(pub T);
#[macro_export]
macro_rules! nconstant {
($value:expr) => { $crate::NumericConstant($value) }
}
impl<T> Deref for NumericConstant<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for NumericConstant<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: Debug, N: ArrayLength<T>> Debug for NumericArray<T, N> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.debug_tuple("NumericArray").field(&self.0).finish()
}
}
impl<T, N: ArrayLength<T>> From<GenericArray<T, N>> for NumericArray<T, N> {
fn from(arr: GenericArray<T, N>) -> NumericArray<T, N> {
NumericArray(arr)
}
}
impl<T: Clone, N: ArrayLength<T>> Clone for NumericArray<T, N> {
fn clone(&self) -> NumericArray<T, N> {
NumericArray(self.0.clone())
}
}
impl<T: Copy, N: ArrayLength<T>> Copy for NumericArray<T, N>
where
N::ArrayType: Copy,
{
}
impl<T, N: ArrayLength<T>> Deref for NumericArray<T, N> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T, N: ArrayLength<T>> DerefMut for NumericArray<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T, U, N: ArrayLength<T> + ArrayLength<U>> PartialEq<NumericArray<U, N>> for NumericArray<T, N>
where
T: PartialEq<U>,
{
fn eq(&self, rhs: &NumericArray<U, N>) -> bool {
**self == **rhs
}
}
impl<T, U, N: ArrayLength<T> + ArrayLength<U>> PartialEq<GenericArray<U, N>> for NumericArray<T, N>
where
T: PartialEq<U>
{
fn eq(&self, rhs: &GenericArray<U, N>) -> bool {
**self == **rhs
}
fn ne(&self, rhs: &GenericArray<U, N>) -> bool {
**self == **rhs
}
}
impl<T, N: ArrayLength<T>> cmp::Eq for NumericArray<T, N>
where
T: cmp::Eq,
{
}
impl<T, N: ArrayLength<T>> PartialOrd<Self> for NumericArray<T, N>
where
T: PartialOrd,
{
#[inline]
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(&self.0, &rhs.0)
}
#[inline]
fn lt(&self, rhs: &Self) -> bool {
PartialOrd::lt(&self.0, &rhs.0)
}
#[inline]
fn le(&self, rhs: &Self) -> bool {
PartialOrd::le(&self.0, &rhs.0)
}
#[inline]
fn gt(&self, rhs: &Self) -> bool {
PartialOrd::gt(&self.0, &rhs.0)
}
#[inline]
fn ge(&self, rhs: &Self) -> bool {
PartialOrd::ge(&self.0, &rhs.0)
}
}
impl<T, N: ArrayLength<T>> PartialOrd<GenericArray<T, N>> for NumericArray<T, N>
where
T: PartialOrd,
{
#[inline]
fn partial_cmp(&self, rhs: &GenericArray<T, N>) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(&self.0, rhs)
}
#[inline]
fn lt(&self, rhs: &GenericArray<T, N>) -> bool {
PartialOrd::lt(&self.0, rhs)
}
#[inline]
fn le(&self, rhs: &GenericArray<T, N>) -> bool {
PartialOrd::le(&self.0, rhs)
}
#[inline]
fn gt(&self, rhs: &GenericArray<T, N>) -> bool {
PartialOrd::gt(&self.0, rhs)
}
#[inline]
fn ge(&self, rhs: &GenericArray<T, N>) -> bool {
PartialOrd::ge(&self.0, rhs)
}
}
impl<T, N: ArrayLength<T>> cmp::Ord for NumericArray<T, N>
where
T: cmp::Ord,
{
#[inline]
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
cmp::Ord::cmp(&self.0, &rhs.0)
}
}
impl<T, N: ArrayLength<T>> NumericArray<T, N> {
#[inline]
pub fn new(arr: GenericArray<T, N>) -> NumericArray<T, N> {
NumericArray(arr)
}
#[inline]
pub fn into_array(self) -> GenericArray<T, N> {
self.0
}
#[inline]
pub fn as_array(&self) -> &GenericArray<T, N> {
&self.0
}
#[inline]
pub fn as_mut_array(&mut self) -> &mut GenericArray<T, N> {
&mut self.0
}
#[inline]
pub fn as_slice(&self) -> &[T] {
&self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.0
}
#[inline]
pub fn from_element(t: T) -> NumericArray<T, N>
where
T: Clone,
{
NumericArray(GenericArray::generate(|_| t.clone()))
}
}
impl<T, N: ArrayLength<T>> AsRef<[T]> for NumericArray<T, N> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<T, N: ArrayLength<T>> Borrow<[T]> for NumericArray<T, N> {
fn borrow(&self) -> &[T] {
self
}
}
impl<T, N: ArrayLength<T>> AsMut<[T]> for NumericArray<T, N> {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
impl<T, N: ArrayLength<T>> BorrowMut<[T]> for NumericArray<T, N> {
fn borrow_mut(&mut self) -> &mut [T] {
self
}
}
impl<T, N: ArrayLength<T>> Index<usize> for NumericArray<T, N> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &T {
&(**self)[index]
}
}
impl<T, N: ArrayLength<T>> IndexMut<usize> for NumericArray<T, N> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
&mut (**self)[index]
}
}
impl<T, N: ArrayLength<T>> Index<Range<usize>> for NumericArray<T, N> {
type Output = [T];
#[inline]
fn index(&self, index: Range<usize>) -> &[T] {
Index::index(&**self, index)
}
}
impl<T, N: ArrayLength<T>> Index<RangeTo<usize>> for NumericArray<T, N> {
type Output = [T];
#[inline]
fn index(&self, index: RangeTo<usize>) -> &[T] {
Index::index(&**self, index)
}
}
impl<T, N: ArrayLength<T>> Index<RangeFrom<usize>> for NumericArray<T, N> {
type Output = [T];
#[inline]
fn index(&self, index: RangeFrom<usize>) -> &[T] {
Index::index(&**self, index)
}
}
impl<T, N: ArrayLength<T>> Index<RangeFull> for NumericArray<T, N> {
type Output = [T];
#[inline]
fn index(&self, _index: RangeFull) -> &[T] {
self
}
}
impl<'a, T, N: ArrayLength<T>> IntoIterator for &'a NumericArray<T, N> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, N: ArrayLength<T>> IntoIterator for &'a mut NumericArray<T, N> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T, N: ArrayLength<T>> IntoIterator for NumericArray<T, N> {
type Item = T;
type IntoIter = GenericArrayIter<T, N>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<T, N: ArrayLength<T>> FromIterator<T> for NumericArray<T, N>
where
T: Default,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
NumericArray(GenericArray::from_iter(iter))
}
}
impl<T, N: ArrayLength<T>> Default for NumericArray<T, N>
where
T: Default,
{
fn default() -> Self {
NumericArray(GenericArray::default())
}
}
impl<T, N: ArrayLength<T>> num_traits::Zero for NumericArray<T, N>
where
T: num_traits::Zero,
{
fn zero() -> Self {
NumericArray(GenericArray::generate(|_| <T as num_traits::Zero>::zero()))
}
fn is_zero(&self) -> bool {
self.iter().all(|x| x.is_zero())
}
}
impl<T, N: ArrayLength<T>> num_traits::One for NumericArray<T, N>
where
T: num_traits::One,
{
fn one() -> Self {
NumericArray(GenericArray::generate(|_| <T as num_traits::One>::one()))
}
}
macro_rules! impl_unary_ops {
($($op_trait:ident::$op:ident),*) => {
$(
impl<T, N: ArrayLength<T>> ::std::ops::$op_trait for NumericArray<T, N>
where
T: ::std::ops::$op_trait,
N: ArrayLength<<T as ::std::ops::$op_trait>::Output>
{
type Output = NumericArray<<T as ::std::ops::$op_trait>::Output, N>;
fn $op(self) -> Self::Output {
NumericArray(self.0.map(::std::ops::$op_trait::$op))
}
}
)*
}
}
macro_rules! impl_binary_ops {
($($op_trait:ident::$op:ident),*) => {
$(
impl<T, U, N: ArrayLength<T> + ArrayLength<U>> ::std::ops::$op_trait<NumericArray<U, N>> for NumericArray<T, N>
where
T: ::std::ops::$op_trait<U>,
N: ArrayLength<<T as ::std::ops::$op_trait<U>>::Output>
{
type Output = NumericArray<<T as ::std::ops::$op_trait<U>>::Output, N>;
fn $op(self, rhs: NumericArray<U, N>) -> Self::Output {
NumericArray(self.0.zip(rhs.0, ::std::ops::$op_trait::$op))
}
}
impl<T, U: Clone, N: ArrayLength<T>> ::std::ops::$op_trait<NumericConstant<U>> for NumericArray<T, N>
where
T: ::std::ops::$op_trait<U>,
N: ArrayLength<<T as ::std::ops::$op_trait<U>>::Output>
{
type Output = NumericArray<<T as ::std::ops::$op_trait<U>>::Output, N>;
fn $op(self, rhs: NumericConstant<U>) -> Self::Output {
NumericArray(self.0.map(|l| ::std::ops::$op_trait::$op(l, rhs.0.clone())))
}
}
)*
}
}
macro_rules! impl_assign_ops {
($($op_trait:ident::$op:ident),*) => {
$(
impl<T, U, N: ArrayLength<T> + ArrayLength<U>> ::std::ops::$op_trait<NumericArray<U, N>> for NumericArray<T, N>
where
T: ::std::ops::$op_trait<U>
{
fn $op(&mut self, rhs: NumericArray<U, N>) {
for (lhs, rhs) in self.iter_mut().zip(rhs.iter()) {
::std::ops::$op_trait::$op(lhs, unsafe { ptr::read(rhs) });
}
mem::forget(rhs);
}
}
impl<T, U: Clone, N: ArrayLength<T>> ::std::ops::$op_trait<NumericConstant<U>> for NumericArray<T, N>
where
T: ::std::ops::$op_trait<U>
{
fn $op(&mut self, rhs: NumericConstant<U>) {
for lhs in self.iter_mut() {
::std::ops::$op_trait::$op(lhs, rhs.0.clone());
}
}
}
)*
}
}
macro_rules! impl_wrapping_ops {
($($op_trait:ident::$op:ident),*) => {
$(
impl<T, N: ArrayLength<T>> num_traits::$op_trait for NumericArray<T, N>
where
T: num_traits::$op_trait
{
fn $op(&self, rhs: &Self) -> Self {
NumericArray(self.0.zip_ref(&rhs.0, num_traits::$op_trait::$op))
}
}
)*
}
}
macro_rules! impl_checked_ops {
($($op_trait:ident::$op:ident),*) => {
$(
impl<T, N: ArrayLength<T>> num_traits::$op_trait for NumericArray<T, N>
where
T: num_traits::$op_trait
{
fn $op(&self, rhs: &Self) -> Option<Self> {
let mut res: ManuallyDrop<GenericArray<T, N>> =
ManuallyDrop::new(unsafe { mem::uninitialized() });
for (dst, (lhs, rhs)) in res.iter_mut().zip(self.iter().zip(rhs.iter())) {
if let Some(value) = num_traits::$op_trait::$op(lhs, rhs) {
unsafe {
ptr::write(dst, value);
}
} else {
return None;
}
}
Some(NumericArray(ManuallyDrop::into_inner(res)))
}
}
)*
}
}
impl_unary_ops!(Neg::neg, Not::not);
impl_binary_ops! {
Add::add,
Sub::sub,
Mul::mul,
Div::div,
Rem::rem,
BitAnd::bitand,
BitOr::bitor,
BitXor::bitxor,
Shr::shr,
Shl::shl
}
impl_assign_ops! {
AddAssign::add_assign,
SubAssign::sub_assign,
MulAssign::mul_assign,
DivAssign::div_assign,
RemAssign::rem_assign,
BitAndAssign::bitand_assign,
BitOrAssign::bitor_assign,
BitXorAssign::bitxor_assign,
ShrAssign::shr_assign,
ShlAssign::shl_assign
}
impl<T, N: ArrayLength<T>> num_traits::Saturating for NumericArray<T, N>
where
T: num_traits::Saturating,
{
fn saturating_add(self, rhs: Self) -> Self {
NumericArray(self.0.zip(rhs.0, num_traits::Saturating::saturating_add))
}
fn saturating_sub(self, rhs: Self) -> Self {
NumericArray(self.0.zip(rhs.0, num_traits::Saturating::saturating_sub))
}
}
impl_wrapping_ops! {
WrappingAdd::wrapping_add,
WrappingSub::wrapping_sub,
WrappingMul::wrapping_mul
}
impl_checked_ops! {
CheckedAdd::checked_add,
CheckedSub::checked_sub,
CheckedMul::checked_mul,
CheckedDiv::checked_div
}
impl<T: Clone, N: ArrayLength<T>> num_traits::Num for NumericArray<T, N>
where
T: num_traits::Num,
{
type FromStrRadixErr = <T as num_traits::Num>::FromStrRadixErr;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
<T as num_traits::Num>::from_str_radix(str, radix).map(Self::from_element)
}
}
impl<T: Clone, N: ArrayLength<T>> num_traits::Signed for NumericArray<T, N>
where
T: num_traits::Signed,
{
fn abs(&self) -> Self {
NumericArray(self.0.map_ref(num_traits::Signed::abs))
}
fn abs_sub(&self, rhs: &Self) -> Self {
NumericArray(self.0.zip_ref(&rhs.0, num_traits::Signed::abs_sub))
}
fn signum(&self) -> Self {
NumericArray(self.0.map_ref(num_traits::Signed::signum))
}
fn is_positive(&self) -> bool {
self.iter().all(num_traits::Signed::is_positive)
}
fn is_negative(&self) -> bool {
self.iter().any(num_traits::Signed::is_negative)
}
}
impl<T: Clone, N: ArrayLength<T>> num_traits::Unsigned for NumericArray<T, N>
where
T: num_traits::Unsigned,
{
}
macro_rules! impl_float_const {
($($f:ident),*) => {
impl<T, N: ArrayLength<T>> num_traits::FloatConst for NumericArray<T, N>
where
T: num_traits::FloatConst
{
$(
fn $f() -> Self {
NumericArray(GenericArray::generate(|_| <T as num_traits::FloatConst>::$f()))
}
)*
}
}
}
impl_float_const!(
E,
FRAC_1_PI,
FRAC_1_SQRT_2,
FRAC_2_PI,
FRAC_2_SQRT_PI,
FRAC_PI_2,
FRAC_PI_3,
FRAC_PI_4,
FRAC_PI_6,
FRAC_PI_8,
LN_10,
LN_2,
LOG10_E,
LOG2_E,
PI,
SQRT_2
);
impl<T, N: ArrayLength<T>> num_traits::Bounded for NumericArray<T, N>
where
T: num_traits::Bounded,
{
fn min_value() -> Self {
NumericArray(GenericArray::generate(
|_| <T as num_traits::Bounded>::min_value(),
))
}
fn max_value() -> Self {
NumericArray(GenericArray::generate(
|_| <T as num_traits::Bounded>::max_value(),
))
}
}
#[cfg(test)]
mod test {
use super::*;
#[inline(never)]
pub fn black_box<T>(val: T) -> T {
use std::{mem, ptr};
let ret = unsafe { ptr::read_volatile(&val) };
mem::forget(val);
ret
}
#[test]
fn shorten() {
let a = narr![i32; 1, 2, 3, 4];
let b = narr![i32; 1, 2, 3];
assert_eq!(a.shorten().0, b);
}
#[test]
fn lengthen() {
let a = narr![i32; 1, 2, 3, 4];
let b = narr![i32; 1, 2, 3];
assert_eq!(a, b.lengthen(4));
}
#[test]
fn ops() {
let a = black_box(narr![i32; 1, 3, 5, 7]);
let b = black_box(narr![i32; 2, 4, 6, 8]);
let c = a + b;
let d = c * nconstant!(black_box(5));
let e = d << nconstant!(1_usize);
assert_eq!(e, narr![i32; 30, 70, 110, 150])
}
#[test]
fn readme_example() {
let a = narr![i32; 1, 3, 5, 7];
let b = narr![i32; 2, 4, 6, 8];
let c = a + b * nconstant!(2);
assert_eq!(c, narr![i32; 5, 11, 17, 23]);
}
#[test]
fn iter() {
use typenum::consts::U6;
let t = [1, 2, 3, 4];
let a = NumericArray::<i32, U6>::from_iter(t.iter().cloned());
assert_eq!(a, narr![i32; 1, 2, 3, 4, 0, 0]);
}
#[test]
fn floats() {
let a = black_box(narr![f32; 1.0, 3.0, 5.0, 7.0]);
let b = black_box(narr![f32; 2.0, 4.0, 6.0, 8.0]);
let c = a + b;
black_box(c);
}
}