macro_rules! create_pair {
(
$doc:literal, $dname:literal,
$tname:ident, $ftype:ty, $n0:ident, $n1:ident
$(, [$c_mname:ident, $c_m0:ident, $c_m1:ident] )*
$(, ($x_name:ident, $x_method:ident, $x_field:tt) )*
) => {
#[doc = $doc]
#[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct $tname(pub $ftype, pub $ftype);
impl $tname {
paste::paste! {
$(
create_pair![new: $tname, $c_mname, $ftype, $c_m0, $c_m1];
)*
}
}
impl $tname {
paste::paste! {
create_pair![get: $dname, $n0, $n0, $ftype, 0];
create_pair![get: $dname, $n1, $n1, $ftype, 1];
create_pair![set: $dname, $n0, $n0, $ftype, 0];
create_pair![set: $dname, $n1, $n1, $ftype, 1];
$(
create_pair![get: $dname, $x_name, $x_method, $ftype, $x_field];
create_pair![set: $dname, $x_name, $x_method, $ftype, $x_field];
)*
}
pub fn swap(self) -> Self {
Self(self.1, self.0)
}
pub fn set_swap(&mut self) {
std::mem::swap(&mut self.0, &mut self.1)
}
}
impl std::fmt::Display for $tname {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{},{}", self.0, self.1)
}
}
impl std::fmt::Debug for $tname {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}({})", stringify![$tname], self)
}
}
};
(new: $tname:ident, $method:ident, $ftype:ty, $n0:ident, $n1:ident) => {
paste::paste! {
#[doc = "Returns a new `" $tname "`." ]
pub fn $method($n0: $ftype, $n1: $ftype) -> $tname {
Self($n0, $n1)
}
}
};
(get: $dname: literal, $name: ident, $method:ident, $ftype:ty, $field:tt) => {
paste::paste! {
#[doc = "Gets the `" $name "` " $dname "." ]
pub fn $method(&self) -> $ftype {
self.$field
}
}
};
(set: $dname: literal, $name: ident, $method:ident, $ftype:ty, $field:tt) => {
paste::paste! {
#[doc = "Sets the `" $name "` " $dname "" ]
pub fn [< set_ $method >](&mut self, $name: $ftype) {
self.$field = $name
}
}
};
}
macro_rules! impl_ops {
(pair_all_ops: $for: ty, $rhs:ty, =$result:ty, $ftype:ty) => {
impl_ops![pair_op: Add, add, $for, $rhs, =$result, $ftype];
impl_ops![pair_op: Sub, sub, $for, $rhs, =$result, $ftype];
impl_ops![pair_op: Mul, mul, $for, $rhs, =$result, $ftype];
impl_ops![pair_op: Div, div, $for, $rhs, =$result, $ftype];
impl_ops![pair_opa: AddAssign, add, $for, $rhs, $ftype];
impl_ops![pair_opa: SubAssign, sub, $for, $rhs, $ftype];
impl_ops![pair_opa: MulAssign, mul, $for, $rhs, $ftype];
impl_ops![pair_opa: DivAssign, div, $for, $rhs, $ftype];
};
(pair_op: $op:tt, $fn:ident, $for: ty, $rhs:ty, =$result:ty, $ftype:ty) => {
impl core::ops::$op<$rhs> for $for {
type Output = $result;
fn $fn(self, rhs: $rhs) -> Self::Output {
use az::SaturatingAs;
paste::paste! {
<$result>::new(
self.0.[< saturating_ $fn >](rhs.0.saturating_as::<$ftype>()),
self.1.[< saturating_ $fn >](rhs.1.saturating_as::<$ftype>()),
)
}
}
}
};
(pair_opa: $op:tt, $fn:ident, $for:ty, $rhs:ty, $ftype:ty) => {
impl core::ops::$op<$rhs> for $for {
paste::paste! {
fn [< $fn _assign >](&mut self, rhs: $rhs) {
use az::SaturatingAs;
<$for>::new(
self.0.[< saturating_ $fn >](rhs.0.saturating_as::<$ftype>()),
self.1.[< saturating_ $fn >](rhs.1.saturating_as::<$ftype>()),
);
}
}
}
};
(pair_all_ops_ints: $for: ty, =$result:ty, $ftype:ty) => {
impl_ops![pair_op_ints: Add, add, $for, =$result, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
impl_ops![pair_op_ints: Sub, sub, $for, =$result, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
impl_ops![pair_op_ints: Mul, mul, $for, =$result, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
impl_ops![pair_op_ints: Div, div, $for, =$result, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
impl_ops![pair_opa_ints: AddAssign, add, $for, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
impl_ops![pair_opa_ints: SubAssign, sub, $for, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
impl_ops![pair_opa_ints: MulAssign, mul, $for, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
impl_ops![pair_opa_ints: DivAssign, div, $for, $ftype,
[i8, i16, i32, i64, isize, u8, u16, u32, u64, usize]];
};
(pair_op_ints: $op:tt, $fn:ident, $for: ty, =$result:ty, $ftype:ty, [$($int:ty),+]) => {
$(
impl_ops![pair_op_int: $op, $fn, $for, $int, =$result, $ftype];
)+
};
(pair_op_int: $op:tt, $fn:ident, $for: ty, $rhs_int:ty, =$result:ty, $ftype:ty) => {
impl core::ops::$op<$rhs_int> for $for {
type Output = $result;
fn $fn(self, rhs: $rhs_int) -> Self::Output {
use az::SaturatingAs;
paste::paste! {
<$result>::new(
self.0.[< saturating_ $fn >](rhs.saturating_as::<$ftype>()),
self.1.[< saturating_ $fn >](rhs.saturating_as::<$ftype>()),
)
}
}
}
};
(pair_opa_ints: $op:tt, $fn:ident, $for: ty, $ftype:ty, [$($int:ty),+]) => {
$(
impl_ops![pair_opa_int: $op, $fn, $for, $int, $ftype];
)+
};
(pair_opa_int: $op:tt, $fn:ident, $for:ty, $rhs_int:ty, $ftype:ty) => {
impl core::ops::$op<$rhs_int> for $for {
paste::paste! {
fn [< $fn _assign >](&mut self, rhs: $rhs_int) {
use az::SaturatingAs;
<$for>::new(
self.0.[< saturating_ $fn >](rhs.saturating_as::<$ftype>()),
self.1.[< saturating_ $fn >](rhs.saturating_as::<$ftype>()),
);
}
}
}
};
}
macro_rules! impl_from_tuple_array {
($pair:ident, $pair_type:ty, list: $( $element:ty ),+ ) => {
$(
impl_from_tuple_array![$pair, $pair_type, $element];
)+
};
($pair:ident, $pair_type:ty, $element:ty) => {
impl From<($element, $element)> for $pair {
fn from(tuple: ($element, $element)) -> $pair {
use az::SaturatingAs;
<$pair>::new(tuple.0.saturating_as::<$pair_type>(), tuple.1.saturating_as::<$pair_type>())
}
}
impl From<$pair> for ($element, $element) {
fn from(pair: $pair) -> ($element, $element) {
use az::SaturatingAs;
(pair.0.saturating_as::<$element>(), pair.1.saturating_as::<$element>())
}
}
impl From<[$element; 2]> for $pair {
fn from(array: [$element; 2]) -> $pair {
use az::SaturatingAs;
<$pair>::new(array[0].saturating_as::<$pair_type>(), array[1].saturating_as::<$pair_type>())
}
}
impl From<$pair> for [$element; 2] {
fn from(pair: $pair) -> [$element; 2] {
use az::SaturatingAs;
[pair.0.saturating_as::<$element>(), pair.1.saturating_as::<$element>()]
}
}
}
}
macro_rules! impl_methods {
($pair:ty, $ftype:ty) => {
impl $pair {
#[inline]
pub const fn into_tuple(&self) -> ($ftype, $ftype) {
(self.0, self.1)
}
pub const fn into_array(&self) -> [$ftype; 2] {
[self.0, self.1]
}
}
};
}
create_pair![
"A pair of positive lengths.\n\n`(x, y)` | `(width, height)` | `(horizontal, vertical)`.",
"dimension",
Size,
u32,
width,
height,
[new, horizontal, vertical],
[new_wh, width, height],
[new_width_height, width, height],
(width, w, 0),
(height, h, 1),
(width, x, 0),
(height, y, 1),
(width, c, 0),
(width, cols, 0),
(width, columns, 0),
(height, r, 1),
(height, rows, 1),
(horizontal, horizontal, 0),
(vertical, vertical, 1)
];
impl_ops![pair_all_ops: Size, Size, =Size, u32];
impl_ops![pair_all_ops: Size, Position, =Size, u32]; impl_ops![pair_all_ops_ints: Size, =Size, u32];
#[rustfmt::skip]
impl_from_tuple_array![Size, u32, list: u8, u16, u32, u64, usize, i8, i16, i32, i64, isize];
impl_methods![Size, u32];
create_pair![
"A pair of coordinates.\n\n`(x, y)` | `(column, row)` | `(horizontal, vertical)`.",
"coordinate",
Position,
i32,
x,
y,
[new, horizontal, vertical],
[from_xy, x, y],
[from_col_row, column, row],
[from_column_row, column, row],
(column, c, 0),
(column, col, 0),
(column, column, 0),
(row, r, 1),
(row, row, 1),
(horizontal, horizontal, 0),
(vertical, vertical, 1)
];
impl_ops![pair_all_ops: Position, Position, =Position, i32];
impl_ops![pair_all_ops: Position, Size, =Position, i32]; impl_ops![pair_all_ops_ints: Position, =Position, i32];
#[rustfmt::skip]
impl_from_tuple_array![Position, i32, list: u8, u16, u32, usize, i8, i16, i32, i64, isize];
impl_methods![Position, i32];