From fc9dad401e76a3a244e12d5a5d1b45bd8a218cb3 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sun, 26 Mar 2017 23:30:18 -0600 Subject: [PATCH 01/17] Add clamp RFC --- 0000-clamp.md | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 0000-clamp.md diff --git a/0000-clamp.md b/0000-clamp.md new file mode 100644 index 00000000000..9f8a037f6ed --- /dev/null +++ b/0000-clamp.md @@ -0,0 +1,163 @@ +- Feature Name: clamp functions +- Start Date: 2017-03-26 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Add functions to the language which take a value and an inclusive range, and will "clamp" the input to the range. I.E. + +```Rust +if input > max { + return max; +} +else if input < min { + return min; +} else { + return input; +} +``` + +Likely locations would be in std::cmp::clamp implemented for all Ord types, and a special version implemented for f32 and f64. +The f32 and f64 versions could live either in std::cmp or in the primitive types themselves. There are good arguments for either +location. + +# Motivation +[motivation]: #motivation + +Clamp is a very common pattern in Rust libraries downstream. Some observed implementations of this include: + +http://nalgebra.org/rustdoc/nalgebra/fn.clamp.html + +http://rust-num.github.io/num/num/fn.clamp.html + +Many libraries don't expose or consume a clamp function but will instead use patterns like this: +```Rust +if input > max { + max +} +else if input < min { + min +} else { + input +} +``` +and +```Rust +input.max(min).min(max); +``` +and even +```Rust +match input { + c if c > max => max, + c if c < min => min, + c => c, +} +``` + +Typically these patterns exist where there is a need to interface with APIs that take normalized values or when sending +output to hardware that expects values to be in a certain range, such as audio samples or painting to pixels on a display. + +While this is pretty trivial to implement downstream there are quite a few ways to do it and just writing the clamp +inline usually results in rather a lot of control flow structure to describe a fairly simple and common concept. + +# Detailed design +[design]: #detailed-design + +Add the following to std::cmp + +```Rust +use ops::RangeInclusive; +/// Returns the upper bound of the range if input is greater than the range, and the lower bound of +/// the range if input is less than the range. Otherwise this will return input. +/// +/// #Examples +/// +/// ``` +/// assert!((-3).clamp(-2...1) == -2); +/// assert!((0).clamp(-2...1) == 0); +/// assert!((2).clamp(-2, 1) == 1); +/// ``` +#[inline] +pub fn clamp(input: T, range: RangeInclusive) -> T { + if let RangeInclusive::NonEmpty{start, end} = range { + if input < start { + return start; + } + else if input > end { + return end; + } + else { + return input; + } + } + else { + // This should never be executed. + return input; + } +} +``` + +And the following to libstd/f32.rs, and a similar version for f64 + +```Rust +use ops::RangeInclusive; +/// Returns the upper bound if self is greater than the bound, and the lower bound if self is less than the bound. +/// Otherwise this returns self. +/// +/// # Examples +/// +/// ``` +/// assert!((-3.0f32).clamp(-2.0f32...1.0f32) == -2.0f32); +/// assert!((0.0f32).clamp(-2.0f32...1.0f32) == 0.0f32); +/// assert!((2.0f32).clamp(-2.0f32...1.0f32) == 1.0f32); +/// ``` +#[inline] +pub fn clamp(self, range: RangeInclusive) -> f32 { + if let NonEmpty{start, end} = range { + if self < start { + return start; + } + else if self > max { + return max; + } + else { + return self; + } + } + else { + // This should never be executed. + return NAN; + } +} +``` + +There are 3 special float values the clamp function will need to handle, and 3 positions into which they can go so I will represent +the edge case behavior with a 3x3 chart. + +| |INFINITY|NEG_INFINITY|NAN| +|---|---|---|---| +|self|return max;|return min;|return NAN;| +|upper bound|No upper bound enforced|return NEG_INFINITY;|No upper bound enforced| +|lower bound|return INFINITY;|No lower bound enforced|No lower bound enforced| + +# How We Teach This +[how-we-teach-this]: #how-we-teach-this + +The proposed changes would not mandate modifications to any Rust educational material. + +# Drawbacks +[drawbacks]: #drawbacks + +This is trivial to implement downstream, and several versions of it exist downstream. + +# Alternatives +[alternatives]: #alternatives + +Alternatives were explored at https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999 + +# Unresolved questions +[unresolved]: #unresolved-questions + +Should the float version of the clamp function live in f32 and f64, or in std::cmp as that's where the Ord version would go? From 3988071ed96c4c4a88731e018cbe08d982d05e3b Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Mon, 27 Mar 2017 00:03:23 -0600 Subject: [PATCH 02/17] Remove incorrect examples --- 0000-clamp.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/0000-clamp.md b/0000-clamp.md index 9f8a037f6ed..5b5ded191b5 100644 --- a/0000-clamp.md +++ b/0000-clamp.md @@ -71,14 +71,6 @@ Add the following to std::cmp use ops::RangeInclusive; /// Returns the upper bound of the range if input is greater than the range, and the lower bound of /// the range if input is less than the range. Otherwise this will return input. -/// -/// #Examples -/// -/// ``` -/// assert!((-3).clamp(-2...1) == -2); -/// assert!((0).clamp(-2...1) == 0); -/// assert!((2).clamp(-2, 1) == 1); -/// ``` #[inline] pub fn clamp(input: T, range: RangeInclusive) -> T { if let RangeInclusive::NonEmpty{start, end} = range { From ba9f88df5cbdee0d37ee7e50bb9532d432855885 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Mon, 27 Mar 2017 14:45:34 -0600 Subject: [PATCH 03/17] Move RFC into text and remove RangeInclusive use --- 0000-clamp.md => text/0000-clamp.md | 64 +++++++++++------------------ 1 file changed, 25 insertions(+), 39 deletions(-) rename 0000-clamp.md => text/0000-clamp.md (67%) diff --git a/0000-clamp.md b/text/0000-clamp.md similarity index 67% rename from 0000-clamp.md rename to text/0000-clamp.md index 5b5ded191b5..c8c8ad72223 100644 --- a/0000-clamp.md +++ b/text/0000-clamp.md @@ -68,25 +68,18 @@ inline usually results in rather a lot of control flow structure to describe a f Add the following to std::cmp ```Rust -use ops::RangeInclusive; -/// Returns the upper bound of the range if input is greater than the range, and the lower bound of -/// the range if input is less than the range. Otherwise this will return input. +/// Returns max if input is greater than max, and min if input is less than min. +/// Otherwise this will return input. #[inline] -pub fn clamp(input: T, range: RangeInclusive) -> T { - if let RangeInclusive::NonEmpty{start, end} = range { - if input < start { - return start; - } - else if input > end { - return end; - } - else { - return input; - } +pub fn clamp(input: T, min: T, max: T) -> T { + if input < min { + min + } + else if input > max { + max } else { - // This should never be executed. - return input; + input } } ``` @@ -94,34 +87,27 @@ pub fn clamp(input: T, range: RangeInclusive) -> T { And the following to libstd/f32.rs, and a similar version for f64 ```Rust -use ops::RangeInclusive; -/// Returns the upper bound if self is greater than the bound, and the lower bound if self is less than the bound. +/// Returns max if self is greater than max, and min if self is less than min. /// Otherwise this returns self. /// /// # Examples /// /// ``` -/// assert!((-3.0f32).clamp(-2.0f32...1.0f32) == -2.0f32); -/// assert!((0.0f32).clamp(-2.0f32...1.0f32) == 0.0f32); -/// assert!((2.0f32).clamp(-2.0f32...1.0f32) == 1.0f32); +/// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32); +/// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32); +/// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32); /// ``` #[inline] -pub fn clamp(self, range: RangeInclusive) -> f32 { - if let NonEmpty{start, end} = range { - if self < start { - return start; - } - else if self > max { - return max; - } - else { - return self; - } - } - else { - // This should never be executed. - return NAN; - } +pub fn clamp(self, min: f32, max: f32>) -> f32 { + if input < min { + min + } + else if input > max { + max + } + else { + input + } } ``` @@ -131,8 +117,8 @@ the edge case behavior with a 3x3 chart. | |INFINITY|NEG_INFINITY|NAN| |---|---|---|---| |self|return max;|return min;|return NAN;| -|upper bound|No upper bound enforced|return NEG_INFINITY;|No upper bound enforced| -|lower bound|return INFINITY;|No lower bound enforced|No lower bound enforced| +|max|No max enforced|return NEG_INFINITY;|No max enforced| +|min|return INFINITY;|No min enforced|No min enforced| # How We Teach This [how-we-teach-this]: #how-we-teach-this From 1a6a796f867fa5e5fd0f7a6dc59a63104ebec9d6 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 28 Mar 2017 12:38:01 -0600 Subject: [PATCH 04/17] Revise NAN behavior & optimize handling of floats. --- text/0000-clamp.md | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index c8c8ad72223..139733fd0e9 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -77,8 +77,7 @@ pub fn clamp(input: T, min: T, max: T) -> T { } else if input > max { max - } - else { + } else { input } } @@ -98,16 +97,11 @@ And the following to libstd/f32.rs, and a similar version for f64 /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32); /// ``` #[inline] -pub fn clamp(self, min: f32, max: f32>) -> f32 { - if input < min { - min - } - else if input > max { - max - } - else { - input - } +pub fn clamp(input:f32, min: f32, max: f32) -> f32 { + let mut x = input; + if !(x < min) { x = min; } + if !(x > max) { x = max; } + x } ``` @@ -117,8 +111,8 @@ the edge case behavior with a 3x3 chart. | |INFINITY|NEG_INFINITY|NAN| |---|---|---|---| |self|return max;|return min;|return NAN;| -|max|No max enforced|return NEG_INFINITY;|No max enforced| -|min|return INFINITY;|No min enforced|No min enforced| +|max|No max enforced|return NEG_INFINITY;|return NAN;| +|min|return INFINITY;|No min enforced|return NAN;| # How We Teach This [how-we-teach-this]: #how-we-teach-this @@ -139,3 +133,4 @@ Alternatives were explored at https://internals.rust-lang.org/t/clamp-function-f [unresolved]: #unresolved-questions Should the float version of the clamp function live in f32 and f64, or in std::cmp as that's where the Ord version would go? +Is the proposed handling for NAN inputs ideal? From 0c1dbc5eeaf34399e4839c33b8b20dda4de9926b Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 28 Mar 2017 12:49:22 -0600 Subject: [PATCH 05/17] Update 0000-clamp.md --- text/0000-clamp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 139733fd0e9..211b9352791 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -133,4 +133,5 @@ Alternatives were explored at https://internals.rust-lang.org/t/clamp-function-f [unresolved]: #unresolved-questions Should the float version of the clamp function live in f32 and f64, or in std::cmp as that's where the Ord version would go? + Is the proposed handling for NAN inputs ideal? From b16f5bd43152e6091c6bd9487ec6a78128dd04e4 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 28 Mar 2017 13:39:56 -0600 Subject: [PATCH 06/17] Update RFC to panic if max is less than min. --- text/0000-clamp.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 211b9352791..d2c52aea404 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -69,9 +69,10 @@ Add the following to std::cmp ```Rust /// Returns max if input is greater than max, and min if input is less than min. -/// Otherwise this will return input. +/// Otherwise this will return input. Panics if max < min. #[inline] pub fn clamp(input: T, min: T, max: T) -> T { + assert!(max >= min); if input < min { min } @@ -87,7 +88,7 @@ And the following to libstd/f32.rs, and a similar version for f64 ```Rust /// Returns max if self is greater than max, and min if self is less than min. -/// Otherwise this returns self. +/// Otherwise this returns self. Panics if max < min. /// /// # Examples /// @@ -98,6 +99,7 @@ And the following to libstd/f32.rs, and a similar version for f64 /// ``` #[inline] pub fn clamp(input:f32, min: f32, max: f32) -> f32 { + assert!(max >= min); let mut x = input; if !(x < min) { x = min; } if !(x > max) { x = max; } @@ -111,8 +113,8 @@ the edge case behavior with a 3x3 chart. | |INFINITY|NEG_INFINITY|NAN| |---|---|---|---| |self|return max;|return min;|return NAN;| -|max|No max enforced|return NEG_INFINITY;|return NAN;| -|min|return INFINITY;|No min enforced|return NAN;| +|max|No max enforced|return NEG_INFINITY;|panic| +|min|return INFINITY;|No min enforced|panic| # How We Teach This [how-we-teach-this]: #how-we-teach-this From 2e31a67730b3765d8484f7ad5382568d32eb60f5 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 28 Mar 2017 13:52:36 -0600 Subject: [PATCH 07/17] Fix float impl --- text/0000-clamp.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index d2c52aea404..fbf5257ad4a 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -69,10 +69,10 @@ Add the following to std::cmp ```Rust /// Returns max if input is greater than max, and min if input is less than min. -/// Otherwise this will return input. Panics if max < min. +/// Otherwise this will return input. Panics if min > max. #[inline] pub fn clamp(input: T, min: T, max: T) -> T { - assert!(max >= min); + assert!(min <= max); if input < min { min } @@ -88,7 +88,7 @@ And the following to libstd/f32.rs, and a similar version for f64 ```Rust /// Returns max if self is greater than max, and min if self is less than min. -/// Otherwise this returns self. Panics if max < min. +/// Otherwise this returns self. Panics if min > max. /// /// # Examples /// @@ -97,12 +97,11 @@ And the following to libstd/f32.rs, and a similar version for f64 /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32); /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32); /// ``` -#[inline] -pub fn clamp(input:f32, min: f32, max: f32) -> f32 { - assert!(max >= min); - let mut x = input; - if !(x < min) { x = min; } - if !(x > max) { x = max; } +pub fn clamp(self, min: f32, max: f32) -> f32 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } x } ``` From b2df178bf038dfe72330c50df2bf816fce3f26ac Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Wed, 29 Mar 2017 23:46:48 -0600 Subject: [PATCH 08/17] Update RFC to reflect discussion. --- text/0000-clamp.md | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index fbf5257ad4a..0cc32b8e0ed 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -65,13 +65,13 @@ inline usually results in rather a lot of control flow structure to describe a f # Detailed design [design]: #detailed-design -Add the following to std::cmp +Add the following to std::cmp::Ord ```Rust -/// Returns max if input is greater than max, and min if input is less than min. -/// Otherwise this will return input. Panics if min > max. +/// Returns max if self is greater than max, and min if self is less than min. +/// Otherwise this will return self. Panics if min > max. #[inline] -pub fn clamp(input: T, min: T, max: T) -> T { +pub fn clamp(self, min: Self, max: Self) -> Self { assert!(min <= max); if input < min { min @@ -79,11 +79,39 @@ pub fn clamp(input: T, min: T, max: T) -> T { else if input > max { max } else { - input + self } } ``` +And the following to std::cmp::PartialOrd. + +```Rust +/// Returns max if self is greater than max, and min if self is less than min. +/// Otherwise this will return self. Panics if min > max. +/// +/// This function will return None if a comparison to either min or max couldn't be made. +#[inline] +pub fn partial_clamp(self, min: Self, max: Self) -> Option { + assert!(min <= max); + let min_compare = input.partial_cmp(&min); + if let Some(Ordering::Less) = min_compare { + return Some(min); + } + else if let None = min_compare { + return None; + } + let max_compare = input.partial_cmp(&max); + if let Some(Ordering::Greater) = max_compare { + return Some(max); + } + else if let None = max_compare { + return None; + } + return Some(self); +} +``` + And the following to libstd/f32.rs, and a similar version for f64 ```Rust @@ -130,9 +158,9 @@ This is trivial to implement downstream, and several versions of it exist downst Alternatives were explored at https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999 +Additionally there is the option of placing clamp and partial_clamp in std::cmp in order to avoid backwards compatibility problems. This is however semantically undesirable, as `1.clamp(2, 3);` is more readable than `clamp(1, 2, 3);` + # Unresolved questions [unresolved]: #unresolved-questions -Should the float version of the clamp function live in f32 and f64, or in std::cmp as that's where the Ord version would go? - Is the proposed handling for NAN inputs ideal? From 81fb0906711277e9bbc885e4f350f2237b049bea Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Wed, 29 Mar 2017 23:58:17 -0600 Subject: [PATCH 09/17] Return None if min can't be compared to max. --- text/0000-clamp.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 0cc32b8e0ed..179844d4ec7 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -93,7 +93,13 @@ And the following to std::cmp::PartialOrd. /// This function will return None if a comparison to either min or max couldn't be made. #[inline] pub fn partial_clamp(self, min: Self, max: Self) -> Option { - assert!(min <= max); + let min_max_compare = min.partial_cmp(&max); + if let None = min_max_compare { + return None; + } + else if let Some(cmp) = min_max_compare { + assert!(cmp == Ordering::Less || cmp == Ordering::Equal); + } let min_compare = input.partial_cmp(&min); if let Some(Ordering::Less) = min_compare { return Some(min); From acacdba9fa02488dd579a23ca08c2c30cc4cfb63 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Thu, 30 Mar 2017 13:32:06 -0600 Subject: [PATCH 10/17] Fix implementation --- text/0000-clamp.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 179844d4ec7..c775f1840fe 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -73,10 +73,10 @@ Add the following to std::cmp::Ord #[inline] pub fn clamp(self, min: Self, max: Self) -> Self { assert!(min <= max); - if input < min { + if self < min { min } - else if input > max { + else if self > max { max } else { self @@ -100,14 +100,14 @@ pub fn partial_clamp(self, min: Self, max: Self) -> Option { else if let Some(cmp) = min_max_compare { assert!(cmp == Ordering::Less || cmp == Ordering::Equal); } - let min_compare = input.partial_cmp(&min); + let min_compare = self.partial_cmp(&min); if let Some(Ordering::Less) = min_compare { return Some(min); } else if let None = min_compare { return None; } - let max_compare = input.partial_cmp(&max); + let max_compare = self.partial_cmp(&max); if let Some(Ordering::Greater) = max_compare { return Some(max); } From 2abd67175f4ada0c7fb4560ae07fe819b8c75da9 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Thu, 30 Mar 2017 13:34:22 -0600 Subject: [PATCH 11/17] Fix doc string --- text/0000-clamp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index c775f1840fe..189993e3f62 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -122,7 +122,7 @@ And the following to libstd/f32.rs, and a similar version for f64 ```Rust /// Returns max if self is greater than max, and min if self is less than min. -/// Otherwise this returns self. Panics if min > max. +/// Otherwise this returns self. Panics if min > max, min equals NAN, or max equals NAN. /// /// # Examples /// From 5c58c29b28c6fc0fca4962510a42569c2c0d4ff5 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Thu, 30 Mar 2017 13:34:51 -0600 Subject: [PATCH 12/17] Remove edge cases table as it is now redundant. --- text/0000-clamp.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 189993e3f62..396efdba88f 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -140,15 +140,6 @@ pub fn clamp(self, min: f32, max: f32) -> f32 { } ``` -There are 3 special float values the clamp function will need to handle, and 3 positions into which they can go so I will represent -the edge case behavior with a 3x3 chart. - -| |INFINITY|NEG_INFINITY|NAN| -|---|---|---|---| -|self|return max;|return min;|return NAN;| -|max|No max enforced|return NEG_INFINITY;|panic| -|min|return INFINITY;|No min enforced|panic| - # How We Teach This [how-we-teach-this]: #how-we-teach-this From 2923d07f1758a6a5815ae6525f7ababaf073e43f Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sat, 1 Apr 2017 10:57:47 -0600 Subject: [PATCH 13/17] Remove partial_clamp --- text/0000-clamp.md | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 396efdba88f..00e1f3f6908 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -84,40 +84,6 @@ pub fn clamp(self, min: Self, max: Self) -> Self { } ``` -And the following to std::cmp::PartialOrd. - -```Rust -/// Returns max if self is greater than max, and min if self is less than min. -/// Otherwise this will return self. Panics if min > max. -/// -/// This function will return None if a comparison to either min or max couldn't be made. -#[inline] -pub fn partial_clamp(self, min: Self, max: Self) -> Option { - let min_max_compare = min.partial_cmp(&max); - if let None = min_max_compare { - return None; - } - else if let Some(cmp) = min_max_compare { - assert!(cmp == Ordering::Less || cmp == Ordering::Equal); - } - let min_compare = self.partial_cmp(&min); - if let Some(Ordering::Less) = min_compare { - return Some(min); - } - else if let None = min_compare { - return None; - } - let max_compare = self.partial_cmp(&max); - if let Some(Ordering::Greater) = max_compare { - return Some(max); - } - else if let None = max_compare { - return None; - } - return Some(self); -} -``` - And the following to libstd/f32.rs, and a similar version for f64 ```Rust From f2cc3c05b5ad3ff56541147d5a6047ae613077ed Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Sun, 2 Apr 2017 00:01:37 -0600 Subject: [PATCH 14/17] Remove partial_clamp from alternatives section --- text/0000-clamp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 00e1f3f6908..8e2bee1a985 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -121,7 +121,7 @@ This is trivial to implement downstream, and several versions of it exist downst Alternatives were explored at https://internals.rust-lang.org/t/clamp-function-for-primitive-types/4999 -Additionally there is the option of placing clamp and partial_clamp in std::cmp in order to avoid backwards compatibility problems. This is however semantically undesirable, as `1.clamp(2, 3);` is more readable than `clamp(1, 2, 3);` +Additionally there is the option of placing clamp in std::cmp in order to avoid backwards compatibility problems. This is however semantically undesirable, as `1.clamp(2, 3);` is more readable than `clamp(1, 2, 3);` # Unresolved questions [unresolved]: #unresolved-questions From 8e968224a1b5e870f7ebec14f6e5dec3b190f854 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Wed, 26 Jul 2017 08:41:18 -0600 Subject: [PATCH 15/17] Remove outdated text --- text/0000-clamp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index 8e2bee1a985..dd918a36a4f 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -19,7 +19,7 @@ else if input < min { } ``` -Likely locations would be in std::cmp::clamp implemented for all Ord types, and a special version implemented for f32 and f64. +Likely locations would be on the Ord trait, and a special version implemented for f32 and f64. The f32 and f64 versions could live either in std::cmp or in the primitive types themselves. There are good arguments for either location. From 71d594d8967031061a91cfd6a88025c2045a92d3 Mon Sep 17 00:00:00 2001 From: Jacob Kiesel Date: Tue, 8 Aug 2017 23:28:00 -0600 Subject: [PATCH 16/17] Update RFC to better reflect conversation thus far --- text/0000-clamp.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/text/0000-clamp.md b/text/0000-clamp.md index dd918a36a4f..34869a687de 100644 --- a/text/0000-clamp.md +++ b/text/0000-clamp.md @@ -19,9 +19,7 @@ else if input < min { } ``` -Likely locations would be on the Ord trait, and a special version implemented for f32 and f64. -The f32 and f64 versions could live either in std::cmp or in the primitive types themselves. There are good arguments for either -location. +These would be on the Ord trait, and have a special version implemented for f32 and f64. # Motivation [motivation]: #motivation @@ -88,7 +86,7 @@ And the following to libstd/f32.rs, and a similar version for f64 ```Rust /// Returns max if self is greater than max, and min if self is less than min. -/// Otherwise this returns self. Panics if min > max, min equals NAN, or max equals NAN. +/// Otherwise this returns self. Panics if min > max, min equals NaN, or max equals NaN. /// /// # Examples /// @@ -106,6 +104,8 @@ pub fn clamp(self, min: f32, max: f32) -> f32 { } ``` +This NaN handling behavior was chosen because a range with NaN on either side isn't really a range at all and the function can't be guaranteed to behave correctly if that is the case. + # How We Teach This [how-we-teach-this]: #how-we-teach-this @@ -126,4 +126,4 @@ Additionally there is the option of placing clamp in std::cmp in order to avoid # Unresolved questions [unresolved]: #unresolved-questions -Is the proposed handling for NAN inputs ideal? +None From ac69333f64f34bf8637d25905c16132c89a9dafa Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 5 Sep 2017 19:05:29 -0700 Subject: [PATCH 17/17] RFC 1961 introduces clamp functions --- text/{0000-clamp.md => 1961-clamp.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename text/{0000-clamp.md => 1961-clamp.md} (96%) diff --git a/text/0000-clamp.md b/text/1961-clamp.md similarity index 96% rename from text/0000-clamp.md rename to text/1961-clamp.md index 34869a687de..3514d0701a3 100644 --- a/text/0000-clamp.md +++ b/text/1961-clamp.md @@ -1,7 +1,7 @@ - Feature Name: clamp functions - Start Date: 2017-03-26 -- RFC PR: (leave this empty) -- Rust Issue: (leave this empty) +- RFC PR: https://github.com/rust-lang/rfcs/pull/1961/ +- Rust Issue: https://github.com/rust-lang/rust/issues/44095 # Summary [summary]: #summary