Skip to content

Commit

Permalink
Added NotNaN predicate
Browse files Browse the repository at this point in the history
  • Loading branch information
dcastro committed Dec 12, 2018
1 parent 88afcd5 commit ae438c1
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ The library comes with these predefined predicates:
* `NonDivisible[N]`: checks if an integral value is not evenly divisible by `N`
* `Even`: checks if an integral value is evenly divisible by 2
* `Odd`: checks if an integral value is not evenly divisible by 2
* `NotNaN`: checks if a floating-point number is not NaN

[`string`](https://github.com/fthomas/refined/blob/master/modules/core/shared/src/main/scala/eu/timepit/refined/string.scala)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ object numeric extends NumericInference {
/** Predicate that checks if an integral value modulo `N` is `O`. */
final case class Modulo[N, O](n: N, o: O)

/** Predicate that checks if a floating-point number value is not NaN. */
case class NotNaN()

/** Predicate that checks if a numeric value is less than or equal to `N`. */
type LessEqual[N] = Not[Greater[N]]

Expand Down Expand Up @@ -117,6 +120,14 @@ object numeric extends NumericInference {
Modulo(wn.fst, wo.fst)
)
}

object NotNaN {
implicit def floatNotNaNValidate: Validate.Plain[Float, NotNaN] = fromIsNaN(_.isNaN)
implicit def doubleNotNaNValidate: Validate.Plain[Double, NotNaN] = fromIsNaN(_.isNaN)

def fromIsNaN[A](isNaN: A => Boolean): Validate.Plain[A, NotNaN] =
Validate.fromPredicate(x => !isNaN(x), x => s"$x != NaN", NotNaN())
}
}

private[refined] trait NumericInference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ trait NumericPredicates {
final type Modulo[N, O] = refined.numeric.Modulo[N, O]
final val Modulo = refined.numeric.Modulo

final type NotNaN = refined.numeric.NotNaN
final val NotNaN = refined.numeric.NotNaN

final type LessEqual[N] = refined.numeric.LessEqual[N]

final type GreaterEqual[N] = refined.numeric.GreaterEqual[N]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package eu.timepit.refined.types

import eu.timepit.refined.api.{Refined, RefinedTypeOps}
import eu.timepit.refined.numeric.{Negative, NonNegative, NonPositive, Positive}
import eu.timepit.refined.numeric.{Negative, NonNegative, NonPositive, NotNaN, Positive}

/** Module for numeric refined types. */
object numeric {
Expand Down Expand Up @@ -165,6 +165,16 @@ object numeric {
type NonPosBigDecimal = BigDecimal Refined NonPositive

object NonPosBigDecimal extends RefinedTypeOps[NonPosBigDecimal, BigDecimal]

/** A `Float` that is not NaN. */
type FloatNotNaN = Float Refined NotNaN

object FloatNotNaN extends RefinedTypeOps[FloatNotNaN, Float]

/** A `Double` that is not NaN. */
type DoubleNotNaN = Double Refined NotNaN

object DoubleNotNaN extends RefinedTypeOps[DoubleNotNaN, Double]
}

trait NumericTypes {
Expand Down Expand Up @@ -215,6 +225,12 @@ trait NumericTypes {

final type NonPosDouble = numeric.NonPosDouble
final val NonPosDouble = numeric.NonPosDouble

final type FloatNotNaN = numeric.FloatNotNaN
final val FloatNotNaN = numeric.FloatNotNaN

final type DoubleNotNaN = numeric.DoubleNotNaN
final val DoubleNotNaN = numeric.DoubleNotNaN
}

trait NumericTypesBinCompat1 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package eu.timepit.refined

import eu.timepit.refined.TestUtils._
import eu.timepit.refined.numeric._
import org.scalacheck.{Arbitrary, Gen, Properties}
import org.scalacheck.Prop._
import org.scalacheck.Properties
import shapeless.nat._

class NumericValidateSpec extends Properties("NumericValidate") {
Expand Down Expand Up @@ -179,4 +179,25 @@ class NumericValidateSpec extends Properties("NumericValidate") {
val s = showExpr[Interval.Closed[_0, _1]](0.5)
(s ?= "(!(0.5 < 0) && !(0.5 > 1))") || (s ?= "(!(0.5 < 0.0) && !(0.5 > 1.0))")
}


val floatWithNaN: Gen[Float] = Gen.frequency(8 -> Arbitrary.arbitrary[Float], 2 -> Float.NaN)
val doubleWithNaN: Gen[Double] = Gen.frequency(8 -> Arbitrary.arbitrary[Double], 2 -> Double.NaN)

property("NotNaN.Float.isValid") = forAll(floatWithNaN) { (d: Float) =>
isValid[NotNaN](d) ?= !d.isNaN
}

property("NotNaN.Float.showExpr") = secure {
showExpr[NotNaN](Float.NaN) ?= "NaN != NaN"
}

property("NotNaN.Double.isValid") = forAll(doubleWithNaN) { (d: Double) =>
isValid[NotNaN](d) ?= !d.isNaN
}

property("NotNaN.Double.showExpr") = secure {
showExpr[NotNaN](Double.NaN) ?= "NaN != NaN"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ trait NumericInstances {
): Arbitrary[F[T, GreaterEqual[N]]] =
rangeClosedArbitrary(wn.snd, max.max)

implicit def floatNotNaNArbitrary[F[_, _]: RefType](implicit arb: Arbitrary[Float]): Arbitrary[F[Float, NotNaN]] =
arbitraryRefType(arb.arbitrary.suchThat(x => !x.isNaN))

implicit def doubleNotNaNArbitrary[F[_, _]: RefType](implicit arb: Arbitrary[Double]): Arbitrary[F[Double, NotNaN]] =
arbitraryRefType(arb.arbitrary.suchThat(x => !x.isNaN))

///

implicit def intervalOpenArbitrary[F[_, _]: RefType, T: Numeric: Choose: Adjacent, L, H](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import eu.timepit.refined.W
import eu.timepit.refined.api.Refined
import eu.timepit.refined.numeric._
import eu.timepit.refined.scalacheck.numeric._
import eu.timepit.refined.types.numeric.{NegDouble, NonNegInt, NonNegLong, PosFloat}
import eu.timepit.refined.types.numeric.{DoubleNotNaN, FloatNotNaN, NegDouble, NonNegInt, NonNegLong, PosFloat}
import eu.timepit.refined.types.time.Minute
import org.scalacheck.Prop._
import org.scalacheck.Properties
Expand Down Expand Up @@ -36,6 +36,10 @@ class NumericArbitrarySpec extends Properties("NumericArbitrary") {

property("GreaterEqual[_10]") = checkArbitraryRefinedType[Int Refined GreaterEqual[_10]]

property("FloatNotNaN") = checkArbitraryRefinedType[FloatNotNaN]

property("DoubleNotNaN") = checkArbitraryRefinedType[DoubleNotNaN]

property("PosFloat") = checkArbitraryRefinedType[PosFloat]

property("NonPositive") = checkArbitraryRefinedType[Short Refined NonPositive]
Expand Down

0 comments on commit ae438c1

Please sign in to comment.