#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector {
	() => {
		impl<const N:usize,T> Vector<N,T>{
			#[inline(always)]
			pub const fn new(array:[T;N])->Self{
				Self{array}
			}
			#[inline(always)]
			pub fn to_array(self)->[T;N]{
				self.array
			}
			#[inline]
			pub fn map<F,U>(self,f:F)->Vector<N,U>
			where
				F:Fn(T)->U
			{
				Vector::new(
					self.array.map(f)
				)
			}
			#[inline]
			pub fn map_zip<F,U,V>(self,other:Vector<N,U>,f:F)->Vector<N,V>
			where
				F:Fn((T,U))->V,
			{
				let mut iter=self.array.into_iter().zip(other.array);
				Vector::new(
					core::array::from_fn(|_|f(iter.next().unwrap())),
				)
			}
		}
		impl<const N:usize,T:Copy> Vector<N,T>{
			#[inline(always)]
			pub const fn from_value(value:T)->Self{
				Self::new([value;N])
			}
		}

		impl<const N:usize,T:Default> Default for Vector<N,T>{
			#[inline]
			fn default()->Self{
				Self::new(
					core::array::from_fn(|_|Default::default())
				)
			}
		}

		impl<const N:usize,T:core::fmt::Display> core::fmt::Display for Vector<N,T>{
			#[inline]
			fn fmt(&self,f:&mut core::fmt::Formatter)->Result<(),core::fmt::Error>{
				for elem in &self.array[0..N-1]{
					core::write!(f,"{}, ",elem)?;
				}
				// assume we will be using vectors of length 1 or greater
				core::write!(f,"{}",self.array.last().unwrap())
			}
		}

		impl<const N:usize,T,E:std::fmt::Debug> Vector<N,Result<T,E>>{
			#[inline]
			pub fn unwrap(self)->Vector<N,T>{
				Vector{
					array:self.array.map(Result::unwrap)
				}
			}
		}

		impl<const N:usize,T:Ord> Vector<N,T>{
			#[inline]
			pub fn min(self,rhs:Self)->Self{
				self.map_zip(rhs,|(a,b)|a.min(b))
			}
			#[inline]
			pub fn max(self,rhs:Self)->Self{
				self.map_zip(rhs,|(a,b)|a.max(b))
			}
			#[inline]
			pub fn cmp(self,rhs:Self)->Vector<N,core::cmp::Ordering>{
				self.map_zip(rhs,|(a,b)|a.cmp(&b))
			}
			#[inline]
			pub fn lt(self,rhs:Self)->Vector<N,bool>{
				self.map_zip(rhs,|(a,b)|a.lt(&b))
			}
			#[inline]
			pub fn gt(self,rhs:Self)->Vector<N,bool>{
				self.map_zip(rhs,|(a,b)|a.gt(&b))
			}
			#[inline]
			pub fn ge(self,rhs:Self)->Vector<N,bool>{
				self.map_zip(rhs,|(a,b)|a.ge(&b))
			}
			#[inline]
			pub fn le(self,rhs:Self)->Vector<N,bool>{
				self.map_zip(rhs,|(a,b)|a.le(&b))
			}
		}

		impl<const N:usize> Vector<N,bool>{
			#[inline]
			pub fn all(&self)->bool{
				self.array==[true;N]
			}
			#[inline]
			pub fn any(&self)->bool{
				self.array!=[false;N]
			}
		}

		impl<const N:usize,T:core::ops::Neg<Output=V>,V> core::ops::Neg for Vector<N,T>{
			type Output=Vector<N,V>;
			#[inline]
			fn neg(self)->Self::Output{
				Vector::new(
					self.array.map(|t|-t)
				)
			}
		}

		impl<const N:usize,T> Vector<N,T>
		{
			#[inline]
			pub fn dot<U,V>(self,rhs:Vector<N,U>)->V
			where
				T:core::ops::Mul<U,Output=V>,
				V:core::iter::Sum,
			{
				self.array.into_iter().zip(rhs.array).map(|(a,b)|a*b).sum()
			}
		}

		impl<const N:usize,T,V> Vector<N,T>
		where
			T:core::ops::Mul<Output=V>+Copy,
			V:core::iter::Sum,
		{
			#[inline]
			pub fn length_squared(self)->V{
				self.array.into_iter().map(|t|t*t).sum()
			}
		}

		// Impl arithmetic operators
		$crate::impl_vector_assign_operator!(AddAssign, add_assign );
		$crate::impl_vector_operator!(Add, add );
		$crate::impl_vector_assign_operator!(SubAssign, sub_assign );
		$crate::impl_vector_operator!(Sub, sub );
		$crate::impl_vector_assign_operator!(RemAssign, rem_assign );
		$crate::impl_vector_operator!(Rem, rem );

		// mul and div are special, usually you multiply by a scalar
		// and implementing both vec*vec and vec*scalar is conflicting implementations Q_Q
		$crate::impl_vector_assign_operator_scalar!(MulAssign, mul_assign );
		$crate::impl_vector_operator_scalar!(Mul, mul );
		$crate::impl_vector_assign_operator_scalar!(DivAssign, div_assign );
		#[cfg(not(feature="deferred-division"))]
		$crate::impl_vector_operator_scalar!(Div, div );
		#[cfg(feature="deferred-division")]
		$crate::impl_vector_deferred_division!();

		// Impl bitwise operators
		$crate::impl_vector_assign_operator!(BitAndAssign, bitand_assign );
		$crate::impl_vector_operator!(BitAnd, bitand );
		$crate::impl_vector_assign_operator!(BitOrAssign, bitor_assign );
		$crate::impl_vector_operator!(BitOr, bitor );
		$crate::impl_vector_assign_operator!(BitXorAssign, bitxor_assign );
		$crate::impl_vector_operator!(BitXor, bitxor );

		// Impl shift operators
		$crate::impl_vector_shift_assign_operator!(ShlAssign, shl_assign);
		$crate::impl_vector_shift_operator!(Shl, shl);
		$crate::impl_vector_shift_assign_operator!(ShrAssign, shr_assign);
		$crate::impl_vector_shift_operator!(Shr, shr);

		// dedicated methods for this type
		#[cfg(feature="fixed-wide")]
		$crate::impl_fixed_wide_vector!();
	}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_deferred_division {
	() => {
		impl<const N:usize,T:ratio_ops::ratio::Divide<U,Output=V>,U:Copy,V> ratio_ops::ratio::Divide<U> for Vector<N,T>{
			type Output=Vector<N,V>;
			#[inline]
			fn divide(self,rhs:U)->Self::Output{
				self.map(|t|t.divide(rhs))
			}
		}
		impl<const N:usize,T,U> core::ops::Div<U> for Vector<N,T>{
			type Output=ratio_ops::ratio::Ratio<Vector<N,T>,U>;
			#[inline]
			fn div(self,rhs:U)->Self::Output{
				ratio_ops::ratio::Ratio::new(self,rhs)
			}
		}
	}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_operator_scalar {
	($trait: ident, $method: ident ) => {
		impl<const N:usize,T:core::ops::$trait<U,Output=V>,U:Copy,V> core::ops::$trait<U> for Vector<N,T>{
			type Output=Vector<N,V>;
			#[inline]
			fn $method(self,rhs:U)->Self::Output{
				self.map(|t|t.$method(rhs))
			}
		}
	}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_operator {
	($trait: ident, $method: ident ) => {
		impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
			type Output=Vector<N,V>;
			#[inline]
			fn $method(self,rhs:Vector<N,U>)->Self::Output{
				self.map_zip(rhs,|(a,b)|a.$method(b))
			}
		}
		impl<const N:usize,T:core::ops::$trait<i64,Output=T>> core::ops::$trait<i64> for Vector<N,T>{
			type Output=Self;
			#[inline]
			fn $method(self,rhs:i64)->Self::Output{
				self.map(|t|t.$method(rhs))
			}
		}
	}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_assign_operator_scalar {
	($trait: ident, $method: ident ) => {
		impl<const N:usize,T:core::ops::$trait<U>,U:Copy> core::ops::$trait<U> for Vector<N,T>{
			#[inline]
			fn $method(&mut self,rhs:U){
				self.array.iter_mut()
					.for_each(|t|t.$method(rhs))
			}
		}
	}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_assign_operator {
	($trait: ident, $method: ident ) => {
		impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
			#[inline]
			fn $method(&mut self,rhs:Vector<N,U>){
				self.array.iter_mut().zip(rhs.array)
					.for_each(|(a,b)|a.$method(b))
			}
		}
		impl<const N:usize,T:core::ops::$trait<i64>> core::ops::$trait<i64> for Vector<N,T>{
			#[inline]
			fn $method(&mut self,rhs:i64){
				self.array.iter_mut()
					.for_each(|t|t.$method(rhs))
			}
		}
	}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_shift_operator {
	($trait: ident, $method: ident ) => {
		impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
			type Output=Vector<N,V>;
			#[inline]
			fn $method(self,rhs:Vector<N,U>)->Self::Output{
				self.map_zip(rhs,|(a,b)|a.$method(b))
			}
		}
		impl<const N:usize,T:core::ops::$trait<u32,Output=V>,V> core::ops::$trait<u32> for Vector<N,T>{
			type Output=Vector<N,V>;
			#[inline]
			fn $method(self,rhs:u32)->Self::Output{
				self.map(|t|t.$method(rhs))
			}
		}
	}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_shift_assign_operator {
	($trait: ident, $method: ident ) => {
		impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
			#[inline]
			fn $method(&mut self,rhs:Vector<N,U>){
				self.array.iter_mut().zip(rhs.array)
					.for_each(|(a,b)|a.$method(b))
			}
		}
		impl<const N:usize,T:core::ops::$trait<u32>> core::ops::$trait<u32> for Vector<N,T>{
			#[inline]
			fn $method(&mut self,rhs:u32){
				self.array.iter_mut()
					.for_each(|t|t.$method(rhs))
			}
		}
	}
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_extend {
	( $size: expr ) => {
		impl<T> Vector<$size,T>{
			#[inline]
			pub fn extend(self,value:T)->Vector<{$size+1},T>{
				let mut iter=self.array.into_iter().chain(core::iter::once(value));
				Vector::new(
					core::array::from_fn(|_|iter.next().unwrap()),
				)
			}
		}
	}
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_named_fields {
	( $struct:ident,  $size: expr ) => {
		impl<T> core::ops::Deref for Vector<$size,T>{
			type Target=$struct<T>;
			#[inline]
			fn deref(&self)->&Self::Target{
				// This cast is valid because Vector has #[repr(transparent)]
				let ptr:*const [T;$size]=&self.array;
				let ptr=ptr as *const Self::Target;
				// SAFETY: this pointer is non-null because it comes from a reference
				unsafe{&*ptr}
			}
		}
		impl<T> core::ops::DerefMut for Vector<$size,T>{
			#[inline]
			fn deref_mut(&mut self)->&mut Self::Target{
				// This cast is valid because Vector has #[repr(transparent)]
				let ptr:*mut [T;$size]=&mut self.array;
				let ptr=ptr as *mut Self::Target;
				// SAFETY: this pointer is non-null because it comes from a reference
				unsafe{&mut*ptr}
			}
		}
	}
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_3 {
	()=>{
		impl<T> Vector<3,T>
		{
			#[inline]
			pub fn cross<U,V>(self,rhs:Vector<3,U>)->Vector<3,<V as core::ops::Sub>::Output>
			where
				T:core::ops::Mul<U,Output=V>+Copy,
				U:Copy,
				V:core::ops::Sub,
			{
				Vector::new([
					self.y*rhs.z-self.z*rhs.y,
					self.z*rhs.x-self.x*rhs.z,
					self.x*rhs.y-self.y*rhs.x,
				])
			}
		}
	}
}
