pub struct PointND<T, const N: usize>(_)
where
    T: Clone + Copy + Default
;
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 point

Alternatively, 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

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

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

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

Returns the number of dimensions of the point (a 2D point will return 2, a 3D point 3, etc)

Equivalent to calling len()

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

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]);

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]);

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]);

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]);

Consumes self, returning the contained array

Consumes self, returning the contained array as a vector

1D

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

2D

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

3D

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

4D

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

Trait Implementations

The resulting type after applying the + operator.

Performs the + operation. Read more

Performs the += operation. Read more

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

The resulting type after dereferencing.

Dereferences the value.

Mutably dereferences the value.

Warning

Dividing by a PointND that contains a zero will cause a panic

The resulting type after applying the / operator.

Performs the / operation. Read more

Warning

Dividing by a PointND that contains a zero will cause a panic

Performs the /= operation. Read more

The resulting type after applying the * operator.

Performs the * operation. Read more

Performs the *= operation. Read more

The resulting type after applying the - operator.

Performs the unary - operation. Read more

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

The resulting type after applying the - operator.

Performs the - operation. Read more

Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

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

Uses borrowed data to replace owned data, usually by cloning. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.