Skip to content

Commit e893d33

Browse files
authored
refactor(slice-safety): enforce deny(clippy::indexing_slicing) with scoped escapes (#341) (#378)
- Lift `#[deny(clippy::indexing_slicing)]` crate-wide in `src/lib.rs`. Tests stay permissive via `#![cfg_attr(test, allow(..))]` — unit / integration tests routinely index into just-pushed buffers and are not expected to migrate. - Migrate the highest-risk unchecked indexing in production code to `.get(..).ok_or_else(..)` returning typed errors: `OptionChain` file-name parsing and CSV row reads in `src/chains/chain.rs`, and the binomial-root lookup in `Option::binomial_price` in `src/model/option.rs`. - Remaining call sites carry a scoped `#![allow(clippy::indexing_slicing)]` at the top of each affected module with a one-paragraph migration note. They are tracked as per-module follow-ups to #341 so that the deny-level lint can be rolled out without a massive, risky single PR. Closes #341 (slice-safety floor; per-module migration continues).
1 parent 48c1652 commit e893d33

45 files changed

Lines changed: 359 additions & 28 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/chains/chain.rs

Lines changed: 94 additions & 26 deletions
Large diffs are not rendered by default.

src/curves/curve.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
Email: jb@taunais.com
44
Date: 9/1/25
55
******************************************************************************/
6+
// Scoped allow: bulk migration of unchecked `[]` indexing to
7+
// `.get().ok_or_else(..)` tracked as follow-ups to #341. The existing
8+
// call sites are internal to this file and audited for invariant-bound
9+
// indices (fixed-length buffers, just-pushed slices, etc.).
10+
#![allow(clippy::indexing_slicing)]
11+
612
use crate::curves::Point2D;
713
use crate::curves::traits::StatisticalCurve;
814
use crate::curves::utils::detect_peaks_and_valleys;

src/curves/traits.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
Email: jb@taunais.com
44
Date: 23/2/25
55
******************************************************************************/
6+
// Scoped allow: bulk migration of unchecked `[]` indexing to
7+
// `.get().ok_or_else(..)` tracked as follow-ups to #341. The existing
8+
// call sites are internal to this file and audited for invariant-bound
9+
// indices (fixed-length buffers, just-pushed slices, etc.).
10+
#![allow(clippy::indexing_slicing)]
11+
612
use crate::curves::{Curve, Point2D};
713
use crate::error::{CurveError, OperationErrorKind};
814
use crate::geometrics::{BasicMetrics, MetricsExtractor, RangeMetrics, ShapeMetrics, TrendMetrics};

src/curves/utils.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
Email: jb@taunais.com
44
Date: 9/1/25
55
******************************************************************************/
6+
// Scoped allow: bulk migration of unchecked `[]` indexing to
7+
// `.get().ok_or_else(..)` tracked as follow-ups to #341. The existing
8+
// call sites are internal to this file and audited for invariant-bound
9+
// indices (fixed-length buffers, just-pushed slices, etc.).
10+
#![allow(clippy::indexing_slicing)]
11+
612
use crate::curves::{Curve, Point2D};
713
use crate::geometrics::GeometricObject;
814
use rust_decimal::Decimal;

src/geometrics/interpolation/traits.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
// Scoped allow: bulk migration of unchecked `[]` indexing to
2+
// `.get().ok_or_else(..)` tracked as follow-ups to #341. The existing
3+
// call sites are internal to this file and audited for invariant-bound
4+
// indices (fixed-length buffers, just-pushed slices, etc.).
5+
#![allow(clippy::indexing_slicing)]
6+
17
use crate::error::InterpolationError;
28
use crate::geometrics::{
39
BiLinearInterpolation, CubicInterpolation, GeometricObject, InterpolationType,

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
#![allow(unknown_lints)]
22
#![allow(clippy::literal_string_with_formatting_args)]
3+
// Per rules/global_rules.md §Error Handling, unchecked `[]` / slicing is
4+
// banned in production code. Enforced crate-wide; individual modules that
5+
// need a transitional escape hatch carry a scoped `#![allow(..)]` with a
6+
// migration note (tracked as follow-ups to #341).
7+
#![deny(clippy::indexing_slicing)]
8+
// Unit and integration tests routinely index into `Vec`s they just pushed
9+
// into, so the lint is silenced in `#[cfg(test)]` only.
10+
#![cfg_attr(test, allow(clippy::indexing_slicing))]
311

412
//! # OptionStratLib v0.16.0: Financial Options Library
513
//!

src/model/option.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,16 @@ impl Options {
384384
side: &self.side,
385385
};
386386
let (asset_tree, option_tree) = generate_binomial_tree(&params)?;
387+
let root = option_tree
388+
.first()
389+
.and_then(|row| row.first())
390+
.copied()
391+
.ok_or(PricingError::BinomialNodeMissing {
392+
node: "option[0][0]",
393+
})?;
387394
let price = match self.side {
388-
Side::Long => option_tree[0][0],
389-
Side::Short => -option_tree[0][0],
395+
Side::Long => root,
396+
Side::Short => -root,
390397
};
391398
Ok((price, asset_tree, option_tree))
392399
}

src/pricing/binomial_model.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
// Scoped allow: bulk migration of unchecked `[]` indexing to
2+
// `.get().ok_or_else(..)` tracked as follow-ups to #341. The existing
3+
// call sites are internal to this file and audited for invariant-bound
4+
// indices (fixed-length buffers, just-pushed slices, etc.).
5+
#![allow(clippy::indexing_slicing)]
6+
17
use crate::error::PricingError;
28
use crate::model::types::{OptionStyle, OptionType, Side};
39
use crate::pricing::payoff::{Payoff, PayoffInfo};

src/pricing/cliquet.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
Date: 13/01/26
55
******************************************************************************/
66

7+
// Scoped allow: bulk migration of unchecked `[]` indexing to
8+
// `.get().ok_or_else(..)` tracked as follow-ups to #341. The existing
9+
// call sites are internal to this file and audited for invariant-bound
10+
// indices (fixed-length buffers, just-pushed slices, etc.).
11+
#![allow(clippy::indexing_slicing)]
12+
713
//! Cliquet option pricing module.
814
//!
915
//! Cliquet options (also known as ratchet options) consist of a series of

src/pricing/compound.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
Date: 13/01/26
55
******************************************************************************/
66

7+
// Scoped allow: bulk migration of unchecked `[]` indexing to
8+
// `.get().ok_or_else(..)` tracked as follow-ups to #341. The existing
9+
// call sites are internal to this file and audited for invariant-bound
10+
// indices (fixed-length buffers, just-pushed slices, etc.).
11+
#![allow(clippy::indexing_slicing)]
12+
713
//! Compound option pricing module.
814
//!
915
//! Compound options are options on options (also called split-fee options).

0 commit comments

Comments
 (0)