From 3473eef66d880876926b4f53fcffd69ba131784a Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Fri, 10 May 2024 19:24:02 +0000 Subject: [PATCH 1/9] Restrict a type Signed-off-by: GitHub --- typed_floats/src/traits.rs | 24 ++++++ typed_floats/src/types/impls/mod.rs | 1 + typed_floats/src/types/impls/restrict.rs | 101 +++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 typed_floats/src/types/impls/restrict.rs diff --git a/typed_floats/src/traits.rs b/typed_floats/src/traits.rs index da77cbc..b6d078f 100644 --- a/typed_floats/src/traits.rs +++ b/typed_floats/src/traits.rs @@ -190,3 +190,27 @@ pub trait Powf { /// See [`f64::powf()`] for more details. fn powf(self, rhs: T) -> Self::Output; } + +pub trait RestrictInf: Sized { + type Output: Sized; + + fn restrict_inf(self) -> Result; +} + +pub trait RestrictZero: Sized { + type Output: Sized; + + fn restrict_zero(self) -> Result; +} + +pub trait RestrictPositive: Sized { + type Output: Sized; + + fn restrict_positive(self) -> Result; +} + +pub trait RestrictNegative: Sized { + type Output: Sized; + + fn restrict_negative(self) -> Result; +} \ No newline at end of file diff --git a/typed_floats/src/types/impls/mod.rs b/typed_floats/src/types/impls/mod.rs index 8dec7f9..7cd3e31 100644 --- a/typed_floats/src/types/impls/mod.rs +++ b/typed_floats/src/types/impls/mod.rs @@ -5,3 +5,4 @@ mod from_str; mod from_to; mod hash; mod ord; +mod restrict; diff --git a/typed_floats/src/types/impls/restrict.rs b/typed_floats/src/types/impls/restrict.rs new file mode 100644 index 0000000..8b31a73 --- /dev/null +++ b/typed_floats/src/types/impls/restrict.rs @@ -0,0 +1,101 @@ +use crate::{ + Negative, NegativeFinite, NonNaN, NonNaNFinite, NonZeroNonNaN, + NonZeroNonNaNFinite, Positive, PositiveFinite, StrictlyNegative, StrictlyNegativeFinite, + StrictlyPositive, StrictlyPositiveFinite, + RestrictInf, RestrictZero, RestrictPositive, RestrictNegative, +}; + + +macro_rules! impl_exclude { + ($trait:ident, $fn:ident, $check:ident, $type:ident, $output:ident) => { + impl $trait for $type { + type Output = $output; + + /// Filters out infinite values. + /// + /// ``` + /// use typed_floats::*; + /// + /// let a: Positive = 0.0.try_into().unwrap(); + /// let b: PositiveFinite = a.restrict_inf().unwrap(); + /// ``` + #[inline] + fn $fn(self) -> Result { + if self.$check() { + Err(self) + } else { + Ok(unsafe { $output::::new_unchecked(self.get()) }) + } + } + } + + impl $trait for $type { + type Output = $output; + + /// Filters out infinite values. + /// + /// ``` + /// use typed_floats::*; + /// + /// let a: Positive = 0.0.try_into().unwrap(); + /// let b: PositiveFinite = a.restrict_inf().unwrap(); + /// ``` + #[inline] + fn $fn(self) -> Result { + if self.$check() { + Err(self) + } else { + Ok(unsafe { $output::::new_unchecked(self.get()) }) + } + } + } + } +} + +macro_rules! impl_exclude_inf { + ($type:ident, $output:ident) => { + impl_exclude!(RestrictInf, restrict_inf, is_infinite, $type, $output); + } +} + +macro_rules! impl_exclude_zero { + ($type:ident, $output:ident) => { + //impl_exclude!(RestrictZero, restrict_zero, is_zero, $type, $output); + } +} + +macro_rules! impl_exclude_positive { + ($type:ident, $output:ident) => { + impl_exclude!(RestrictPositive, restrict_positive, is_sign_positive, $type, $output); + } +} + +macro_rules! impl_exclude_negative { + ($type:ident, $output:ident) => { + impl_exclude!(RestrictNegative, restrict_negative, is_sign_positive, $type, $output); + } +} + +impl_exclude_inf!(NonNaN, NonNaNFinite); +impl_exclude_inf!(NonZeroNonNaN, NonZeroNonNaNFinite); +impl_exclude_inf!(StrictlyPositive, StrictlyPositiveFinite); +impl_exclude_inf!(StrictlyNegative, StrictlyNegativeFinite); +impl_exclude_inf!(Positive, PositiveFinite); +impl_exclude_inf!(Negative, NegativeFinite); + +impl_exclude_zero!(NonNaN, NonZeroNonNaN); +impl_exclude_zero!(NonNaNFinite, NonZeroNonNaNFinite); +impl_exclude_zero!(PositiveFinite, StrictlyPositiveFinite); +impl_exclude_zero!(NegativeFinite, StrictlyNegativeFinite); +impl_exclude_zero!(Positive, StrictlyPositive); +impl_exclude_zero!(Negative, StrictlyNegative); + +impl_exclude_positive!(NonNaN, Negative); +impl_exclude_positive!(NonNaNFinite, NegativeFinite); +impl_exclude_positive!(NonZeroNonNaN, StrictlyNegative); +impl_exclude_positive!(NonZeroNonNaNFinite, StrictlyNegativeFinite); + +impl_exclude_negative!(NonNaN, Positive); +impl_exclude_negative!(NonNaNFinite, PositiveFinite); +impl_exclude_negative!(NonZeroNonNaN, StrictlyPositive); +impl_exclude_negative!(NonZeroNonNaNFinite, StrictlyPositiveFinite); From de36629fd6a2752e06973bdc13aa1a99b3bb4ab4 Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Fri, 10 May 2024 19:28:27 +0000 Subject: [PATCH 2/9] Example Signed-off-by: GitHub --- typed_floats/src/types/impls/restrict.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/typed_floats/src/types/impls/restrict.rs b/typed_floats/src/types/impls/restrict.rs index 8b31a73..558c849 100644 --- a/typed_floats/src/types/impls/restrict.rs +++ b/typed_floats/src/types/impls/restrict.rs @@ -18,6 +18,10 @@ macro_rules! impl_exclude { /// /// let a: Positive = 0.0.try_into().unwrap(); /// let b: PositiveFinite = a.restrict_inf().unwrap(); + /// let c: PositiveFinite = match a.restrict_inf() { + /// Ok(x) => x, + /// Err(x) => panic!("{} is infinite", x), + /// }; /// ``` #[inline] fn $fn(self) -> Result { From 09cadf4feb0cf38e7670080371d13e29bcb2b268 Mon Sep 17 00:00:00 2001 From: Raimundo Martins Date: Sat, 12 Jul 2025 14:24:51 +0100 Subject: [PATCH 3/9] Add implementation of restrict_zero (#228) --- typed_floats/src/types/impls/restrict.rs | 46 +++++++++++++----------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/typed_floats/src/types/impls/restrict.rs b/typed_floats/src/types/impls/restrict.rs index 558c849..3913798 100644 --- a/typed_floats/src/types/impls/restrict.rs +++ b/typed_floats/src/types/impls/restrict.rs @@ -1,83 +1,87 @@ use crate::{ - Negative, NegativeFinite, NonNaN, NonNaNFinite, NonZeroNonNaN, - NonZeroNonNaNFinite, Positive, PositiveFinite, StrictlyNegative, StrictlyNegativeFinite, - StrictlyPositive, StrictlyPositiveFinite, - RestrictInf, RestrictZero, RestrictPositive, RestrictNegative, + Negative, NegativeFinite, NonNaN, NonNaNFinite, NonZeroNonNaN, NonZeroNonNaNFinite, Positive, + PositiveFinite, RestrictInf, RestrictNegative, RestrictPositive, RestrictZero, + StrictlyNegative, StrictlyNegativeFinite, StrictlyPositive, StrictlyPositiveFinite, }; - macro_rules! impl_exclude { - ($trait:ident, $fn:ident, $check:ident, $type:ident, $output:ident) => { + ($trait:ident, $fn:ident, $($check:ident)? $($zero:literal)?, $type:ident, $output:ident) => { impl $trait for $type { type Output = $output; /// Filters out infinite values. - /// + /// /// ``` /// use typed_floats::*; - /// + /// /// let a: Positive = 0.0.try_into().unwrap(); /// let b: PositiveFinite = a.restrict_inf().unwrap(); /// let c: PositiveFinite = match a.restrict_inf() { - /// Ok(x) => x, - /// Err(x) => panic!("{} is infinite", x), + /// Ok(x) => x, + /// Err(x) => panic!("{} is infinite", x), /// }; /// ``` #[inline] fn $fn(self) -> Result { - if self.$check() { + if + $(self.$check())? + $($crate::$type::accept_zero() && self.0 == $zero)? + { Err(self) } else { Ok(unsafe { $output::::new_unchecked(self.get()) }) } } } - + impl $trait for $type { type Output = $output; /// Filters out infinite values. - /// + /// /// ``` /// use typed_floats::*; - /// + /// /// let a: Positive = 0.0.try_into().unwrap(); /// let b: PositiveFinite = a.restrict_inf().unwrap(); /// ``` #[inline] fn $fn(self) -> Result { - if self.$check() { + if + $(self.$check())? + $($crate::$type::accept_zero() && self.0 == $zero)? + { Err(self) } else { Ok(unsafe { $output::::new_unchecked(self.get()) }) } } } - } + }; } macro_rules! impl_exclude_inf { ($type:ident, $output:ident) => { impl_exclude!(RestrictInf, restrict_inf, is_infinite, $type, $output); - } + }; } macro_rules! impl_exclude_zero { ($type:ident, $output:ident) => { - //impl_exclude!(RestrictZero, restrict_zero, is_zero, $type, $output); - } + impl_exclude!(RestrictZero, restrict_zero, 0.0, $type, $output); + }; } macro_rules! impl_exclude_positive { ($type:ident, $output:ident) => { impl_exclude!(RestrictPositive, restrict_positive, is_sign_positive, $type, $output); - } + }; } macro_rules! impl_exclude_negative { ($type:ident, $output:ident) => { impl_exclude!(RestrictNegative, restrict_negative, is_sign_positive, $type, $output); - } + }; } impl_exclude_inf!(NonNaN, NonNaNFinite); From 6f72b4e85021709a4bab1d27d8f692884075c6ef Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Sat, 12 Jul 2025 19:30:28 +0000 Subject: [PATCH 4/9] fmt + clippy Signed-off-by: GitHub --- typed_floats/src/traits.rs | 8 ++++---- typed_floats/src/types/impls/restrict.rs | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/typed_floats/src/traits.rs b/typed_floats/src/traits.rs index 26df511..156c6f2 100644 --- a/typed_floats/src/traits.rs +++ b/typed_floats/src/traits.rs @@ -194,25 +194,25 @@ pub trait Powf { pub trait RestrictInf: Sized { type Output: Sized; - fn restrict_inf(self) -> Result; + fn restrict_inf(self) -> Result; } pub trait RestrictZero: Sized { type Output: Sized; - fn restrict_zero(self) -> Result; + fn restrict_zero(self) -> Result; } pub trait RestrictPositive: Sized { type Output: Sized; - fn restrict_positive(self) -> Result; + fn restrict_positive(self) -> Result; } pub trait RestrictNegative: Sized { type Output: Sized; - fn restrict_negative(self) -> Result; + fn restrict_negative(self) -> Result; } #[rustversion::since(1.85)] diff --git a/typed_floats/src/types/impls/restrict.rs b/typed_floats/src/types/impls/restrict.rs index 3913798..327baa9 100644 --- a/typed_floats/src/types/impls/restrict.rs +++ b/typed_floats/src/types/impls/restrict.rs @@ -17,8 +17,8 @@ macro_rules! impl_exclude { /// let a: Positive = 0.0.try_into().unwrap(); /// let b: PositiveFinite = a.restrict_inf().unwrap(); /// let c: PositiveFinite = match a.restrict_inf() { - /// Ok(x) => x, - /// Err(x) => panic!("{} is infinite", x), + /// Ok(x) => x, + /// Err(x) => panic!("{} is infinite", x), /// }; /// ``` #[inline] @@ -74,13 +74,25 @@ macro_rules! impl_exclude_zero { macro_rules! impl_exclude_positive { ($type:ident, $output:ident) => { - impl_exclude!(RestrictPositive, restrict_positive, is_sign_positive, $type, $output); + impl_exclude!( + RestrictPositive, + restrict_positive, + is_sign_positive, + $type, + $output + ); }; } macro_rules! impl_exclude_negative { ($type:ident, $output:ident) => { - impl_exclude!(RestrictNegative, restrict_negative, is_sign_positive, $type, $output); + impl_exclude!( + RestrictNegative, + restrict_negative, + is_sign_positive, + $type, + $output + ); }; } From 088442fa3bca01d6c1b65d5f37c795c1ba8c73e2 Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Sun, 13 Jul 2025 12:56:21 +0000 Subject: [PATCH 5/9] fixes, doc & tests Signed-off-by: GitHub --- typed_floats/src/traits.rs | 94 ++++++++++++++++++++++-- typed_floats/src/types/impls/restrict.rs | 36 ++------- 2 files changed, 94 insertions(+), 36 deletions(-) diff --git a/typed_floats/src/traits.rs b/typed_floats/src/traits.rs index 156c6f2..7c30af1 100644 --- a/typed_floats/src/traits.rs +++ b/typed_floats/src/traits.rs @@ -191,28 +191,106 @@ pub trait Powf { fn powf(self, rhs: T) -> Self::Output; } -pub trait RestrictInf: Sized { +/// This trait is used to specify the return type of the exclude function. +pub trait ExcludeInf: Sized { + /// The resulting type after applying [`ExcludeInf::exclude_inf()`]. type Output: Sized; - fn restrict_inf(self) -> Result; + /// Filters out zeros. + /// + /// # Errors + /// + /// If the value is infinite, it returns an error with the original value. + /// + /// # Examples + /// + /// ``` + /// use typed_floats::*; + /// + /// let a: Positive = 0.0.try_into().unwrap(); + /// let b: PositiveFinite = a.exclude_inf().unwrap(); + /// let c: PositiveFinite = match a.exclude_inf() { + /// Ok(x) => x, + /// Err(x) => panic!("{} is infinite", x), + /// }; + /// ``` + fn exclude_inf(self) -> Result; } -pub trait RestrictZero: Sized { +/// This trait is used to specify the return type of the exclude function. +pub trait ExcludeZero: Sized { + /// The resulting type after applying [`ExcludeZero::exclude_zero()`]. type Output: Sized; - fn restrict_zero(self) -> Result; + /// Filters out zeros. + /// + /// # Errors + /// + /// If the value is zero, it returns an error with the original value. + /// + /// # Examples + /// + /// ``` + /// use typed_floats::*; + /// + /// let a: Positive = 1.0.try_into().unwrap(); + /// let b: StrictlyPositive = a.exclude_zero().unwrap(); + /// let c: StrictlyPositive = match a.exclude_zero() { + /// Ok(x) => x, + /// Err(x) => panic!("{} is +/-0.0", x), + /// }; + /// ``` + fn exclude_zero(self) -> Result; } -pub trait RestrictPositive: Sized { +/// This trait is used to specify the return type of the exclude function. +pub trait ExcludePositive: Sized { + /// The resulting type after applying [`ExcludePositive::exclude_positive()`]. type Output: Sized; - fn restrict_positive(self) -> Result; + /// Filters out positive values. + /// + /// # Errors + /// + /// If the value is positive, it returns an error with the original value. + /// + /// # Examples + /// + /// ``` + /// use typed_floats::*; + /// let a: NonNaN = (-0.0).try_into().unwrap(); + /// let b: Negative = a.exclude_positive().unwrap(); + /// let c: Negative = match a.exclude_positive() { + /// Ok(x) => x, + /// Err(x) => panic!("{} is positive", x), + /// }; + /// ``` + fn exclude_positive(self) -> Result; } -pub trait RestrictNegative: Sized { +/// This trait is used to specify the return type of the exclude function. +pub trait ExcludeNegative: Sized { + /// The resulting type after applying [`ExcludeNegative::exclude_negative()`]. type Output: Sized; - fn restrict_negative(self) -> Result; + /// Filters out negative values. + /// + /// # Errors + /// + /// If the value is negative, it returns an error with the original value. + /// + /// # Examples + /// + /// ``` + /// use typed_floats::*; + /// let a: NonNaN = 0.0.try_into().unwrap(); + /// let b: Positive = a.exclude_negative().unwrap(); + /// let c: Positive = match a.exclude_negative() { + /// Ok(x) => x, + /// Err(x) => panic!("{} is negative", x), + /// }; + /// ``` + fn exclude_negative(self) -> Result; } #[rustversion::since(1.85)] diff --git a/typed_floats/src/types/impls/restrict.rs b/typed_floats/src/types/impls/restrict.rs index 327baa9..b4b8150 100644 --- a/typed_floats/src/types/impls/restrict.rs +++ b/typed_floats/src/types/impls/restrict.rs @@ -1,6 +1,6 @@ use crate::{ Negative, NegativeFinite, NonNaN, NonNaNFinite, NonZeroNonNaN, NonZeroNonNaNFinite, Positive, - PositiveFinite, RestrictInf, RestrictNegative, RestrictPositive, RestrictZero, + PositiveFinite, ExcludeInf, ExcludeNegative, ExcludePositive, ExcludeZero, StrictlyNegative, StrictlyNegativeFinite, StrictlyPositive, StrictlyPositiveFinite, }; @@ -9,18 +9,6 @@ macro_rules! impl_exclude { impl $trait for $type { type Output = $output; - /// Filters out infinite values. - /// - /// ``` - /// use typed_floats::*; - /// - /// let a: Positive = 0.0.try_into().unwrap(); - /// let b: PositiveFinite = a.restrict_inf().unwrap(); - /// let c: PositiveFinite = match a.restrict_inf() { - /// Ok(x) => x, - /// Err(x) => panic!("{} is infinite", x), - /// }; - /// ``` #[inline] fn $fn(self) -> Result { if @@ -37,14 +25,6 @@ macro_rules! impl_exclude { impl $trait for $type { type Output = $output; - /// Filters out infinite values. - /// - /// ``` - /// use typed_floats::*; - /// - /// let a: Positive = 0.0.try_into().unwrap(); - /// let b: PositiveFinite = a.restrict_inf().unwrap(); - /// ``` #[inline] fn $fn(self) -> Result { if @@ -62,21 +42,21 @@ macro_rules! impl_exclude { macro_rules! impl_exclude_inf { ($type:ident, $output:ident) => { - impl_exclude!(RestrictInf, restrict_inf, is_infinite, $type, $output); + impl_exclude!(ExcludeInf, exclude_inf, is_infinite, $type, $output); }; } macro_rules! impl_exclude_zero { ($type:ident, $output:ident) => { - impl_exclude!(RestrictZero, restrict_zero, 0.0, $type, $output); + impl_exclude!(ExcludeZero, exclude_zero, 0.0, $type, $output); }; } macro_rules! impl_exclude_positive { ($type:ident, $output:ident) => { impl_exclude!( - RestrictPositive, - restrict_positive, + ExcludePositive, + exclude_positive, is_sign_positive, $type, $output @@ -87,9 +67,9 @@ macro_rules! impl_exclude_positive { macro_rules! impl_exclude_negative { ($type:ident, $output:ident) => { impl_exclude!( - RestrictNegative, - restrict_negative, - is_sign_positive, + ExcludeNegative, + exclude_negative, + is_sign_negative, $type, $output ); From 469e723f91626d402af880c68d45cc7e31818864 Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Mon, 14 Jul 2025 00:30:58 +0000 Subject: [PATCH 6/9] rename `restrict` into `exclude` Signed-off-by: GitHub --- typed_floats/src/types/impls/{restrict.rs => exclude.rs} | 0 typed_floats/src/types/impls/mod.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename typed_floats/src/types/impls/{restrict.rs => exclude.rs} (100%) diff --git a/typed_floats/src/types/impls/restrict.rs b/typed_floats/src/types/impls/exclude.rs similarity index 100% rename from typed_floats/src/types/impls/restrict.rs rename to typed_floats/src/types/impls/exclude.rs diff --git a/typed_floats/src/types/impls/mod.rs b/typed_floats/src/types/impls/mod.rs index 7cd3e31..40ee3b5 100644 --- a/typed_floats/src/types/impls/mod.rs +++ b/typed_floats/src/types/impls/mod.rs @@ -5,4 +5,4 @@ mod from_str; mod from_to; mod hash; mod ord; -mod restrict; +mod exclude; From 07061094a176d79ad0086ffd872fe5e8c4df171e Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Mon, 14 Jul 2025 11:41:07 +0000 Subject: [PATCH 7/9] Fix https://github.com/obi1kenobi/cargo-semver-checks/issues/1366 Signed-off-by: GitHub --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3a9fe80..ee47afb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -109,7 +109,7 @@ jobs: steps: - uses: actions/checkout@v4 - - run: cargo install cargo-semver-checks + - run: cargo install cargo-semver-checks --locked - run: cd typed_floats && cargo semver-checks --only-explicit-features ${{ matrix.features }} check-docs: From 2f6748ac859dbf8e954f164e8870b459896c183c Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:32:44 +0000 Subject: [PATCH 8/9] CHANGELOG Signed-off-by: GitHub --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40ef12b..5f835e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 1.0.7 - Unreleased +### Added + +- `exclude_inf`, `exclude_zero`, `exclude_positive` and `exclude_negative` to restrict a type [#136](https://github.com/tdelmas/typed_floats/pull/136) + ### Fixed - Panic when using `as_const!` with non-const values [#229](https://github.com/tdelmas/typed_floats/pull/229) From 42acfe81706467a1fccc6b38e3ffadb4e81e23bb Mon Sep 17 00:00:00 2001 From: Tom <1955774+tdelmas@users.noreply.github.com> Date: Mon, 14 Jul 2025 16:33:41 +0000 Subject: [PATCH 9/9] Add tests Signed-off-by: GitHub --- typed_floats/tests/exclude.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 typed_floats/tests/exclude.rs diff --git a/typed_floats/tests/exclude.rs b/typed_floats/tests/exclude.rs new file mode 100644 index 0000000..d5daf60 --- /dev/null +++ b/typed_floats/tests/exclude.rs @@ -0,0 +1,19 @@ +use typed_floats::*; + +#[test] +fn test_exclude_ok() { + let nonnan: NonNaN = 1.0.try_into().unwrap(); + let positive: Positive = nonnan.exclude_negative().unwrap(); + let finite: PositiveFinite = positive.exclude_inf().unwrap(); + let nonzero: Result, PositiveFinite> = finite.exclude_zero(); + assert!(nonzero.is_ok()); +} + +#[test] +fn test_exclude_err() { + let nonnan: NonNaN = 0.0.try_into().unwrap(); + let positive: Positive = nonnan.exclude_negative().unwrap(); + let finite: PositiveFinite = positive.exclude_inf().unwrap(); + let err: Result, PositiveFinite> = finite.exclude_zero(); + assert_eq!(err, Err(finite)); +}