Skip to main content

UniformAxis

Struct UniformAxis 

Source
pub struct UniformAxis<const N: usize, const ORIGIN: u16, const STEP: u16>(/* private fields */);
Expand description

An axis of N evenly spaced knots, described by ORIGIN and STEP rather than stored.

Knot i is ORIGIN + i * STEP, so the whole axis is ORIGIN, STEP, and N — all three in the type. The value is zero-sized: an evenly spaced axis costs no static bytes, adds nothing to the surface handle, and needs no knot array to walk or probe. Because the descriptor is a compile-time constant, the division that locates a cell is a division by a constant in every instantiation.

This is the one strategy that cannot describe an arbitrary axis. If the spacing is irregular, use BinaryAxis, or BucketedAxis when a smaller search bound is worth index bytes.

§Cost

No stored bytes, no index, and no strategy-specific knot comparison after the endpoint checks: one subtraction and one division locate the cell regardless of N.

§Examples

use ph_surfaces::{BilinearSurface, BinaryAxis, UniformAxis};

// Five knots at 0, 25, 50, 75, 100 — declared, not stored.
static Y: [u16; 2] = [0, 10];
static VALUES: [[i32; 5]; 2] = [[0, 25, 50, 75, 100], [10, 35, 60, 85, 110]];

static SURFACE: BilinearSurface<5, 2, UniformAxis<5, 0, 25>, BinaryAxis<2>> =
    BilinearSurface::from_axes(UniformAxis::new(), BinaryAxis::new(&Y), &VALUES);

assert_eq!(SURFACE.x_knot(3), 75);
assert_eq!(SURFACE.evaluate(60, 0), Ok(60));
assert_eq!(SURFACE.evaluate(100, 10), Ok(110));

The same surface with the knots spelled out and located binarily returns the same values:

use ph_surfaces::{BilinearSurface, BinaryAxis, UniformAxis};

static X: [u16; 5] = [0, 25, 50, 75, 100];
static Y: [u16; 2] = [0, 10];
static VALUES: [[i32; 5]; 2] = [[0, 25, 50, 75, 100], [10, 35, 60, 85, 110]];

static UNIFORM: BilinearSurface<5, 2, UniformAxis<5, 0, 25>, BinaryAxis<2>> =
    BilinearSurface::from_axes(UniformAxis::new(), BinaryAxis::new(&Y), &VALUES);
static STORED: BilinearSurface<5, 2> = BilinearSurface::new(&X, &Y, &VALUES);

for x in [0u16, 1, 37, 50, 99, 100] {
    assert_eq!(UNIFORM.evaluate(x, 5), STORED.evaluate(x, 5));
}

A single-knot axis does not compile:

use ph_surfaces::UniformAxis;

static AXIS: UniformAxis<1, 0, 25> = UniformAxis::new();

Nor does a zero step, which would declare N copies of one knot:

use ph_surfaces::UniformAxis;

static AXIS: UniformAxis<5, 0, 0> = UniformAxis::new();

Nor does a descriptor whose last knot leaves u16:

use ph_surfaces::UniformAxis;

static AXIS: UniformAxis<5, 60_000, 2_000> = UniformAxis::new();

The descriptor cannot bypass UniformAxis::new; its zero-sized field is private:

use ph_surfaces::UniformAxis;

static AXIS: UniformAxis<5, 0, 25> = UniformAxis(());

Implementations§

Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> UniformAxis<N, ORIGIN, STEP>

Source

pub const fn new() -> Self

Declares an evenly spaced axis.

§Panics

Panics unless the descriptor names at least two strictly increasing knots that are all representable: N >= 2, STEP >= 1, and N <= 65_536, and ORIGIN + (N - 1) * STEP <= u16::MAX. In a constant or static definition that panic is a compile error, so an unrepresentable axis cannot be declared.

