Skip to content

Commit

Permalink
Add isConstant field
Browse files Browse the repository at this point in the history
  • Loading branch information
fthomas committed Jul 18, 2015
1 parent 1ae93d2 commit a1859ee
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 15 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ lazy val compileSettings = Seq(
),

wartremoverErrors in (Compile, compile) ++= Warts.unsafe diff
Seq(Wart.Any, Wart.AsInstanceOf, Wart.NonUnitStatements, Wart.Throw)
Seq(Wart.Any, Wart.DefaultArguments, Wart.AsInstanceOf, Wart.NonUnitStatements, Wart.Throw)
)

lazy val scaladocSettings = Seq(
Expand Down
21 changes: 16 additions & 5 deletions shared/src/main/scala/eu/timepit/refined/Predicate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ trait Predicate[P, T] extends Serializable { self =>
def validate(t: T): Option[String] =
if (isValid(t)) None else Some(s"Predicate failed: ${show(t)}.")

val isConstant: Boolean = false

/** Checks if `t` does not satisfy the predicate `P`. */
final def notValid(t: T): Boolean =
!isValid(t)
Expand All @@ -45,6 +47,7 @@ trait Predicate[P, T] extends Serializable { self =>
def isValid(u: U): Boolean = self.isValid(f(u))
def show(u: U): String = self.show(f(u))
override def validate(u: U): Option[String] = self.validate(f(u))
override val isConstant: Boolean = self.isConstant
override def accumulateIsValid(u: U): List[Boolean] = self.accumulateIsValid(f(u))
override def accumulateShow(u: U): List[String] = self.accumulateShow(f(u))
}
Expand All @@ -55,10 +58,18 @@ object Predicate {
def apply[P, T](implicit p: Predicate[P, T]): Predicate[P, T] = p

/** Constructs a [[Predicate]] from its parameters. */
def instance[P, T](validateT: T => Boolean, showT: T => String): Predicate[P, T] =
def instance[P, T](isValidF: T => Boolean, showF: T => String, constant: Boolean = false): Predicate[P, T] =
new Predicate[P, T] {
def isValid(t: T): Boolean = validateT(t)
def show(t: T): String = showT(t)
def isValid(t: T): Boolean = isValidF(t)
def show(t: T): String = showF(t)
override val isConstant: Boolean = constant
}

def constant[P, T](isValidV: Boolean, showV: String): Predicate[P, T] =
new Predicate[P, T] {
def isValid(t: T): Boolean = isValidV
def show(t: T): String = showV
override val isConstant: Boolean = true
}

/**
Expand All @@ -79,9 +90,9 @@ object Predicate {

/** Returns a [[Predicate]] that ignores its inputs and always yields `true`. */
def alwaysValid[P, T]: Predicate[P, T] =
instance(_ => true, _ => "true")
constant(isValidV = true, "true")

/** Returns a [[Predicate]] that ignores its inputs and always yields `false`. */
def alwaysInvalid[P, T]: Predicate[P, T] =
instance(_ => false, _ => "false")
constant(isValidV = false, "false")
}
16 changes: 14 additions & 2 deletions shared/src/main/scala/eu/timepit/refined/boolean.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ private[refined] trait BooleanPredicates {
case Some(_) => None
case None => Some(s"Predicate ${p.show(t)} did not fail.")
}

override val isConstant: Boolean = p.isConstant
}

implicit def andPredicate[A, B, T](implicit pa: Predicate[A, T], pb: Predicate[B, T]): Predicate[A And B, T] =
Expand All @@ -69,6 +71,8 @@ private[refined] trait BooleanPredicates {
Some(s"Right predicate of ${show(t)} failed: $sr")
case _ => None
}

override val isConstant: Boolean = pa.isConstant && pb.isConstant
}

implicit def orPredicate[A, B, T](implicit pa: Predicate[A, T], pb: Predicate[B, T]): Predicate[A Or B, T] =
Expand All @@ -82,6 +86,8 @@ private[refined] trait BooleanPredicates {
Some(s"Both predicates of ${show(t)} failed. Left: $sl Right: $sr")
case _ => None
}

override val isConstant: Boolean = pa.isConstant && pb.isConstant
}

