diff --git a/crates/nu-protocol/src/value/range.rs b/crates/nu-protocol/src/value/range.rs index 6ec7ce16ad..77aa5a60ef 100644 --- a/crates/nu-protocol/src/value/range.rs +++ b/crates/nu-protocol/src/value/range.rs @@ -95,20 +95,27 @@ mod int_range { pub fn contains(&self, value: i64) -> bool { if self.step < 0 { - value <= self.start - && match self.end { - Bound::Included(end) => value >= end, - Bound::Excluded(end) => value > end, - Bound::Unbounded => true, - } + // Decreasing range + if value > self.start { + return false; + } + match self.end { + Bound::Included(end) if value < end => return false, + Bound::Excluded(end) if value <= end => return false, + _ => {} + }; } else { - self.start <= value - && match self.end { - Bound::Included(end) => value <= end, - Bound::Excluded(end) => value < end, - Bound::Unbounded => true, - } + // Increasing range + if value < self.start { + return false; + } + match self.end { + Bound::Included(end) if value > end => return false, + Bound::Excluded(end) if value >= end => return false, + _ => {} + }; } + (value - self.start) % self.step == 0 } pub fn into_range_iter(self, signals: Signals) -> Iter { @@ -330,20 +337,27 @@ mod float_range { pub fn contains(&self, value: f64) -> bool { if self.step < 0.0 { - value <= self.start - && match self.end { - Bound::Included(end) => value >= end, - Bound::Excluded(end) => value > end, - Bound::Unbounded => true, - } + // Decreasing range + if value > self.start { + return false; + } + match self.end { + Bound::Included(end) if value <= end => return false, + Bound::Excluded(end) if value < end => return false, + _ => {} + }; } else { - self.start <= value - && match self.end { - Bound::Included(end) => value <= end, - Bound::Excluded(end) => value < end, - Bound::Unbounded => true, - } + // Increasing range + if value < self.start { + return false; + } + match self.end { + Bound::Included(end) if value >= end => return false, + Bound::Excluded(end) if value > end => return false, + _ => {} + }; } + ((value - self.start) % self.step).abs() < f64::EPSILON } pub fn into_range_iter(self, signals: Signals) -> Iter { diff --git a/tests/repl/test_ranges.rs b/tests/repl/test_ranges.rs index 96f59eea84..8e7a557738 100644 --- a/tests/repl/test_ranges.rs +++ b/tests/repl/test_ranges.rs @@ -7,7 +7,7 @@ fn int_in_inc_range() -> TestResult { #[test] fn int_in_dec_range() -> TestResult { - run_test(r#"1 in 9.42..-4"#, "true") + run_test(r#"1 in 9..-4.42"#, "true") } #[test] @@ -15,6 +15,16 @@ fn int_in_exclusive_range() -> TestResult { run_test(r#"3 in 0..<3"#, "false") } +#[test] +fn float_in_inc_range() -> TestResult { + run_test(r#"1.58 in -4.42..9"#, "true") +} + +#[test] +fn float_in_dec_range() -> TestResult { + run_test(r#"1.42 in 9.42..-4.42"#, "true") +} + #[test] fn non_number_in_range() -> TestResult { fail_test(r#"'a' in 1..3"#, "subset comparison is not supported") @@ -34,3 +44,33 @@ fn range_and_reduction() -> TestResult { fn zip_ranges() -> TestResult { run_test(r#"1..3 | zip 4..6 | get 2.1"#, "6") } + +#[test] +fn int_in_stepped_range() -> TestResult { + run_test(r#"7 in 1..3..15"#, "true") +} + +#[test] +fn int_in_unbounded_stepped_range() -> TestResult { + run_test(r#"1000001 in 1..3.."#, "true") +} + +#[test] +fn int_not_in_unbounded_stepped_range() -> TestResult { + run_test(r#"2 in 1..3.."#, "false") +} + +#[test] +fn float_in_stepped_range() -> TestResult { + run_test(r#"5.5 in 1..1.5..10"#, "true") +} + +#[test] +fn float_in_unbounded_stepped_range() -> TestResult { + run_test(r#"100.5 in 1..1.5.."#, "true") +} + +#[test] +fn float_not_in_unbounded_stepped_range() -> TestResult { + run_test(r#"2.1 in 1.2..3.."#, "false") +}