So for a library I am writing, I want to calculate the distance between two points in N dimensions (2, 3, 4, etc...) and I have a Point trait so that user's of the library can use this function on their own types, so long as they are "point like".
I have a trait, "Point", which has the dimensions (N) and floating point type (T) kept as an associated type and constant:
pub trait Point: Copy + Clone {
type T: num::Float;
const N: usize;
fn as_array(&self) -> [Self::T; Self::N];
}
and the function that uses it:
fn dist<P>(a: &P, b: &P) -> P::T
where
P: Point,
[(); P::N]: ,
{
// implementation goes here ...
}
An example of the Point trait being used as intended:
#[derive(Copy, Clone)]
struct MyCustomPoint { a: f64, b: f64 }
impl Point for MyCustomPoint {
type T = f64;
const N: usize = 2;
fn as_array(&self) -> [Self::T; Self::N] {
[self.a, self.b]
}
}
The problem
If I implement the Point trait for [f32;N], I get the following issue:
error[E0308]: mismatched types
--> src\main.rs:63:9
|
63 | *self
| ^^^^^ expected `Self::N`, found `N`
|
= note: expected type `Self::N`
found type `N`
The code which causes the problem:
impl<const N: usize> Point for [f32; N] {
type T = f32;
const N: usize = N;
fn as_array(&self) -> [Self::T; Self::N] {
*self
}
}
Why does the code below cause a mismatched types error, when using a number in the code works fine?
impl Point for [f32; 3] {
type T = f32;
const N: usize = 3;
fn as_array(&self) -> [Self::T; Self::N] {
*self
}
}
All the code put together in one block:
#![feature(adt_const_params)]
#![feature(generic_const_exprs)]
use num::Float;
pub trait Point: Copy + Clone {
type T: num::Float;
const N: usize;
fn as_array(&self) -> [Self::T; Self::N];
}
fn dist<P>(a: &P, b: &P) -> P::T
where
P: Point,
[(); P::N]: ,
{
let mut dist_sq: P::T = num::zero();
for i in 0..P::N {
let delta = (a.as_array())[i] - (b.as_array())[i];
dist_sq = dist_sq + delta * delta;
}
dist_sq.sqrt()
}
// Works
#[derive(Copy, Clone)]
struct MyCustomPoint { a: f64, b: f64 }
impl Point for MyCustomPoint {
type T = f64;
const N: usize = 2;
fn as_array(&self) -> [Self::T; Self::N] {
[self.a, self.b]
}
}
// Works
// impl Point for [f32; 3] {
// type T = f32;
// const N: usize = 3;
// fn as_array(&self) -> [Self::T; Self::N] {
// *self
// }
// }
// Doesn't work
impl<const N: usize> Point for [f32; N] {
type T = f32;
const N: usize = N;
fn as_array(&self) -> [Self::T; Self::N] {
*self
}
}
fn main() {
let a = [0f32, 1f32, 0f32];
let b = [3f32, 1f32, 4f32];
assert_eq!(dist(&a, &b), 5f32);
}
Also, I've discovered that the following is a workaround.
fn as_array(&self) -> [Self::T; Self::N] {
// *self
// Workaround - replace with something simpler if possible.
let mut array = [0f64; Self::N];
array[..Self::N].copy_from_slice(&self[..Self::N]);
array
}