#![deny(missing_docs)]
#![deny(unsafe_code)]
use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait Pair {
type Item;
fn first(self) -> Self::Item;
fn second(self) -> Self::Item;
fn from_items(a: Self::Item, b: Self::Item) -> Self;
}
impl<T> Pair for (T, T)
where
T: Clone,
{
type Item = T;
fn first(self) -> Self::Item {
self.0.clone()
}
fn second(self) -> Self::Item {
self.1.clone()
}
fn from_items(a: Self::Item, b: Self::Item) -> Self {
(a, b)
}
}
impl<T> Pair for [T; 2]
where
T: Clone,
{
type Item = T;
fn first(self) -> Self::Item {
self[0].clone()
}
fn second(self) -> Self::Item {
self[1].clone()
}
fn from_items(a: Self::Item, b: Self::Item) -> Self {
[a, b]
}
}
impl<T> Pair for (T, T, T, T)
where
T: Clone,
{
type Item = (T, T);
fn first(self) -> Self::Item {
(self.0.clone(), self.1.clone())
}
fn second(self) -> Self::Item {
(self.2.clone(), self.3.clone())
}
fn from_items(a: Self::Item, b: Self::Item) -> Self {
(a.0, a.1, b.0, b.1)
}
}
impl<T> Pair for [T; 4]
where
T: Clone,
{
type Item = [T; 2];
fn first(self) -> Self::Item {
[self[0].clone(), self[1].clone()]
}
fn second(self) -> Self::Item {
[self[2].clone(), self[3].clone()]
}
fn from_items(a: Self::Item, b: Self::Item) -> Self {
[a[0].clone(), a[1].clone(), b[0].clone(), b[1].clone()]
}
}
pub trait Sin {
type Output;
fn sin(self) -> Self::Output;
}
impl Sin for f32 {
type Output = f32;
fn sin(self) -> Self::Output {
f32::sin(self)
}
}
impl Sin for f64 {
type Output = f64;
fn sin(self) -> Self::Output {
f64::sin(self)
}
}
pub trait Cos {
type Output;
fn cos(self) -> Self::Output;
}
impl Cos for f32 {
type Output = f32;
fn cos(self) -> Self::Output {
f32::cos(self)
}
}
impl Cos for f64 {
type Output = f64;
fn cos(self) -> Self::Output {
f64::cos(self)
}
}
pub trait Pow<P> {
type Output;
fn pow(self, power: P) -> Self::Output;
}
macro_rules! pow_float_impl {
($type:ty) => {
impl Pow<Self> for $type {
type Output = Self;
fn pow(self, power: Self) -> Self::Output {
self.powf(power)
}
}
};
}
pow_float_impl! {f32}
pow_float_impl! {f64}
pub trait ZeroOneTwo: Copy {
const ZERO: Self;
const ONE: Self;
const TWO: Self;
}
macro_rules! zot_int_impl {
($type:ty) => {
impl ZeroOneTwo for $type {
const ZERO: Self = 0;
const ONE: Self = 1;
const TWO: Self = 2;
}
};
}
zot_int_impl! {u8}
zot_int_impl! {u16}
zot_int_impl! {u32}
zot_int_impl! {u64}
zot_int_impl! {u128}
zot_int_impl! {usize}
zot_int_impl! {i8}
zot_int_impl! {i16}
zot_int_impl! {i32}
zot_int_impl! {i64}
zot_int_impl! {i128}
zot_int_impl! {isize}
macro_rules! zot_float_impl {
($type:ty) => {
impl ZeroOneTwo for $type {
const ZERO: Self = 0.0;
const ONE: Self = 1.0;
const TWO: Self = 2.0;
}
};
}
zot_float_impl! {f32}
zot_float_impl! {f64}
pub trait Scalar:
Add<Self, Output = Self>
+ Copy
+ PartialEq
+ PartialOrd
+ Sub<Self, Output = Self>
+ Mul<Self, Output = Self>
+ Div<Self, Output = Self>
+ ZeroOneTwo
{
fn max(self, other: Self) -> Self {
if self > other {
self
} else {
other
}
}
fn min(self, other: Self) -> Self {
if self < other {
self
} else {
other
}
}
}
impl<T> Scalar for T where
T: Copy
+ PartialEq
+ PartialOrd
+ Add<T, Output = T>
+ Sub<T, Output = T>
+ Mul<T, Output = T>
+ Div<T, Output = T>
+ ZeroOneTwo
{
}
pub trait NegScalar: Scalar + Neg<Output = Self> {
fn abs(self) -> Self;
}
impl<T> NegScalar for T
where
T: Scalar + Neg<Output = Self>,
{
fn abs(self) -> Self {
if self >= Self::ZERO {
self
} else {
self.neg()
}
}
}
pub trait FloatingScalar:
NegScalar + Pow<Self, Output = Self> + Sin<Output = Self> + Cos<Output = Self>
{
}
impl<T> FloatingScalar for T where
T: NegScalar + Pow<Self, Output = Self> + Sin<Output = T> + Cos<Output = T>
{
}
pub trait Vector2: Copy {
type Scalar: Scalar;
fn x(self) -> Self::Scalar;
fn y(self) -> Self::Scalar;
fn new(x: Self::Scalar, y: Self::Scalar) -> Self;
fn square(s: Self::Scalar) -> Self {
Self::new(s, s)
}
fn map<V>(self) -> V
where
V: Vector2,
V::Scalar: From<Self::Scalar>,
{
V::new(V::Scalar::from(self.x()), V::Scalar::from(self.y()))
}
fn map_with<V, F>(self, mut f: F) -> V
where
V: Vector2,
F: FnMut(Self::Scalar) -> V::Scalar,
{
V::new(f(self.x()), f(self.y()))
}
fn add<V>(self, other: V) -> Self
where
V: Vector2<Scalar = Self::Scalar>,
{
Self::new(self.x() + other.x(), self.y() + other.y())
}
fn sub<V>(self, other: V) -> Self
where
V: Vector2<Scalar = Self::Scalar>,
{
Self::new(self.x() - other.x(), self.y() - other.y())
}
fn mul(self, by: Self::Scalar) -> Self {
Self::new(self.x() * by, self.y() * by)
}
fn mul2<V>(self, other: V) -> Self
where
V: Vector2<Scalar = Self::Scalar>,
{
Self::new(self.x() * other.x(), self.y() * other.y())
}
fn div(self, by: Self::Scalar) -> Self {
Self::new(self.x() / by, self.y() / by)
}
fn div2<V>(self, other: V) -> Self
where
V: Vector2<Scalar = Self::Scalar>,
{
Self::new(self.x() / other.x(), self.y() / other.y())
}
}
impl<P> Vector2 for P
where
P: Pair + Copy,
P::Item: Scalar,
{
type Scalar = P::Item;
fn x(self) -> P::Item {
self.first()
}
fn y(self) -> P::Item {
self.second()
}
fn new(x: P::Item, y: P::Item) -> Self {
Self::from_items(x, y)
}
}
pub trait NegVector2: Vector2
where
Self::Scalar: NegScalar,
{
fn neg(self) -> Self {
Self::new(-self.x(), -self.y())
}
fn max_dim(self) -> Self::Scalar {
if self.x().abs() > self.y().abs() {
self.x()
} else {
self.y()
}
}
}
impl<T> NegVector2 for T
where
T: Vector2,
T::Scalar: NegScalar,
{
}
pub trait FloatingVector2: Vector2
where
Self::Scalar: FloatingScalar,
{
fn dist<V>(self, to: V) -> Self::Scalar
where
V: Vector2<Scalar = Self::Scalar>,
{
((self.x() - to.x()).pow(Self::Scalar::TWO) + (self.y() - to.y()).pow(Self::Scalar::TWO))
.pow(Self::Scalar::ONE / Self::Scalar::TWO)
}
fn mag(self) -> Self::Scalar {
(self.x().pow(Self::Scalar::TWO) + self.y().pow(Self::Scalar::TWO))
.pow(Self::Scalar::ONE / Self::Scalar::TWO)
}
fn rotate_about<V>(self, pivot: V, radians: Self::Scalar) -> Self
where
V: Vector2<Scalar = Self::Scalar> + Clone,
{
let sin = radians.sin();
let cos = radians.cos();
let origin_point = self.sub(pivot);
let rotated_point = Self::new(
origin_point.x() * cos - origin_point.y() * sin,
origin_point.x() * sin + origin_point.y() * cos,
);
rotated_point.add(pivot)
}
}
impl<T> FloatingVector2 for T
where
T: Vector2,
T::Scalar: FloatingScalar,
{
}
pub trait Rectangle: Copy {
type Scalar: Scalar;
type Vector: Vector2<Scalar = Self::Scalar>;
fn new(top_left: Self::Vector, size: Self::Vector) -> Self;
fn top_left(self) -> Self::Vector;
fn size(self) -> Self::Vector;
fn square(top_left: Self::Vector, side_length: Self::Scalar) -> Self {
Self::new(top_left, Self::Vector::square(side_length))
}
fn centered(center: Self::Vector, size: Self::Vector) -> Self {
Self::new(center.sub(size.div(Self::Scalar::TWO)), size)
}
fn map<R>(self) -> R
where
R: Rectangle,
R::Scalar: From<Self::Scalar>,
{
R::new(
R::Vector::new(R::Scalar::from(self.left()), R::Scalar::from(self.top())),
R::Vector::new(
R::Scalar::from(self.width()),
R::Scalar::from(self.height()),
),
)
}
fn map_with<R, F>(self, mut f: F) -> R
where
R: Rectangle,
F: FnMut(Self::Scalar) -> <<R as Rectangle>::Vector as Vector2>::Scalar,
{
R::new(
R::Vector::new(f(self.left()), f(self.top())),
R::Vector::new(f(self.width()), f(self.height())),
)
}
fn top_right(self) -> Self::Vector {
Self::Vector::new(self.top_left().x() + self.size().x(), self.top_left().y())
}
fn bottom_left(self) -> Self::Vector {
Self::Vector::new(self.top_left().x(), self.top_left().y() + self.size().y())
}
fn bottom_right(self) -> Self::Vector {
self.top_left().add(self.size())
}
fn top(self) -> Self::Scalar {
self.top_left().y()
}
fn bottom(self) -> Self::Scalar {
self.top_left().y() + self.size().y()
}
fn left(self) -> Self::Scalar {
self.top_left().x()
}
fn right(self) -> Self::Scalar {
self.top_left().x() + self.size().x()
}
fn width(self) -> Self::Scalar {
self.size().x()
}
fn height(self) -> Self::Scalar {
self.size().y()
}
fn center(self) -> Self::Vector {
self.top_left().add(self.size().div(Self::Scalar::TWO))
}
fn with_top_left(self, top_left: Self::Vector) -> Self {
Self::new(top_left, self.size())
}
fn with_size(self, size: Self::Vector) -> Self {
Self::new(self.top_left(), size)
}
fn perimeter(self) -> Self::Scalar {
self.width() * Self::Scalar::TWO + self.height() * Self::Scalar::TWO
}
fn area(self) -> Self::Scalar {
self.width() * self.height()
}
fn translated(self, offset: Self::Vector) -> Self {
self.with_top_left(self.top_left().add(offset))
}
fn scaled(self, scale: Self::Scalar) -> Self {
self.with_size(self.size().mul(scale))
}
fn scaled2(self, scale: Self::Vector) -> Self {
self.with_size(self.size().mul2(scale))
}
}
impl<P> Rectangle for P
where
P: Pair + Copy,
P::Item: Vector2,
{
type Scalar = <P::Item as Vector2>::Scalar;
type Vector = P::Item;
fn new(top_left: Self::Vector, size: Self::Vector) -> Self {
Self::from_items(top_left, size)
}
fn top_left(self) -> Self::Vector {
self.first()
}
fn size(self) -> Self::Vector {
self.second()
}
}