PointND

Struct PointND 

Source
pub struct PointND<T, const N: usize>(/* private fields */);
Expand description

The whole point of the crate.

The PointND struct is really just a smart pointer to an array of type [T; N] with convenience methods for accessing, setting and transforming values.

As the struct dereferences to a slice, all methods implemented for slices are available with this.

§Making a Point

There are three PointND constructors (in order of usefulness): from(), fill() and from_slice().

The from_slice() and fill() functions can only be used if creating a point where the items implement Copy

// Creating a 2D point from a given array
let arr = [0, 1];
let p = PointND::from(arr);

// Creating a 4D point with all values set to 5
let p: PointND<_, 4> = PointND::fill(5);

// Creating a 3D point from values of a given slice
let p: PointND<_, 3> = PointND::from_slice(&vec![0, 1, 2]);

// You can even construct a PointND with zero dimensions
let arr: [i32; 0] = [];
let p = PointND::from(arr);

The generic arg N in PointND<T, N> is a usize constant generic and for the fill() and from_slice() functions, specifying it is sometimes needed when the compiler cannot infer it itself.

See their documentation for cases when explicit generics are not necessary

Otherwise, if you don’t like writing PointND twice for type annotation, it is recommended to use FQS (fully qualified syntax) instead:

let p1 = PointND::<_, 4>::from_slice(&vec![5,5,5,5]);
let p2 = PointND::<_, 4>::fill(5);

assert_eq!(p1, p2);

§Getting Values

If the dimensions of the point are within 1..=4, it is recommended to use the convenience getters x(), y(), z() and w()

The above all return references to the value, regardless of whether they implement Copy

let p = PointND::from([0,1]);