Examples found in repository?
examples/uniform_sensor_compensation.rs (line 21)
20static SURFACE: Compensation =
21    BilinearSurface::from_axes(UniformAxis::new(), UniformAxis::new(), &VALUES);
More examples
Hide additional examples
examples/firmware_cost_budget.rs (line 64)
63    static SURFACE: UniformPair =
64        BilinearSurface::from_axes(UniformAxis::new(), UniformAxis::new(), &VALUES);
65
66    assert_eq!(SURFACE.evaluate(100, 200), Ok(0));
67    assert_eq!(SURFACE.x_knot(16), 1_600);
68    assert_eq!(SURFACE.y_knot(8), 1_600);
69
70    assert_eq!(UniformPair::VALUE_BYTES, 612);
71    assert_eq!(UniformPair::PAYLOAD_BYTES, 612);
72    assert_eq!(AllBinary::PAYLOAD_BYTES, 664);
73    assert_eq!(UniformPair::PAYLOAD_BYTES + 52, AllBinary::PAYLOAD_BYTES);
74    assert_eq!(<UniformAxis<17, 0, 100>>::KNOT_BYTES, 0);
75    assert_eq!(<UniformAxis<17, 0, 100>>::MAX_SEARCH_COMPARISONS, 0);
76    assert_eq!(<UniformAxis<9, 0, 200>>::MAX_SEARCH_COMPARISONS, 0);
77    assert_eq!(UniformPair::SUCCESS_INTERPOLATIONS, 3);
78    assert_eq!(UniformPair::SUCCESS_GRID_READS, 4);
79    assert_eq!(
80        UniformPair::HANDLE_BYTES,
81        core::mem::size_of::<UniformPair>()
82    );
83}
84
85fn mixed_bucketed_uniform_17x9() {
86    static X: [u16; 17] = [
87        0, 100, 210, 300, 405, 500, 610, 700, 805, 900, 1_010, 1_100, 1_205, 1_300, 1_410, 1_500,
88        1_600,
89    ];
90    static X_INDEX: [u16; 8] = bucket_index(&X);
91    static VALUES: [[i32; 17]; 9] = [[0; 17]; 9];
92
93    type Mixed = BilinearSurface<17, 9, BucketedAxis<17, 8>, UniformAxis<9, 0, 200>>;
94    type AllBinary = BilinearSurface<17, 9>;
95
96    static MIXED: Mixed =
97        BilinearSurface::from_axes(BucketedAxis::new(&X, &X_INDEX), UniformAxis::new(), &VALUES);
examples/mixed_calibration_map.rs (line 33)
31static MIXED: Mixed = BilinearSurface::from_axes(
32    BucketedAxis::new(&X, &X_INDEX_8),
33    UniformAxis::new(),
34    &VALUES,
35);
Source

pub const fn origin(&self) -> u16

Returns the first knot, ORIGIN.

The same value as AxisLookup::first, available in a constant context.

Source

pub const fn step(&self) -> u16

Returns the spacing between consecutive knots, STEP.

Source

pub const fn knot(&self, index: usize) -> u16

Returns the knot at index, computed from the descriptor.

The same value as AxisLookup::knot, available in a constant context.

§Panics

Panics if index >= N.

Source

pub const fn last(&self) -> u16

Returns the last knot, ORIGIN + (N - 1) * STEP.

The same value as AxisLookup::last, available in a constant context. inline(always) because the body folds to one constant; an outlined copy would be all call overhead.

Trait Implementations§

Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> AxisLookup<N> for UniformAxis<N, ORIGIN, STEP>

Source§

const KNOT_BYTES: usize = 0

Bytes of stored knots or descriptor this strategy references. Read more
Source§

const INDEX_BYTES: usize = 0

Bytes of auxiliary index this strategy references. Read more
Source§

const MAX_SEARCH_COMPARISONS: u32 = 0

The most strategy-specific knot comparisons needed to locate an in-domain coordinate, after the inclusive endpoint checks. Read more
Source§

fn first(&self) -> u16

Returns the first knot: the inclusive lower bound of the axis domain.
Source§

fn last(&self) -> u16

Returns the last knot: the inclusive upper bound of the axis domain.
Source§

fn knot(&self, index: usize) -> u16

Returns the knot at index. Read more
Source§

fn search(&self, coordinate: u16) -> (usize, u32)

Returns the greatest index whose knot is at or below coordinate, together with the number of knot comparisons it took. Read more
Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Clone for UniformAxis<N, ORIGIN, STEP>

Source§

fn clone(&self) -> UniformAxis<N, ORIGIN, STEP>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

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

Performs copy-assignment from source. Read more
Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Copy for UniformAxis<N, ORIGIN, STEP>

Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Debug for UniformAxis<N, ORIGIN, STEP>

Source§

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

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

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Default for UniformAxis<N, ORIGIN, STEP>

Source§

fn default() -> Self

Returns UniformAxis::new, validating the descriptor.

It is written out rather than derived on purpose: a derived Default would hand back an axis whose descriptor had never been checked, and the rest of the crate relies on every axis having been.

Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Eq for UniformAxis<N, ORIGIN, STEP>

Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Hash for UniformAxis<N, ORIGIN, STEP>

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> PartialEq for UniformAxis<N, ORIGIN, STEP>

Source§

fn eq(&self, other: &UniformAxis<N, ORIGIN, STEP>) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

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

Inequality operator !=. Read more
Source§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> StructuralPartialEq for UniformAxis<N, ORIGIN, STEP>

Auto Trait Implementations§

§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Freeze for UniformAxis<N, ORIGIN, STEP>

§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> RefUnwindSafe for UniformAxis<N, ORIGIN, STEP>

§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Send for UniformAxis<N, ORIGIN, STEP>

§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Sync for UniformAxis<N, ORIGIN, STEP>

§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> Unpin for UniformAxis<N, ORIGIN, STEP>

§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> UnsafeUnpin for UniformAxis<N, ORIGIN, STEP>

§

impl<const N: usize, const ORIGIN: u16, const STEP: u16> UnwindSafe for UniformAxis<N, ORIGIN, STEP>

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<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.