#![no_std]
pub mod create_pair_prelude {
pub use crate::{create_pair, declare_type, impl_common_methods, impl_core_ops};
pub use crate::num_traits_method;
#[cfg(feature = "num-traits")]
pub use num_traits::{Float, Zero};
#[cfg(feature = "serde")]
pub use serde::{Deserialize, Serialize};
}
#[allow(unused_imports)]
use create_pair_prelude::*;
#[macro_export]
macro_rules! create_pair {
( $name: tt; $($field: tt),* ) => {
create_pair!(struct $name; $($field),*);
};
($(#[$attr: meta])* struct $name: tt; $($field: tt),* ) =>{
#[cfg(feature = "serde")]
declare_type!(
$(#[$attr])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[derive(Deserialize, Serialize)]
struct $name; $($field),*
);
#[cfg(not(feature = "serde"))]
declare_type!(
$(#[$attr])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
struct $name; $($field),*
);
impl_common_methods!($name; $($field),*);
impl_core_ops!($name);
#[cfg(feature = "num-traits")]
num_traits_method!($name);
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! declare_type {
($(#[$attr: meta])* struct $name: tt; $($field: tt),* ) => {
$(#[$attr])*
pub struct $name<T> {
$(pub $field: T),*
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_common_methods {
($name: tt; $($field: tt),*) => {
impl<T> $name<T>{
pub const fn new($($field: T),*) -> $name<T> {
Self {$($field),*}
}
pub fn from_cloned(value: T) -> $name<T>
where T: Clone
{
Self {$($field: value.clone()),*}
}
pub const fn as_ref(&self) -> $name<&T> {
$name {$($field: &self.$field),*}
}
pub fn as_mut(&mut self) -> $name<&mut T> {
$name {$($field: &mut self.$field),*}
}
pub fn map<U, F>(self, mut f: F) -> $name<U>
where F: FnMut(T) -> U
{
$name {$($field: f(self.$field)),*}
}
pub fn map_in_place<F>(&mut self, mut f: F) -> &mut $name<T>
where F: FnMut(&mut T)
{
$(f(&mut self.$field);)*
self
}
pub fn map_entrywise<U, V, F>(self, rhs: $name<U>, mut f: F) -> $name<V>
where F: FnMut(T, U) -> V
{
$name {$($field: f(self.$field, rhs.$field)),*}
}
pub fn map_entrywise_in_place<U, F>(&mut self, rhs: $name<U>, mut f: F) -> &mut $name<T>
where F: FnMut(&mut T, U)
{
$(f(&mut self.$field, rhs.$field);)*
self
}
#[deprecated(since = "0.1.3", note = "Use into_iter().fold(init, f) instead")]
pub fn fold<U, F>(self, init: U, f: F) -> U
where F: FnMut(U, T) -> U
{
self.into_iter().fold(init, f)
}
pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
core::iter::empty() $(.chain(core::iter::once(&self.$field)))*
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
core::iter::empty() $(.chain(core::iter::once(&mut self.$field)))*
}
pub fn into_iter(self) -> impl Iterator<Item = T> {
core::iter::empty() $(.chain(core::iter::once(self.$field)))*
}
}
impl<T: core::ops::Deref> $name<T>
{
pub fn as_deref(&self) -> $name<&<T as core::ops::Deref>::Target> {
self.as_ref().map(core::ops::Deref::deref)
}
}
impl<T: core::ops::DerefMut> $name<T>
{
pub fn as_deref_mut(&mut self) -> $name<&mut <T as core::ops::Deref>::Target> {
self.as_mut().map(core::ops::DerefMut::deref_mut)
}
}
impl<T: Clone> $name<&T> {
pub fn cloned(self) -> $name<T> {
self.map(Clone::clone)
}
}
impl<T: Clone> $name<&mut T> {
pub fn cloned(self) -> $name<T> {
self.map(|r| r as &T).map(Clone::clone)
}
}
impl<T: Copy> $name<&T> {
pub fn copied(self) -> $name<T> {
self.cloned()
}
}
impl<T: Copy> $name<&mut T> {
pub fn copied(self) -> $name<T> {
self.cloned()
}
}
impl<T> $name<Option<T>> {
pub fn into_option(self) -> Option<$name<T>> {
Some($name {$($field: self.$field?),*})
}
}
impl<T, E> $name<Result<T, E>> {
pub fn into_result(self) -> Result<$name<T>, E> {
Ok($name {$($field: self.$field?),*})
}
}
impl<T> core::fmt::Display for $name<T>
where T: core::fmt::Display
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "(")?;
$(write!(f, "{}, ", self.$field)?;)*
write!(f, ")")?;
Ok(())
}
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! impl_core_ops {
($name: tt) => {
impl<T> core::ops::Neg for $name<T>
where
T: core::ops::Neg,
{
type Output = $name<T::Output>;
fn neg(self) -> Self::Output {
self.map(|value| -value)
}
}
impl<T, U> core::ops::Add<$name<U>> for $name<T>
where
T: core::ops::Add<U>,
{
type Output = $name<T::Output>;
fn add(self, rhs: $name<U>) -> Self::Output {
self.map_entrywise(rhs, |left, right| left + right)
}
}
impl<T, U> core::ops::Sub<$name<U>> for $name<T>
where
T: core::ops::Sub<U>,
{
type Output = $name<T::Output>;
fn sub(self, rhs: $name<U>) -> Self::Output {
self.map_entrywise(rhs, |left, right| left - right)
}
}
impl<T, U> core::ops::Mul<U> for $name<T>
where
T: core::ops::Mul<U>,
U: Copy,
{
type Output = $name<T::Output>;
fn mul(self, rhs: U) -> Self::Output {
self.map(|value| value * rhs)
}
}
impl<T, U> core::ops::Div<U> for $name<T>
where
T: core::ops::Div<U>,
U: Copy,
{
type Output = $name<T::Output>;
fn div(self, rhs: U) -> Self::Output {
self.map(|value| value / rhs)
}
}
impl<T, U> core::ops::Rem<U> for $name<T>
where
T: core::ops::Rem<U>,
U: Copy,
{
type Output = $name<T::Output>;
fn rem(self, rhs: U) -> Self::Output {
self.map(|value| value % rhs)
}
}
impl<T> core::ops::AddAssign for $name<T>
where
T: core::ops::AddAssign,
{
fn add_assign(&mut self, rhs: Self) {
self.map_entrywise_in_place(rhs, |lhs, rhs| *lhs += rhs);
}
}
impl<T> core::ops::SubAssign for $name<T>
where
T: core::ops::SubAssign,
{
fn sub_assign(&mut self, rhs: Self) {
self.map_entrywise_in_place(rhs, |lhs, rhs| *lhs -= rhs);
}
}
impl<T, U> core::ops::MulAssign<U> for $name<T>
where
T: core::ops::MulAssign<U>,
U: Copy,
{
fn mul_assign(&mut self, rhs: U) {
self.map_in_place(|value| *value *= rhs);
}
}
impl<T, U> core::ops::DivAssign<U> for $name<T>
where
T: core::ops::DivAssign<U>,
U: Copy,
{
fn div_assign(&mut self, rhs: U) {
self.map_in_place(|value| *value /= rhs);
}
}
impl<T, U> core::ops::RemAssign<U> for $name<T>
where
T: core::ops::RemAssign<U>,
U: Copy,
{
fn rem_assign(&mut self, rhs: U) {
self.map_in_place(|value| *value %= rhs);
}
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! num_traits_method {
($name: tt) => {
impl<T> $name<T>
where
T: Copy + core::ops::Add<Output = T> + core::ops::Mul<Output = T> + Zero,
{
pub fn norm(self) -> T {
self.map(|value| value * value)
.into_iter()
.fold(T::zero(), |acc, cur| acc + cur)
}
}
impl<T: Float> $name<T> {
pub fn len(self) -> T {
self.norm().sqrt()
}
pub fn normalize(self) -> $name<T> {
self / self.len()
}
}
};
}
create_pair!(
struct Pair;
x,
y
);
create_pair!(
struct Triplet;
x,
y,
z
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let p = Pair::new(2, 3);
assert_eq!(2, p.x);
assert_eq!(3, p.y);
}
#[test]
fn test_from_cloned() {
let v = [0, 1, 2];
let p = Pair::from_cloned(v.clone());
assert_eq!(v, p.x);
assert_eq!(v, p.y);
}
#[test]
fn test_as_ref() {
let v = [0, 1, 2];
let p = Pair::from_cloned(v.clone());
let q = p.as_ref();
assert_eq!(Pair::new(&v, &v), q);
}
#[test]
fn test_as_mut() {
let mut p = Pair::new(1, 2);
let q = p.as_mut();
assert_eq!(Pair::new(&mut 1, &mut 2), q);
}
#[test]
fn test_map() {
let p = Pair::new(2, 3).map(|value| value * value);
assert_eq!(4, p.x);
assert_eq!(9, p.y);
}
#[test]
fn test_map_in_place() {
let mut p = Pair::new(2, 3);
p.map_in_place(|value| *value += 1)
.map_in_place(|value| *value *= 2);
assert_eq!(6, p.x);
assert_eq!(8, p.y);
}
#[test]
fn map_entrywise() {
let p = Pair::new(2, 3);
let q = Pair::new(4, 5);
let r = p.map_entrywise(q, |lhs, rhs| lhs + rhs);
assert_eq!(6, r.x);
assert_eq!(8, r.y);
}
#[test]
fn test_map_entrywise_in_place() {
let mut p = Pair::new(2, 3);
let q = Pair::new(4, 5);
let r = Pair::new(6, 7);
p.map_entrywise_in_place(q, |lhs, rhs| *lhs += rhs)
.map_entrywise_in_place(r, |lhs, rhs| *lhs *= rhs);
assert_eq!(36, p.x);
assert_eq!(56, p.y);
}
#[test]
fn test_fold() {
let f = Pair::new(2, 3).fold(1, |acc, cur| acc * cur);
assert_eq!(6, f);
}
#[test]
fn test_iter() {
let p = Pair::new(1, 2);
let mut iter = p.iter();
assert_eq!(Some(&1), iter.next());
assert_eq!(Some(&2), iter.next());
assert!(iter.next().is_none());
}
#[test]
fn test_iter_mut() {
let mut p = Pair::new(1, 2);
let mut iter = p.iter_mut();
assert_eq!(Some(&mut 1), iter.next());
assert_eq!(Some(&mut 2), iter.next());
assert!(iter.next().is_none());
}
#[test]
fn test_into_iter() {
let p = Pair::new(1, 2);
let mut iter = p.into_iter();
assert_eq!(Some(1), iter.next());
assert_eq!(Some(2), iter.next());
assert!(iter.next().is_none());
}
#[test]
fn test_as_deref() {
let p = Pair::new(1, 2);
let q = p.as_ref();
let r = q.as_deref();
assert_eq!(Pair::new(&1, &2), r);
}
#[test]
fn test_as_deref_mut() {
let mut p = Pair::new(1, 2);
let mut q = p.as_mut();
let r = q.as_deref_mut();
assert_eq!(Pair::new(&mut 1, &mut 2), r);
}
#[test]
fn test_cloned() {
let p = Pair::new([1, 2], [3, 4]);
let q = p.as_ref().cloned();
assert_eq!(p, q);
}
#[test]
fn test_cloned_mut() {
let mut p = Pair::new([1, 2], [3, 4]);
let q = p.as_mut().cloned();
assert_eq!(p, q);
}
#[test]
fn test_copied() {
let p = Pair::new(1, 2);
let q = p.as_ref().copied();
assert_eq!(p, q);
}
#[test]
fn test_copied_mut() {
let mut p = Pair::new(1, 2);
let q = p.as_mut().copied();
assert_eq!(p, q);
}
#[test]
fn test_into_option() {
let p = Pair::new(Some(2), Some(3)).into_option();
assert_eq!(Some(Pair::new(2, 3)), p);
assert!(Pair::new(Some(2), None).into_option().is_none());
assert!(Pair::new(None, Some(3)).into_option().is_none());
assert!(Pair::<Option<i32>>::new(None, None).into_option().is_none());
}
#[test]
fn test_into_result() {
use core::str::FromStr;
let p = Pair::new("1", "2").map(i32::from_str).into_result();
assert_eq!(Ok(Pair::new(1, 2)), p);
let q = Pair::new("1", "lamy").map(i32::from_str).into_result();
assert!(q.is_err());
let r = Pair::new("polka", "lamy").map(i32::from_str).into_result();
assert!(r.is_err());
}
#[test]
fn test_neg() {
assert_eq!(Pair::new(-2, -3), -Pair::new(2, 3));
}
#[test]
fn test_add() {
let p = Pair::new(2, 3);
let q = Pair::new(4, 5);
assert_eq!(Pair::new(6, 8), p + q);
assert_eq!(Pair::new(6, 8), p + q.as_ref());
assert_eq!(Pair::new(6, 8), p.as_ref() + q);
assert_eq!(Pair::new(6, 8), p.as_ref() + q.as_ref());
}
#[test]
fn test_sub() {
assert_eq!(Pair::new(-3, 0), Pair::new(2, 3) - Pair::new(5, 3));
}
#[test]
fn test_mul() {
assert_eq!(Pair::new(4, 6), Pair::new(2, 3) * 2);
}
#[test]
fn test_div() {
assert_eq!(Pair::new(2, 3), Pair::new(4, 6) / 2);
}
#[test]
fn test_rem() {
assert_eq!(Pair::new(1, 2), Pair::new(4, 5) % 3);
}
#[test]
fn test_add_assign() {
let mut p = Pair::new(2, 3);
p += Pair::new(4, 5);
assert_eq!(6, p.x);
assert_eq!(8, p.y);
}
#[test]
fn test_sub_assign() {
let mut p = Pair::new(2, 3);
p -= Pair::new(4, 6);
assert_eq!(-2, p.x);
assert_eq!(-3, p.y);
}
#[test]
fn test_mul_assign() {
let mut p = Pair::new(2, 3);
p *= 2;
assert_eq!(4, p.x);
assert_eq!(6, p.y);
}
#[test]
fn test_div_assign() {
let mut p = Pair::new(4, 6);
p /= 2;
assert_eq!(2, p.x);
assert_eq!(3, p.y);
}
#[test]
fn test_rem_assign() {
let mut p = Pair::new(4, 5);
p %= 3;
assert_eq!(1, p.x);
assert_eq!(2, p.y);
}
}
#[cfg(test)]
#[cfg(feature = "serde")]
mod tests_feature_serde {
use super::*;
#[test]
fn test_serialize() {
let p = Pair::new(1, 2);
let s = serde_json::to_string(&p).unwrap();
let expected = r#"{"x":1,"y":2}"#;
assert_eq!(expected, &s);
}
#[test]
fn test_deserialize() {
let s = r#"{"x":1,"y":2}"#;
let p = serde_json::from_str(s).unwrap();
assert_eq!(Pair::new(1, 2), p);
}
}
#[cfg(test)]
#[cfg(feature = "num-traits")]
mod tests_feature_num_traits {
use super::*;
#[test]
fn test_norm() {
let p = Pair::new(2.0, 3.0);
assert_eq!(13.0, p.norm());
}
#[test]
fn test_len() {
let p = Pair::new(3.0, 4.0);
assert_eq!(5.0, p.len());
}
#[test]
fn test_normalize() {
let p = Pair::new(3.0, 4.0);
let n = p.normalize();
assert_eq!(n, Pair::new(0.6, 0.8));
assert_eq!(1.0, n.norm());
}
}