// As the point has 2 dimensions, we can access
//  it's values with the x() and y() methods
let x: &i32 = p.x();
let y = p.y();
assert_eq!(*x, 0);
assert_eq!(*y, 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();

The above methods are not implemented for PointND’s with more than 4 dimensions.

Instead, we must use the native implementations of the contained array. See the notes below on how direct indexing can be made easier.

let p = PointND::from([0,1,2,3,4,5]);

// ERROR: Not implemented for PointND of 6 dimensions
//  let x = p.x();

let x = p[0];
let y = p.get(1);
let z_to_last = &p[2..];

assert_eq!(x, 0);
assert_eq!(*y.unwrap(), 1);
assert_eq!(z_to_last, &[2, 3, 4, 5]);

To get all the values contained by a point, use the into_arr() method

let p = PointND::from([-10, -2, 0, 2, 10]);
assert_eq!(p.into_arr(), [-10, -2, 0, 2, 10])

§Querying Size

The number of dimensions can be retrieved using the dims() method (short for dimensions).

let p = PointND::from([0,1]);
assert_eq!(p.dims(), 2);

// Alternatively, as PointND implements Deref, we can use len().
// It's not as descriptive however...
assert_eq!(p.len(), 2);

§Transforming Values

If the dimensions of the point are within 1..=4, it is recommended to use the convenience set and shift methods.

let mut p = PointND::from([0, 1]);

// As the point has 2 dimensions, we can set
//  it's values with the set_x() and set_y() methods
// There are set_z() and set_w() methods available for
//  points with 3 and 4 dimensions respectively
p.set_x(-10);
p.set_y(-20);
assert_eq!(*p.x(), -10);
assert_eq!(*p.y(), -20);

// We can AddAssign the values of a point with the
//  shift methods
// Like set, there are methods available for points
//  of 3 and 4 dimensions
p.shift_x(5);
p.shift_y(25);
assert_eq!(*p.x(), -5);
assert_eq!(*p.y(), 5);

The above methods are not implemented for PointND’s with more than 4 dimensions.

Instead, we must use the native implementations of the contained array. See the notes below on how direct indexing can be made easier.

let mut p = PointND::from([0, 1, 2, 3, 4, 5]);

// Sets x via indexing
p[0] = -100;
assert_eq!(p[0], -100);

§Appliers

The apply(), apply_vals(), apply_dims() and apply_point() methods all consume self and return a new point after calling a function or closure on all contained values

Multiple applier methods 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 other ways
//  ...but it gets the point across
let p = PointND
    ::from([0,1,2])            // Creates a new PointND
    .apply(|item| item + 2)    // Adds 2 to each item
    .apply(|item| item * 3);   // Multiplies each item by 3
assert_eq!(p.into_arr(), [6, 9, 12]);

Each applier has it’s own subtle differences, it is recommended to read the documentation for each of them

§Iterating

Iterating over a PointND is as easy as:

let mut p = PointND::from([0,1]);

for _ in p.iter()      { /* Do stuff     */ }
for _ in p.iter_mut()  { /* Change stuff */ }
for _ in p.into_iter() { /* Move stuff (unless items implement Copy) */ }

It must be noted that if the items implement Copy, using into_iter() will not actually move the point out of scope.

If this behaviour is necessary, use the into_arr() method to consume the point and move the contained array into the loop

for _ in p.into_arr().into_iter() { /* Move stuff */ }

// ERROR: Can't access moved value
// assert_eq!(p.dims(), 2);

§Things (not strictly necessary) to Note

§Convenience Methods

As stated earlier, certain methods for accessing and setting the values contained by a PointND are only implemented for points within 1..=4 dimensions.

This was done to mirror the behaviour of arrays closely as possible, where out of bounds indexing errors are caught at compile time.

§Direct Indexing

Indexing values can become cumbersome if using usize values. As of v0.5.0, point-nd’s indexing macros have been moved to the axmac crate which provides macros to index the first 4 dimensions of a point by simply specifying x, y, z or w.

The axmac crate is highly recommended when working with points above 4 dimensions

§Math Operations

Unlike structures in other crates, PointND’s (as of v0.5.0) do not implement mutating and consuming math operations like Neg, Add, SubAssign, etc.

It was decided that these functionalities and others could provided by independent crates via functions which could be imported and passed to the apply methods.

Eq and PartialEq are implemented though.

§Dimensional Capacity

This crate relies heavily on the arrayvec crate when applying transformations to points. Due to the fact that arrayvec::ArrayVec’s lengths are capped at u32::MAX, any apply, extend and retain methods will panic if used on PointND’s with dimensions exceeding that limit.

This shouldn’t be a problem in most use cases (who needs a u32::MAX + 1 dimensional point anyway?), but it is probably worth mentioning.

Implementations§

Source§

impl<T, const N: usize> PointND<T, N>
where T: Copy,

Source

pub fn from_slice(slice: &[T]) -> Self

Returns a new PointND with values from the specified slice

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_slice(&vec![0,1,2]);

// The generics don't always have to be specified though, for example
let p1 = PointND::from([0,1]);       // Compiler knows this has 2 dimensions
let p2 = PointND::from_slice(&vec![2,3]);

// Later, p2 is applied to p1. The compiler is able to infer its dimensions
let p3 = p1.apply_point(p2, |a, b| a + b);

If the length of the slice being passed is uncertain, it is recommended to use the try_from() method for more graceful error handling.

§Panics
  • If the slice passed cannot be converted into an array
let arr = [0,1,2];
// ERROR: Cannot convert slice of [i32; 3] to [i32; 100]
let p = PointND::<_, 100>::from_slice(&arr[..]);
Source

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_slice() function for cases when generics don’t need to be explicitly specified

// A 10 dimensional point with all values set to 2
let p = PointND::<_, 10>::fill(2);

assert_eq!(p.dims(), 10);
assert_eq!(p.into_arr(), [2; 10]);
Source§

impl<T, const N: usize> PointND<T, N>

Source

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()

Source

pub fn into_arr(self) -> [T; N]

Consumes self, returning the contained array

Source

pub fn apply<U>(self, modifier: ApplyFn<T, U>) -> PointND<U, N>

Consumes self and calls the modifier on each item contained by self to create a new PointND of the same length.

let p = PointND
    ::from([0,1,2])             // Creates a new PointND
    .apply(|item| item + 2)     // Adds 2 to each item
    .apply(|item| item * 3);    // Multiplies each item by 3
assert_eq!(p.into_arr(), [6, 9, 12]);

The return type of the modifier does not necessarily have to be the same as the type of the items passed to it. This means that apply can create a new point with items of a different type, but the same length.

let p = PointND
    ::from([0,1,2])                // Creates a new PointND
    .apply(|item| item as f32);    // Converts items to float
assert_eq!(p.into_arr(), [0.0, 1.0, 2.0]);
§Enabled by features:
  • default

  • appliers

§Panics
  • If the dimensions of self are greater than u32::MAX.
Source

pub fn apply_dims(self, dims: &[usize], modifier: ApplyDimsFn<T>) -> Self

Consumes self and calls the modifier on the items at the specified dims to create a new PointND of the same length.

Any items at dimensions not specified will be passed to the new point without change

let p = PointND
    ::from([0,1,2,3,4])                       // Creates a PointND
    .apply_dims(&[1,3], |item| item * 2)      // Multiplies items 1 and 3 by 2
    .apply_dims(&[0,2], |item| item + 10);    // Adds 10 to items 0 and 2
assert_eq!(p.into_arr(), [10, 2, 12, 6, 4]);

Unlike some other apply methods, this apply_dims cannot return a PointND with items of a different type from the original.

§Enabled by features:
  • default

  • appliers

§Panics
  • If the dimensions of self are greater than u32::MAX.
Source

pub fn apply_vals<U, V>( self, values: [V; N], modifier: ApplyValsFn<T, U, V>, ) -> PointND<U, N>

Consumes self and calls the modifier on each item contained by self and values to create a new PointND of the same length.

As this method may modify every value in the original point, the values array must be the same length as the 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 values through the second.

let p = PointND
    ::from([0,1,2])                      // Creates a new PointND
    .apply_vals([1,3,5], |a, b| a + b)   // Adds items in point to items in array
    .apply_vals([2,4,6], |a, b| a * b);  // Multiplies items in point to items in array
assert_eq!(p.into_arr(), [2, 16, 42]);

Neither the return type of the modifier nor the type of the items contained by the values array necessarily have to be the same as the item type of the original point. This means that apply_vals can create a new point with items of a different type, but the same length.

enum Op {
   Add,
   Sub,
}

// Adds or subtracts 10 from 'a' depending on the
//  operation specified in 'b', then converts to float
let add_or_sub = |a, b| {
   match b {
       Op::Add => (a + 10) as f32,
       Op::Sub => (a - 10) as f32
   }
};

let p = PointND
    ::from([0,1,2])
    .apply_vals(
        [Op::Add, Op::Sub, Op::Add],
        add_or_sub
    );
assert_eq!(p.into_arr(), [10.0, -9.0, 12.0]);
§Enabled by features:
  • default

  • appliers

§Panics
  • If the dimensions of self or values are greater than u32::MAX.
Source

pub fn apply_point<U, V>( self, other: PointND<V, N>, modifier: ApplyPointFn<T, U, V>, ) -> PointND<U, N>

Consumes self and calls the modifier on each item contained by self and another PointND to create a new point of the same length.

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::from([0,9,3,1]);
let p2 = PointND::fill(10);
let p3 = PointND
    ::from([1,2,3,4])                // Creates a new PointND
    .apply_point(p1, |a, b| a - b)   // Subtracts items in p3 with those in p1
    .apply_point(p2, |a, b| a * b);  // Multiplies items in p3 with those in p2
assert_eq!(p3.into_arr(), [10, -70, 0, 30]);

Neither the return type of the modifier nor the type of the items contained by the other point necessarily have to be the same as the type of the items in the original point. This means that apply_point can create a new point with items of a different type, but the same length.

§Enabled by features:
  • default

  • appliers

§Panics
  • If the dimensions of self or other are greater than u32::MAX.
Source§

impl<T> PointND<T, 1>

Methods for safely getting and setting the value contained by a 1D PointND

§Enabled by features:

  • default

  • conv_methods

  • x

Source

pub fn x(&self) -> &T

Source

pub fn set_x(&mut self, new_value: T)

Source§

impl<T> PointND<T, 2>

Methods for safely getting and setting the values contained by a 2D PointND

§Enabled by features:

  • default

  • conv_methods

  • y

Source

pub fn x(&self) -> &T

Source

pub fn y(&self) -> &T

Source

pub fn set_x(&mut self, new_value: T)

Source

pub fn set_y(&mut self, new_value: T)

Source§

impl<T> PointND<T, 3>

Methods for safely getting and setting the values contained by a 3D PointND

§Enabled by features:

  • default

  • conv_methods

  • z

Source

pub fn x(&self) -> &T

Source

pub fn y(&self) -> &T

Source

pub fn z(&self) -> &T

Source

pub fn set_x(&mut self, new_value: T)

Source

pub fn set_y(&mut self, new_value: T)

Source

pub fn set_z(&mut self, new_value: T)

Source§

impl<T> PointND<T, 4>

Methods for safely getting and setting the values contained by a 4D PointND

§Enabled by features:

  • default

  • conv_methods

  • w

Source

pub fn x(&self) -> &T

Source

pub fn y(&self) -> &T

Source

pub fn z(&self) -> &T

Source

pub fn w(&self) -> &T

Source

pub fn set_x(&mut self, new_value: T)

Source

pub fn set_y(&mut self, new_value: T)

Source

pub fn set_z(&mut self, new_value: T)

Source

pub fn set_w(&mut self, new_value: T)

Source§

impl<T> PointND<T, 1>
where T: AddAssign,

Method for safely transforming the value contained by a 1D PointND

§Enabled by features:

  • default

  • conv_methods

  • x

Source

pub fn shift_x(&mut self, delta: T)

Source§

impl<T> PointND<T, 2>
where T: AddAssign,

Methods for safely transforming the values contained by a 2D PointND

§Enabled by features:

  • default

  • conv_methods

  • y

Source

pub fn shift_x(&mut self, delta: T)

Source

pub fn shift_y(&mut self, delta: T)

Source§

impl<T> PointND<T, 3>
where T: AddAssign,

Methods for safely transforming the values contained by a 3D PointND

§Enabled by features:

  • default

  • conv_methods

  • z

Source

pub fn shift_x(&mut self, delta: T)

Source

pub fn shift_y(&mut self, delta: T)

Source

pub fn shift_z(&mut self, delta: T)

Source§

impl<T> PointND<T, 4>
where T: AddAssign,

Methods for safely transforming the values contained by a 4D PointND

§Enabled by features:

  • default

  • conv_methods

  • w

Source

pub fn shift_x(&mut self, delta: T)

Source

pub fn shift_y(&mut self, delta: T)

Source

pub fn shift_z(&mut self, delta: T)

Source

pub fn shift_w(&mut self, delta: T)

Methods from Deref<Target = [T; N]>§

1.57.0 · Source

pub fn as_slice(&self) -> &[T]

Returns a slice containing the entire array. Equivalent to &s[..].

1.57.0 · Source

pub fn as_mut_slice(&mut self) -> &mut [T]

Returns a mutable slice containing the entire array. Equivalent to &mut s[..].

1.77.0 · Source

pub fn each_ref(&self) -> [&T; N]

Borrows each element and returns an array of references with the same size as self.

§Example
let floats = [3.1, 2.7, -1.0];
let float_refs: [&f64; 3] = floats.each_ref();
assert_eq!(float_refs, [&3.1, &2.7, &-1.0]);

This method is particularly useful if combined with other methods, like map. This way, you can avoid moving the original array if its elements are not Copy.

let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()];
let is_ascii = strings.each_ref().map(|s| s.is_ascii());
assert_eq!(is_ascii, [true, false, true]);

