From fbb3b639798b1c32c3a704ac6b646b015196f736 Mon Sep 17 00:00:00 2001 From: Kyle Carow Date: Fri, 7 Aug 2026 00:47:00 -0600 Subject: [PATCH] Close docs gaps from #22: custom-strategy grid access, example naming - Warn against .as_slice() on strategy grid data (panics on non-contiguous storage, reachable via Interp*Viewed) and point to strategy::utils::locate_lower_index as the ready-made bracket search, in both the custom_strategy.rs example and the Strategy*D::interpolate trait docs. - Rename examples/dynamic_strategy.rs and dynamic_interpolator.rs to swap_strategy.rs / swap_interpolator.rs, since "dynamic" overloads with "dyn" dispatch even though the examples also cover the non-dyn enum swapping approach. Updates all cross-references (README, enum module docs). --- README.md | 4 ++-- examples/custom_strategy.rs | 5 +++++ ...c_interpolator.rs => swap_interpolator.rs} | 0 .../{dynamic_strategy.rs => swap_strategy.rs} | 0 src/interpolator/enums.rs | 2 +- src/strategy/enums/mod.rs | 2 +- src/strategy/traits.rs | 20 +++++++++++++++++++ 7 files changed, 29 insertions(+), 4 deletions(-) rename examples/{dynamic_interpolator.rs => swap_interpolator.rs} (100%) rename examples/{dynamic_strategy.rs => swap_strategy.rs} (100%) diff --git a/README.md b/README.md index 925e551..09f5054 100644 --- a/README.md +++ b/README.md @@ -286,10 +286,10 @@ See examples in `new` method documentation: - [`InterpND::new`](https://docs.rs/ninterp/latest/ninterp/interpolator/struct.InterpND.html#method.new) Also see the [`examples`](https://github.com/NatLabRockies/ninterp/tree/main/examples) directory for advanced examples: -- Swapping strategies at runtime: [`dynamic_strategy.rs`](https://github.com/NatLabRockies/ninterp/blob/main/examples/dynamic_strategy.rs) +- Swapping strategies at runtime: [`swap_strategy.rs`](https://github.com/NatLabRockies/ninterp/blob/main/examples/swap_strategy.rs) - Strategy enums (`strategy::enums::Strategy1DEnum`/etc.): `serde`-compatible, custom strategies not supported - `Box`/etc. (dynamic dispatch): custom strategies supported, not `serde`-compatible, runtime cost -- Swapping interpolators at runtime: [`dynamic_interpolator.rs`](https://github.com/NatLabRockies/ninterp/blob/main/examples/dynamic_interpolator.rs) +- Swapping interpolators at runtime: [`swap_interpolator.rs`](https://github.com/NatLabRockies/ninterp/blob/main/examples/swap_interpolator.rs) - `InterpolatorEnum`: `serde`-compatible, custom strategies not supported - `Box` (dynamic dispatch): custom strategies supported, not `serde`-compatible, runtime cost - Defining custom strategies: [`custom_strategy.rs`](https://github.com/NatLabRockies/ninterp/blob/main/examples/custom_strategy.rs) diff --git a/examples/custom_strategy.rs b/examples/custom_strategy.rs index c9bdb54..88703df 100644 --- a/examples/custom_strategy.rs +++ b/examples/custom_strategy.rs @@ -19,6 +19,11 @@ where // e.g. `Array2`, `ArrayView2`, `CowArray<<'a, f32>, Ix2>`, etc. // For a more generic bound, consider introducing a bound for D::Elem // e.g. D::Elem: num_traits::Num + PartialOrd + // + // Note: when reading grid coordinates in `interpolate`, index `data.grid[i]` directly + // via ArrayView indexing (e.g. `data.grid[i][idx]`), not `.as_slice()`, which panics + // on non-contiguous storage. `Interp*Viewed` can produce that from a strided slice. + // For a bracket-search helper, see `ninterp::strategy::utils::locate_lower_index`. D: Data + RawDataClone + Clone, { // We can optionally define an initialization step, useful for strategies that need precalculation. diff --git a/examples/dynamic_interpolator.rs b/examples/swap_interpolator.rs similarity index 100% rename from examples/dynamic_interpolator.rs rename to examples/swap_interpolator.rs diff --git a/examples/dynamic_strategy.rs b/examples/swap_strategy.rs similarity index 100% rename from examples/dynamic_strategy.rs rename to examples/swap_strategy.rs diff --git a/src/interpolator/enums.rs b/src/interpolator/enums.rs index da69716..f964dfd 100644 --- a/src/interpolator/enums.rs +++ b/src/interpolator/enums.rs @@ -60,7 +60,7 @@ use strategy::enums::*; /// interp = InterpolatorEnum::new_0d(0.5); /// assert_eq!(interp.interpolate(&[]).unwrap(), 0.5); /// ``` -/// See also: `examples/dynamic_interpolator.rs` +/// See also: `examples/swap_interpolator.rs` #[allow(missing_docs)] #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] diff --git a/src/strategy/enums/mod.rs b/src/strategy/enums/mod.rs index 6abd76c..1289c67 100644 --- a/src/strategy/enums/mod.rs +++ b/src/strategy/enums/mod.rs @@ -41,7 +41,7 @@ //! assert_eq!(interp.interpolate(&[3.75]).unwrap(), 0.8); //! assert_eq!(interp.interpolate(&[4.00]).unwrap(), 1.0); //! ``` -//! See also: `examples/dynamic_strategy.rs` +//! See also: `examples/swap_strategy.rs` // NOTE: `enum_dispatch` does essentially what this module does, but with less boilerplate. // However, it does not currently support using a generic trait on a non-generic enum. diff --git a/src/strategy/traits.rs b/src/strategy/traits.rs index 35eeefa..66393ee 100644 --- a/src/strategy/traits.rs +++ b/src/strategy/traits.rs @@ -14,6 +14,11 @@ where } /// Execute interpolation (after handling [`Extrapolate`](`crate::interpolator::Extrapolate`) setting). + /// + /// # Note for custom strategies + /// Index `data.grid[i]` directly via `ArrayView` indexing; avoid `.as_slice()`, which + /// panics on non-contiguous storage (possible with `Interp*Viewed`). See + /// [`crate::strategy::utils::locate_lower_index`] for a ready-made bracket search. fn interpolate( &self, data: &InterpData1D, @@ -64,6 +69,11 @@ where } /// Execute interpolation (after handling [`Extrapolate`](`crate::interpolator::Extrapolate`) setting). + /// + /// # Note for custom strategies + /// Index `data.grid[i]` directly via `ArrayView` indexing; avoid `.as_slice()`, which + /// panics on non-contiguous storage (possible with `Interp*Viewed`). See + /// [`crate::strategy::utils::locate_lower_index`] for a ready-made bracket search. fn interpolate( &self, data: &InterpData2D, @@ -114,6 +124,11 @@ where } /// Execute interpolation (after handling [`Extrapolate`](`crate::interpolator::Extrapolate`) setting). + /// + /// # Note for custom strategies + /// Index `data.grid[i]` directly via `ArrayView` indexing; avoid `.as_slice()`, which + /// panics on non-contiguous storage (possible with `Interp*Viewed`). See + /// [`crate::strategy::utils::locate_lower_index`] for a ready-made bracket search. fn interpolate( &self, data: &InterpData3D, @@ -164,6 +179,11 @@ where } /// Execute interpolation (after handling [`Extrapolate`](`crate::interpolator::Extrapolate`) setting). + /// + /// # Note for custom strategies + /// Index `data.grid[i]` directly via `ArrayView` indexing; avoid `.as_slice()`, which + /// panics on non-contiguous storage (possible with `Interp*Viewed`). See + /// [`crate::strategy::utils::locate_lower_index`] for a ready-made bracket search. fn interpolate( &self, data: &InterpDataND,