Expand description
The whole point of the crate
Think of this as an array with convenience methods for accessing values if it’s dimensions are
within 1..=4, i.e - all methods implemented for arrays are available with this
Making a Point
// Creating a 2D point from a given array
let arr: [i32; 2] = [0,1];
let p: PointND<_, 2> = PointND::new(arr);
// Creating a 3D point from values of a given slice
let vec: Vec<i32> = vec![0, 1, 2];
let p: PointND<_, 3> = PointND::from(&vec);
// Creating a 4D point with all values set to 5
let p: PointND<i32, 4> = PointND::fill(5);
// The second generic arg is a usize constant and for the ::fill()
// and ::from() functions, specifying it is sometimes necessary
// If you don't like writing PointND twice for type annotation,
// use FQS (fully qualified syntax) instead:
let p = PointND::<_, 4>::fill(5);
// Trying to create a PointND with zero dimensions using the above will panic at runtime
// ERROR: Can't create a point with zero dimensions
// let p: PointND<_, 0> = PointND::new([]);Getting and Setting Values
If the dimensions of the point are within 1..=4, it is recommended to use the convenience getters and setters
let arr = [0,1];
let p: PointND<_, 2> = PointND::new(arr);
// As the point has 2 dimensions, we can access
// it's values with the x() and y() methods
let x: &i32 = p.x();
assert_eq!(*x, arr[0]);
let y = p.y();
assert_eq!(*y, arr[1]);
// If the point had 3 dimensions, we could use the above and:
// let z = p.z();
// Or with 4 dimensions, the above and:
// let w = p.w();
// Setting values is just as simple
let mut p = PointND::new(arr);
p.set_x(101);
assert_eq!(*p.x(), 101);
// As with the getters, there are respective methods for setting the
// values at y, z and w depending on the dimensions of the pointAlternatively, since PointND implements Deref, all methods of getting and setting array elements can work as well
These are the only methods available for PointND’s with dimensions not within 1..=4
Their use can be made easier using the dimension macros: dim, dims and dimr (see their documentation for more info)
// A 5D point, cannot use any of the convenience methods
let arr = [-2, -1, 0, 1, 2];
let mut p = PointND::new(arr);
// ERROR: Not implemented for PointND<i32, 5>
// let x = p.x()
// ...
// let w = p.w();
// Instead use these deref array methods:
// Safely getting
let x: Option<&i32> = p.get(0);
assert_eq!(*x.unwrap(), arr[0]);
// Indexing
let y: i32 = p[1];
assert_eq!(y, arr[1]);
// Slicing
let z_to_last: &[i32] = &p[2..];
assert_eq!(z_to_last, [0,1,2]);
// Setting via Indexing
p[1] = 345;
assert_eq!(p[1], 345);Querying Size
The number of dimensions can be retrieved using the dims() method (short for dimensions)
let p: PointND<i32, 2> = PointND::new([0,1]);
assert_eq!(p.dims(), 2);
// Alternatively, as PointND implements Deref, we can use len().
// It's name isn't as descriptive however
assert_eq!(p.len(), 2);Iterating
Iterating over a PointND is as easy as:
let mut p = PointND::new([0,1]);
for _ in p.iter() { /* Do stuff */ }
for _ in p.iter_mut() { /* Change stuff */ }
for _ in p.into_iter() { /* Do more stuff */ }It must be noted that due to the Copy trait bounds of the items contained by a PointND,
using into_iter() will not actually move the point as we are actually iterating over the contained
array via the Deref trait.
// The point 'p' is still usable after the call to into_iter()
assert_eq!(p.dims(), 2);If destroying innocent points is your thing however, using into_arr() or into_vec() to
consume the point before iterating will move it out of scope
for _ in p.into_vec().into_iter() { /* Do stuff */ }
// ERROR: Can't access moved value
// assert_eq!(p.dims(), 2);Transforming Points
Appliers
The apply, apply_vals, apply_dims and apply_point (henceforth referred to as appliers)
methods all consume self and return a new point after applying a function to all contained values
Multiple appliers can be chained together to make complex transformations to a PointND
This is probably best explained with an example:
// A trivial transformation more easily done via other methods...
// but it gets the point across
let p = PointND
::new([0,1,2]) // Creates a new PointND
.apply(|item| Ok( item + 2 ))? // Adds 2 to each item
.apply(|item| Ok( item * 3 ))?; // Multiplies each item by 3
assert_eq!(p.into_arr(), [6, 9, 12]);Creating a Function to Pass to Appliers
The function or closure passed to the applier methods (henceforth referred to as modifiers)
accept either one or two args of type T (where T is the type of the items contained
by the point) depending on whether one or two sets of values are being modified.
Modifiers must all return a Result<T, ()> to allow graceful error handling by the applier instead of just panicking.
If an Err is returned by the modifier when called on any item, the applier returns an Err(())
If all goes well, the applier returns an Ok with the new PointND as it’s value
Hopefully the above wasn’t confusing, but here’s an example just in case:
// Dividing by zero causes a runtime error, so we return an Err if the second arg is zero
let divide_items = |a: f32, b: f32| -> Result<f32, ()> {
if b == 0.0 {
Err(())
} else {
Ok( a / b )
}
};
let p1 = PointND::new([-1.2, 2.0, -3.0, 4.5]);
let p2 = PointND::new([2.3, 9.0, -3.0, 1.0]);
let zero_point = PointND::fill(0.0);
// Divides each item in p1 with each in p2
let result = p1.clone().apply_point(p2, divide_items);
// No zeros in p2, so everything's Ok
assert!(result.is_ok());
// Divides each item in p1 with each in zero_point
let result = p1.apply_point(zero_point, divide_items);
// Error is thrown by divide_items, causing apply_point() to throw error
assert!(result.is_err());Implementations
sourceimpl<T, const N: usize> PointND<T, N> where
T: Clone + Copy + Default,
impl<T, const N: usize> PointND<T, N> where
T: Clone + Copy + Default,
sourcepub fn new(arr: [T; N]) -> Self
pub fn new(arr: [T; N]) -> Self
Returns a new PointND with values from the specified array
This is the only constructor that does not ever need type annotation
Panics
If the length of the array is zero
sourcepub fn from(slice: &[T]) -> Self
pub fn from(slice: &[T]) -> Self
Returns a new PointND with values from the specified slice
This constructor is probably only useful when Vec’s of unknown length are
the only collections available
If the compiler is not able to infer the dimensions (a.k.a - length) of the point, it needs to be explicitly specified
// Explicitly specifying dimensions
let p = PointND::<_, 3>::from(&vec![0,1,2]);
// The generics don't always have to be specified though, for example
let p1 = PointND::new([0,1]); // Compiler knows this has 2 dimensions
let p2 = PointND::from(&vec![2,3]);
// Later, p2 is added to p1. The compiler is able to infer its dimensions
let p = p1 + p2;Panics
If the length of the slice is zero
If the slice passed cannot be converted into an array
sourcepub fn fill(value: T) -> Self
pub fn fill(value: T) -> Self
Returns a new PointND with all values set as specified
If the compiler is not able to infer the dimensions (a.k.a - length) of the point, it needs to be explicitly specified
See the from() function for cases when generics don’t need to be explicitly specified
// A point with 10 dimensions with all values set to 2
let p = PointND::<_, 10>::fill(2);
assert_eq!(p.dims(), 10);
for i in p.into_iter() {
assert_eq!(i, 2);
}Panics
If the dimensions of the point being constructed is zero
sourcepub fn dims(&self) -> usize
pub fn dims(&self) -> usize
Returns the number of dimensions of the point (a 2D point will return 2, a 3D point 3, etc)
Equivalent to calling len()
sourcepub fn set(&mut self, i: usize, new_val: T) -> Result<(), ()>
pub fn set(&mut self, i: usize, new_val: T) -> Result<(), ()>
Safe method of setting values
Sets value at index i to new_val and returns Ok. If the index specified was out of range, does nothing and returns Err
This is probably only useful if dealing with PointND’s of differing dimensions at once
let mut p = PointND::new([0,1]);
// Setting an item within bounds, returns Ok
let result = p.set(0, 21);
assert!(result.is_ok());
// Setting an item out of bounds, returns Err
let result = p.set(1000000, 4);
assert!(result.is_err());sourcepub fn apply<F>(self, modifier: F) -> Result<Self, ()> where
F: Fn(T) -> Result<T, ()>,
pub fn apply<F>(self, modifier: F) -> Result<Self, ()> where
F: Fn(T) -> Result<T, ()>,
Consumes self and calls the modifier on each item contained by self to create a new PointND
let p = PointND
::new([0,1,2]) // Creates a new PointND
.apply(|item| Ok( item + 2 ))? // Adds 2 to each item
.apply(|item| Ok( item * 3 ))?; // Multiplies each item by 3
assert_eq!(p.into_arr(), [6, 9, 12]);sourcepub fn apply_dims<F>(self, dims: &[usize], modifier: F) -> Result<Self, ()> where
F: Fn(T) -> Result<T, ()>,
pub fn apply_dims<F>(self, dims: &[usize], modifier: F) -> Result<Self, ()> where
F: Fn(T) -> Result<T, ()>,
Consumes self and calls the modifier on the items at the specified dims to create a new PointND
Any items at dimensions not specified will be passed to the new point as is
let p = PointND
::new([0,1,2,3]) // Creates a new PointND
.apply_dims(&[1,3], |item| Ok( item * 2 ))? // Multiplies items 1 and 3 by 2
.apply_dims(&[0,2], |item| Ok( item + 10 ))?; // Adds 10 to items 0 and 2
assert_eq!(p.into_arr(), [10, 2, 20, 6]);sourcepub fn apply_vals<F>(self, values: [T; N], modifier: F) -> Result<Self, ()> where
F: Fn(T, T) -> Result<T, ()>,
pub fn apply_vals<F>(self, values: [T; N], modifier: F) -> Result<Self, ()> where
F: Fn(T, T) -> Result<T, ()>,
Consumes self and calls the modifier on each item contained
by self and values to create a new PointND
When creating a modifier function to be used by this method, keep in mind that the items in
self are passed to it through the first arg, and the items in value through the second
let p = PointND
::new([0,1,2]) // Creates a new PointND
.apply_vals([1,3,5], |a, b| Ok( a + b ))? // Adds items in point to items in array
.apply_vals([2,4,6], |a, b| Ok( a * b ))?; // Multiplies items in point
// to items in array
assert_eq!(p.into_arr(), [2, 16, 42]);sourcepub fn apply_point<F>(self, other: Self, modifier: F) -> Result<Self, ()> where
F: Fn(T, T) -> Result<T, ()>,
pub fn apply_point<F>(self, other: Self, modifier: F) -> Result<Self, ()> where
F: Fn(T, T) -> Result<T, ()>,
Consumes self and calls the modifier on each item contained by self and another PointND to create a new point
When creating a modifier function to be used by this method, keep in mind that the items in
self are passed to it through the first arg, and the items in other through the second
let p1 = PointND::new([0,9,3,1]);
let p2 = PointND::fill(10);
let p3 = PointND
::new([1,2,3,4]) // Creates a new PointND
.apply_point(p1, |a, b| Ok ( a - b ))? // Subtracts items in p3 with those in p1
.apply_point(p2, |a, b| Ok ( a * b ))?; // Multiplies items in the returned point
// with the items in p2
assert_eq!(p3.into_arr(), [10, -70, 0, 30]);sourceimpl<T> PointND<T, 1> where
T: Clone + Copy + Default,
impl<T> PointND<T, 1> where
T: Clone + Copy + Default,
1D
Functions for safely getting and setting the value contained by a 1D PointND
sourceimpl<T> PointND<T, 2> where
T: Clone + Copy + Default,
impl<T> PointND<T, 2> where
T: Clone + Copy + Default,
2D
Functions for safely getting and setting the values contained by a 2D PointND
sourceimpl<T> PointND<T, 3> where
T: Clone + Copy + Default,
impl<T> PointND<T, 3> where
T: Clone + Copy + Default,
3D
Functions for safely getting and setting the values contained by a 3D PointND
Trait Implementations
sourceimpl<T, const N: usize> Add<PointND<T, N>> for PointND<T, N> where
T: Add<Output = T> + Clone + Copy + Default,
impl<T, const N: usize> Add<PointND<T, N>> for PointND<T, N> where
T: Add<Output = T> + Clone + Copy + Default,
sourceimpl<T, const N: usize> AddAssign<PointND<T, N>> for PointND<T, N> where
T: AddAssign + Clone + Copy + Default,
impl<T, const N: usize> AddAssign<PointND<T, N>> for PointND<T, N> where
T: AddAssign + Clone + Copy + Default,
sourcefn add_assign(&mut self, rhs: Self)
fn add_assign(&mut self, rhs: Self)
Performs the += operation. Read more
sourceimpl<T, const N: usize> Div<PointND<T, N>> for PointND<T, N> where
T: Div<Output = T> + Clone + Copy + Default,
impl<T, const N: usize> Div<PointND<T, N>> for PointND<T, N> where
T: Div<Output = T> + Clone + Copy + Default,
Warning
Dividing by a PointND that contains a zero will cause a panic
sourceimpl<T, const N: usize> DivAssign<PointND<T, N>> for PointND<T, N> where
T: DivAssign + Clone + Copy + Default,
impl<T, const N: usize> DivAssign<PointND<T, N>> for PointND<T, N> where
T: DivAssign + Clone + Copy + Default,
Warning
Dividing by a PointND that contains a zero will cause a panic
sourcefn div_assign(&mut self, rhs: Self)
fn div_assign(&mut self, rhs: Self)
Performs the /= operation. Read more
sourceimpl<T, const N: usize> Mul<PointND<T, N>> for PointND<T, N> where
T: Mul<Output = T> + Clone + Copy + Default,
impl<T, const N: usize> Mul<PointND<T, N>> for PointND<T, N> where
T: Mul<Output = T> + Clone + Copy + Default,
sourceimpl<T, const N: usize> MulAssign<PointND<T, N>> for PointND<T, N> where
T: MulAssign + Clone + Copy + Default,
impl<T, const N: usize> MulAssign<PointND<T, N>> for PointND<T, N> where
T: MulAssign + Clone + Copy + Default,
sourcefn mul_assign(&mut self, rhs: Self)
fn mul_assign(&mut self, rhs: Self)
Performs the *= operation. Read more
sourceimpl<T, const N: usize> Neg for PointND<T, N> where
T: Clone + Copy + Default + Neg<Output = T>,
impl<T, const N: usize> Neg for PointND<T, N> where
T: Clone + Copy + Default + Neg<Output = T>,
sourceimpl<T: PartialEq, const N: usize> PartialEq<PointND<T, N>> for PointND<T, N> where
T: Clone + Copy + Default,
impl<T: PartialEq, const N: usize> PartialEq<PointND<T, N>> for PointND<T, N> where
T: Clone + Copy + Default,
sourceimpl<T, const N: usize> Sub<PointND<T, N>> for PointND<T, N> where
T: Sub<Output = T> + Clone + Copy + Default,
impl<T, const N: usize> Sub<PointND<T, N>> for PointND<T, N> where
T: Sub<Output = T> + Clone + Copy + Default,
sourceimpl<T, const N: usize> SubAssign<PointND<T, N>> for PointND<T, N> where
T: SubAssign + Clone + Copy + Default,
impl<T, const N: usize> SubAssign<PointND<T, N>> for PointND<T, N> where
T: SubAssign + Clone + Copy + Default,
sourcefn sub_assign(&mut self, rhs: Self)
fn sub_assign(&mut self, rhs: Self)
Performs the -= operation. Read more
impl<T: Eq, const N: usize> Eq for PointND<T, N> where
T: Clone + Copy + Default,
impl<T, const N: usize> StructuralEq for PointND<T, N> where
T: Clone + Copy + Default,
impl<T, const N: usize> StructuralPartialEq for PointND<T, N> where
T: Clone + Copy + Default,
Auto Trait Implementations
impl<T, const N: usize> RefUnwindSafe for PointND<T, N> where
T: RefUnwindSafe,
impl<T, const N: usize> Send for PointND<T, N> where
T: Send,
impl<T, const N: usize> Sync for PointND<T, N> where
T: Sync,
impl<T, const N: usize> Unpin for PointND<T, N> where
T: Unpin,
impl<T, const N: usize> UnwindSafe for PointND<T, N> where
T: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
sourceimpl<T> ToOwned for T where
T: Clone,
impl<T> ToOwned for T where
T: Clone,
type Owned = T
type Owned = T
The resulting type after obtaining ownership.
sourcefn clone_into(&self, target: &mut T)
fn clone_into(&self, target: &mut T)
toowned_clone_into)Uses borrowed data to replace owned data, usually by cloning. Read more