implicit def xorPredicate[A, B, T](implicit pa: Predicate[A, T], pb: Predicate[B, T]): Predicate[A Xor B, T] =
Expand All @@ -97,6 +103,8 @@ private[refined] trait BooleanPredicates {
Some(s"Both predicates of ${show(t)} succeeded.")
case _ => None
}

override val isConstant: Boolean = pa.isConstant && pb.isConstant
}

implicit def allOfHNilPredicate[T]: Predicate[AllOf[HNil], T] =
Expand All @@ -105,7 +113,8 @@ private[refined] trait BooleanPredicates {
implicit def allOfHConsPredicate[PH, PT <: HList, T](implicit ph: Predicate[PH, T], pt: Predicate[AllOf[PT], T]): Predicate[AllOf[PH :: PT], T] =
Predicate.instance(
t => ph.isValid(t) && pt.isValid(t),
t => s"(${ph.show(t)} && ${pt.show(t)})"
t => s"(${ph.show(t)} && ${pt.show(t)})",
ph.isConstant && pt.isConstant
)

implicit def anyOfHNilPredicate[T]: Predicate[AnyOf[HNil], T] =
Expand All @@ -114,7 +123,8 @@ private[refined] trait BooleanPredicates {
implicit def anyOfHConsPredicate[PH, PT <: HList, T](implicit ph: Predicate[PH, T], pt: Predicate[AnyOf[PT], T]): Predicate[AnyOf[PH :: PT], T] =
Predicate.instance(
t => ph.isValid(t) || pt.isValid(t),
t => s"(${ph.show(t)} || ${pt.show(t)})"
t => s"(${ph.show(t)} || ${pt.show(t)})",
ph.isConstant && pt.isConstant
)

implicit def oneOfHNilPredicate[T]: Predicate[OneOf[HNil], T] =
Expand All @@ -125,6 +135,8 @@ private[refined] trait BooleanPredicates {
def isValid(t: T): Boolean = accumulateIsValid(t).count(identity) == 1
def show(t: T): String = accumulateShow(t).mkString("oneOf(", ", ", ")")

override val isConstant: Boolean = ph.isConstant && pt.isConstant

override def accumulateIsValid(t: T): List[Boolean] =
ph.isValid(t) :: pt.accumulateIsValid(t)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ object RefineLit {
def macroImpl[P: c.WeakTypeTag, T: c.WeakTypeTag](c: blackbox.Context)(t: c.Expr[T])(p: c.Expr[Predicate[P, T]]): c.Expr[T @@ P] = {
import c.universe._

val litValue: T = t.tree match {
val predicate: Predicate[P, T] = MacroUtils.eval(c)(p)

val tValue: T = t.tree match {
case Literal(Constant(value)) => value.asInstanceOf[T]
case _ if predicate.isConstant => null.asInstanceOf[T]
case _ => c.abort(c.enclosingPosition, "refineLit only supports literals")
}

val predicate: Predicate[P, T] = MacroUtils.eval(c)(p)
predicate.validate(litValue) match {
case None => c.Expr(q"$t.asInstanceOf[${weakTypeOf[T @@ P]}]")
predicate.validate(tValue) match {
case None =>
c.Expr(q"$t.asInstanceOf[${weakTypeOf[T @@ P]}]")
case Some(msg) => c.abort(c.enclosingPosition, msg)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ object RefineM {
def macroImpl[P: c.WeakTypeTag, T: c.WeakTypeTag](c: blackbox.Context)(t: c.Expr[T])(p: c.Expr[Predicate[P, T]]): c.Expr[Refined[T, P]] = {
import c.universe._

val litValue: T = t.tree match {
val predicate: Predicate[P, T] = MacroUtils.eval(c)(p)

val tValue: T = t.tree match {
case Literal(Constant(value)) => value.asInstanceOf[T]
case _ if predicate.isConstant => null.asInstanceOf[T]
case _ => c.abort(c.enclosingPosition, "refineM only supports literals")
}

val predicate: Predicate[P, T] = MacroUtils.eval(c)(p)
predicate.validate(litValue) match {
predicate.validate(tValue) match {
case None =>
c.Expr(q"_root_.eu.timepit.refined.Refined[${weakTypeOf[T]}, ${weakTypeOf[P]}]($t)")
case Some(msg) => c.abort(c.enclosingPosition, msg)
Expand Down

0 comments on commit a1859ee

Please sign in to comment.