use crate::compute_method::{
math::{Array, Float, FloatVector},
storage::{ParticleReordered, PointMass},
ComputeMethod,
};
use std::vec::IntoIter;
pub trait Particle {
type Array: Array;
fn position(&self) -> Self::Array;
fn mu(&self) -> <Self::Array as Array>::Item;
}
pub trait ScalarArray: Array + From<Self::Vector> + Into<Self::Vector> {
type Vector: FloatVector<Float = Self::Item>;
}
macro_rules! impl_scalar_array {
([$scalar: ty; $dim: literal], $vector: ty) => {
impl ScalarArray for [$scalar; $dim] {
type Vector = $vector;
}
};
}
impl_scalar_array!([f32; 2], ultraviolet::Vec2);
impl_scalar_array!([f32; 3], ultraviolet::Vec3);
impl_scalar_array!([f32; 4], ultraviolet::Vec4);
impl_scalar_array!([f64; 2], ultraviolet::DVec2);
impl_scalar_array!([f64; 3], ultraviolet::DVec3);
impl_scalar_array!([f64; 4], ultraviolet::DVec4);
pub type ParticleArray<P> = <P as Particle>::Array;
pub type ParticleVector<P> = <<P as Particle>::Array as ScalarArray>::Vector;
pub type ParticleScalar<P> = <<P as Particle>::Array as Array>::Item;
pub trait IntoPointMass: Particle + Sized {
#[inline]
fn point_mass(&self) -> PointMass<ParticleVector<Self>, ParticleScalar<Self>>
where
Self::Array: ScalarArray,
{
PointMass::new(self.position().into(), self.mu())
}
}
impl<P: Particle> IntoPointMass for P {}
pub trait ReorderedCompute<P>:
for<'a> ComputeMethod<
&'a ParticleReordered<'a, ParticleVector<P>, ParticleScalar<P>>,
Output = Vec<ParticleVector<P>>,
>
where
P: Particle,
P::Array: ScalarArray,
{
}
impl<C, P> ReorderedCompute<P> for C
where
P: Particle,
P::Array: ScalarArray,
for<'a> C: ComputeMethod<
&'a ParticleReordered<'a, ParticleVector<P>, ParticleScalar<P>>,
Output = Vec<ParticleVector<P>>,
>,
{
}
pub trait Accelerations: Iterator + Sized
where
Self::Item: Particle,
{
#[inline]
fn accelerations<C>(self, cm: &mut C) -> IntoIter<ParticleArray<Self::Item>>
where
C: ReorderedCompute<Self::Item>,
ParticleScalar<Self::Item>: Float,
ParticleArray<Self::Item>: ScalarArray,
{
#[inline]
fn scalar_to_array<A>(vec: Vec<A::Vector>) -> Vec<A>
where
A: ScalarArray,
{
vec.into_iter().map(A::from).collect()
}
let collection = self.map(|p| p.point_mass()).collect::<Vec<_>>();
scalar_to_array(cm.compute(&ParticleReordered::from(&*collection))).into_iter()
}
}
impl<I: Iterator> Accelerations for I where I::Item: Particle {}
impl<P: Particle> Particle for &P {
type Array = P::Array;
#[inline]
fn position(&self) -> Self::Array {
(**self).position()
}
#[inline]
fn mu(&self) -> <Self::Array as Array>::Item {
(**self).mu()
}
}
impl<P: Particle> Particle for &mut P {
type Array = P::Array;
#[inline]
fn position(&self) -> Self::Array {
(**self).position()
}
#[inline]
fn mu(&self) -> <Self::Array as Array>::Item {
(**self).mu()
}
}
impl<const D: usize, S: Clone> Particle for ([S; D], S) {
type Array = [S; D];
#[inline]
fn position(&self) -> Self::Array {
self.0.clone()
}
#[inline]
fn mu(&self) -> <Self::Array as Array>::Item {
self.1.clone()
}
}