// We can still access the original array: it has not been moved.
assert_eq!(strings.len(), 3);
1.77.0 · Source

pub fn each_mut(&mut self) -> [&mut T; N]

Borrows each element mutably and returns an array of mutable references with the same size as self.

§Example

let mut floats = [3.1, 2.7, -1.0];
let float_refs: [&mut f64; 3] = floats.each_mut();
*float_refs[0] = 0.0;
assert_eq!(float_refs, [&mut 0.0, &mut 2.7, &mut -1.0]);
assert_eq!(floats, [0.0, 2.7, -1.0]);
Source

pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T])

🔬This is a nightly-only experimental API. (split_array)

Divides one array reference into two at an index.

The first will contain all indices from [0, M) (excluding the index M itself) and the second will contain all indices from [M, N) (excluding the index N itself).

§Panics

Panics if M > N.

§Examples
#![feature(split_array)]

let v = [1, 2, 3, 4, 5, 6];

{
   let (left, right) = v.split_array_ref::<0>();
   assert_eq!(left, &[]);
   assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
}

{
    let (left, right) = v.split_array_ref::<2>();
    assert_eq!(left, &[1, 2]);
    assert_eq!(right, &[3, 4, 5, 6]);
}

{
    let (left, right) = v.split_array_ref::<6>();
    assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
    assert_eq!(right, &[]);
}
Source

pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T])

🔬This is a nightly-only experimental API. (split_array)

Divides one mutable array reference into two at an index.

The first will contain all indices from [0, M) (excluding the index M itself) and the second will contain all indices from [M, N) (excluding the index N itself).

§Panics

Panics if M > N.

§Examples
#![feature(split_array)]

let mut v = [1, 0, 3, 0, 5, 6];
let (left, right) = v.split_array_mut::<2>();
assert_eq!(left, &mut [1, 0][..]);
assert_eq!(right, &mut [3, 0, 5, 6]);
left[1] = 2;
right[1] = 4;
assert_eq!(v, [1, 2, 3, 4, 5, 6]);
Source

pub fn rsplit_array_ref<const M: usize>(&self) -> (&[T], &[T; M])

🔬This is a nightly-only experimental API. (split_array)

Divides one array reference into two at an index from the end.

The first will contain all indices from [0, N - M) (excluding the index N - M itself) and the second will contain all indices from [N - M, N) (excluding the index N itself).

§Panics

Panics if M > N.

§Examples
#![feature(split_array)]

let v = [1, 2, 3, 4, 5, 6];

{
   let (left, right) = v.rsplit_array_ref::<0>();
   assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
   assert_eq!(right, &[]);
}

{
    let (left, right) = v.rsplit_array_ref::<2>();
    assert_eq!(left, &[1, 2, 3, 4]);
    assert_eq!(right, &[5, 6]);
}

{
    let (left, right) = v.rsplit_array_ref::<6>();
    assert_eq!(left, &[]);
    assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
}
Source

pub fn rsplit_array_mut<const M: usize>(&mut self) -> (&mut [T], &mut [T; M])

🔬This is a nightly-only experimental API. (split_array)

Divides one mutable array reference into two at an index from the end.

The first will contain all indices from [0, N - M) (excluding the index N - M itself) and the second will contain all indices from [N - M, N) (excluding the index N itself).

§Panics

Panics if M > N.

§Examples
#![feature(split_array)]

let mut v = [1, 0, 3, 0, 5, 6];
let (left, right) = v.rsplit_array_mut::<4>();
assert_eq!(left, &mut [1, 0]);
assert_eq!(right, &mut [3, 0, 5, 6][..]);
left[1] = 2;
right[1] = 4;
assert_eq!(v, [1, 2, 3, 4, 5, 6]);

Trait Implementations§

Source§

impl<T: Clone, const N: usize> Clone for PointND<T, N>

Source§

fn clone(&self) -> PointND<T, N>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug, const N: usize> Debug for PointND<T, N>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T, const N: usize> Deref for PointND<T, N>

Source§

type Target = [T; N]

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<T, const N: usize> DerefMut for PointND<T, N>

Source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.
Source§

impl<T, const N: usize> From<[T; N]> for PointND<T, N>

Source§

fn from(array: [T; N]) -> Self

Converts to this type from the input type.
Source§

impl<T, const N: usize> From<PointND<T, N>> for [T; N]

Source§

fn from(point: PointND<T, N>) -> Self

Converts to this type from the input type.
Source§

impl<T: PartialEq, const N: usize> PartialEq for PointND<T, N>

Source§

fn eq(&self, other: &PointND<T, N>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T, const N: usize> TryFrom<&[T]> for PointND<T, N>
where T: Copy,

Source§

type Error = TryFromSliceError

The type returned in the event of a conversion error.
Source§

fn try_from(slice: &[T]) -> Result<Self, Self::Error>

Performs the conversion.
Source§

impl<T: Eq, const N: usize> Eq for PointND<T, N>

Source§

impl<T, const N: usize> StructuralPartialEq for PointND<T, N>

Auto Trait Implementations§

§

impl<T, const N: usize> Freeze for PointND<T, N>
where T: Freeze,

§

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§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.