Merge pull request #3666 from isaacl/anyvalSteroids
[WIP] Refactor lila implicits
This commit is contained in:
commit
22a3ec7781
|
@ -9,15 +9,7 @@ import play.twirl.api.Html
|
|||
import lila.api.Env.{ current => apiEnv }
|
||||
|
||||
object Environment
|
||||
extends scalaz.syntax.ToIdOps
|
||||
with scalaz.std.OptionInstances
|
||||
with scalaz.std.OptionFunctions
|
||||
with scalaz.std.StringInstances
|
||||
with scalaz.syntax.std.ToOptionIdOps
|
||||
with scalalib.OrnicarMonoid.Instances
|
||||
with scalalib.Zero.Instances
|
||||
with scalalib.OrnicarOption
|
||||
with lila.LilaSteroids
|
||||
extends lila.Steroids
|
||||
with StringHelper
|
||||
with JsonHelper
|
||||
with AssetHelper
|
||||
|
|
69
modules/common/src/main/Lilaisms.scala
Normal file
69
modules/common/src/main/Lilaisms.scala
Normal file
|
@ -0,0 +1,69 @@
|
|||
package lila
|
||||
|
||||
import scala.util.Try
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import ornicar.scalalib
|
||||
import ornicar.scalalib.Zero
|
||||
import org.joda.time.DateTime
|
||||
import com.typesafe.config.Config
|
||||
import play.api.libs.json.{ JsObject, JsValue }
|
||||
import lila.common.implicits._
|
||||
|
||||
trait Lilaisms
|
||||
extends scalalib.Common
|
||||
with lila.common.base.LilaTypes
|
||||
with scalalib.OrnicarMonoid.Instances
|
||||
with scalalib.OrnicarNonEmptyList
|
||||
with scalalib.OrnicarOption
|
||||
with scalalib.Regex
|
||||
with scalalib.Validation
|
||||
with scalalib.Zero.Instances
|
||||
with scalalib.Zero.Syntax
|
||||
with scalaz.std.ListFunctions
|
||||
with scalaz.std.ListInstances
|
||||
with scalaz.std.OptionFunctions
|
||||
with scalaz.std.OptionInstances
|
||||
with scalaz.std.StringInstances
|
||||
with scalaz.std.TupleInstances
|
||||
with scalaz.syntax.std.ToListOps
|
||||
with scalaz.syntax.std.ToOptionIdOps
|
||||
with scalaz.syntax.ToApplyOps
|
||||
with scalaz.syntax.ToEqualOps
|
||||
with scalaz.syntax.ToFunctorOps
|
||||
with scalaz.syntax.ToIdOps
|
||||
with scalaz.syntax.ToMonoidOps
|
||||
with scalaz.syntax.ToShowOps
|
||||
with scalaz.syntax.ToTraverseOps
|
||||
with scalaz.syntax.ToValidationOps {
|
||||
|
||||
@inline implicit def toPimpedFuture[A](f: Fu[A]) = new PimpedFuture(f)
|
||||
@inline implicit def toPimpedFutureBoolean(f: Fu[Boolean]) = new PimpedFutureBoolean(f)
|
||||
@inline implicit def toPimpedFutureOption[A](f: Fu[Option[A]]) = new PimpedFutureOption(f)
|
||||
@inline implicit def toPimpedFutureValid[A](f: Fu[Valid[A]]) = new PimpedFutureValid(f)
|
||||
|
||||
@inline implicit def toPimpedJsObject(jo: JsObject) = new PimpedJsObject(jo)
|
||||
@inline implicit def toPimpedJsValue(jv: JsValue) = new PimpedJsValue(jv)
|
||||
|
||||
@inline implicit def toPimpedBoolean(b: Boolean) = new PimpedBoolean(b)
|
||||
@inline implicit def toPimpedInt(i: Int) = new PimpedInt(i)
|
||||
@inline implicit def toPimpedLong(l: Long) = new PimpedLong(l)
|
||||
@inline implicit def toPimpedFloat(f: Float) = new PimpedFloat(f)
|
||||
@inline implicit def toPimpedDouble(d: Double) = new PimpedDouble(d)
|
||||
|
||||
@inline implicit def toPimpedTryList[A](l: List[Try[A]]) = new PimpedTryList(l)
|
||||
@inline implicit def toPimpedList[A](l: List[A]) = new PimpedList(l)
|
||||
@inline implicit def toPimpedSeq[A](l: List[A]) = new PimpedSeq(l)
|
||||
@inline implicit def toPimpedByteArray(ba: Array[Byte]) = new PimpedByteArray(ba)
|
||||
|
||||
@inline implicit def toPimpedOption[A](a: Option[A]) = new PimpedOption(a)
|
||||
@inline implicit def toPimpedString(s: String) = new PimpedString(s)
|
||||
@inline implicit def toPimpedConfig(c: Config) = new PimpedConfig(c)
|
||||
@inline implicit def toPimpedDateTime(d: DateTime) = new PimpedDateTime(d)
|
||||
@inline implicit def toPimpedValid[A](v: Valid[A]) = new PimpedValid(v)
|
||||
@inline implicit def toPimpedTry[A](t: Try[A]) = new PimpedTry(t)
|
||||
@inline implicit def toPimpedFiniteDuration(d: FiniteDuration) = new PimpedFiniteDuration(d)
|
||||
|
||||
implicit val dateTimeOrdering: Ordering[DateTime] = Ordering.fromLessThan(_ isBefore _)
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
package lila
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration, MILLISECONDS }
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.Future
|
||||
import scala.util.Try
|
||||
|
||||
import ornicar.scalalib
|
||||
|
||||
import scalaz.{ Monad, Monoid, OptionT, ~> }
|
||||
|
||||
trait PackageObject extends Steroids with WithFuture {
|
||||
trait PackageObject extends Lilaisms {
|
||||
|
||||
// case object Key(value: String) extends AnyVal with StringValue
|
||||
trait StringValue extends Any {
|
||||
|
@ -37,46 +39,14 @@ trait PackageObject extends Steroids with WithFuture {
|
|||
def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x)
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedString(s: String) {
|
||||
def parseIntOption(str: String): Option[Int] =
|
||||
Try(java.lang.Integer.parseInt(str)).toOption
|
||||
|
||||
def boot[A](v: => A): A = lila.common.Chronometer.syncEffect(v) { lap =>
|
||||
lila.log.boot.info(s"${lap.millis}ms $s")
|
||||
}
|
||||
}
|
||||
def parseFloatOption(str: String): Option[Float] =
|
||||
Try(java.lang.Float.parseFloat(str)).toOption
|
||||
|
||||
implicit final class LilaPimpedValid[A](v: Valid[A]) {
|
||||
|
||||
def future: Fu[A] = v fold (errs => fufail(errs.shows), fuccess)
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedTry[A](v: scala.util.Try[A]) {
|
||||
|
||||
def fold[B](fe: Exception => B, fa: A => B): B = v match {
|
||||
case scala.util.Failure(e: Exception) => fe(e)
|
||||
case scala.util.Failure(e) => throw e
|
||||
case scala.util.Success(a) => fa(a)
|
||||
}
|
||||
|
||||
def future: Fu[A] = fold(Future.failed, fuccess)
|
||||
}
|
||||
|
||||
def parseIntOption(str: String): Option[Int] = try {
|
||||
Some(java.lang.Integer.parseInt(str))
|
||||
} catch {
|
||||
case e: NumberFormatException => None
|
||||
}
|
||||
|
||||
def parseFloatOption(str: String): Option[Float] = try {
|
||||
Some(java.lang.Float.parseFloat(str))
|
||||
} catch {
|
||||
case e: NumberFormatException => None
|
||||
}
|
||||
|
||||
def parseLongOption(str: String): Option[Long] = try {
|
||||
Some(java.lang.Long.parseLong(str))
|
||||
} catch {
|
||||
case e: NumberFormatException => None
|
||||
}
|
||||
def parseLongOption(str: String): Option[Long] =
|
||||
Try(java.lang.Long.parseLong(str)).toOption
|
||||
|
||||
def intBox(in: Range.Inclusive)(v: Int): Int =
|
||||
math.max(in.start, math.min(v, in.end))
|
||||
|
@ -88,25 +58,13 @@ trait PackageObject extends Steroids with WithFuture {
|
|||
math.max(in.start, math.min(v, in.end))
|
||||
}
|
||||
|
||||
trait WithFuture extends scalalib.Validation {
|
||||
|
||||
type Fu[+A] = Future[A]
|
||||
type Funit = Fu[Unit]
|
||||
|
||||
def fuccess[A](a: A) = Future successful a
|
||||
def fufail[A <: Throwable, B](a: A): Fu[B] = Future failed a
|
||||
def fufail[A](a: String): Fu[A] = fufail(common.LilaException(a))
|
||||
def fufail[A](a: Failures): Fu[A] = fufail(common.LilaException(a))
|
||||
val funit = fuccess(())
|
||||
}
|
||||
|
||||
trait WithPlay { self: PackageObject =>
|
||||
|
||||
import play.api.libs.json._
|
||||
import scalalib.Zero
|
||||
import ornicar.scalalib.Zero
|
||||
|
||||
implicit def playExecutionContext = play.api.libs.concurrent.Execution.defaultContext
|
||||
val directEC = lila.PimpedFuture.DirectExecutionContext
|
||||
val directEC = lila.common.implicits.DirectExecutionContext
|
||||
|
||||
implicit val LilaFutureMonad = new Monad[Fu] {
|
||||
override def map[A, B](fa: Fu[A])(f: A => B) = fa map f
|
||||
|
@ -134,72 +92,11 @@ trait WithPlay { self: PackageObject =>
|
|||
Future sequence t
|
||||
}
|
||||
|
||||
implicit def LilaPimpedFuture[A](fua: Fu[A]): PimpedFuture.LilaPimpedFuture[A] =
|
||||
new PimpedFuture.LilaPimpedFuture(fua)
|
||||
|
||||
implicit final class LilaPimpedFutureZero[A: Zero](fua: Fu[A]) {
|
||||
|
||||
def nevermind: Fu[A] = fua recover {
|
||||
case e: lila.common.LilaException => zero[A]
|
||||
case e: java.util.concurrent.TimeoutException => zero[A]
|
||||
case e: Exception =>
|
||||
lila.log("common").warn("Future.nevermind", e)
|
||||
zero[A]
|
||||
}
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedFutureOption[A](fua: Fu[Option[A]]) {
|
||||
|
||||
def flatten(msg: => String): Fu[A] = fua flatMap {
|
||||
_.fold[Fu[A]](fufail(msg))(fuccess(_))
|
||||
}
|
||||
|
||||
def orElse(other: => Fu[Option[A]]): Fu[Option[A]] = fua flatMap {
|
||||
_.fold(other) { x => fuccess(x.some) }
|
||||
}
|
||||
|
||||
def getOrElse(other: => Fu[A]): Fu[A] = fua flatMap { _.fold(other)(fuccess) }
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedFutureValid[A](fua: Fu[Valid[A]]) {
|
||||
|
||||
def flatten: Fu[A] = fua flatMap { _.fold[Fu[A]](fufail(_), fuccess(_)) }
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedFutureBoolean(fua: Fu[Boolean]) {
|
||||
|
||||
def >>&(fub: => Fu[Boolean]): Fu[Boolean] =
|
||||
fua flatMap { _.fold(fub, fuccess(false)) }
|
||||
|
||||
def >>|(fub: => Fu[Boolean]): Fu[Boolean] =
|
||||
fua flatMap { _.fold(fuccess(true), fub) }
|
||||
|
||||
def unary_! = fua dmap (!_)
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedBooleanWithFuture(self: Boolean) {
|
||||
|
||||
def optionFu[A](v: => Fu[A]): Fu[Option[A]] = if (self) v map (_.some) else fuccess(none)
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedActorSystem(self: akka.actor.ActorSystem) {
|
||||
|
||||
def lilaBus = lila.common.Bus(self)
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedFiniteDuration(self: FiniteDuration) {
|
||||
|
||||
def toCentis = chess.Centis {
|
||||
// divide by Double, then round, to avoid rounding issues with just `/10`!
|
||||
math.round {
|
||||
if (self.unit eq MILLISECONDS) self.length / 10d
|
||||
else self.toMillis / 10d
|
||||
}
|
||||
}
|
||||
|
||||
def abs = if (self.length < 0) -self else self
|
||||
}
|
||||
|
||||
implicit val LilaFiniteDurationZero: Zero[FiniteDuration] = Zero.instance(Duration.Zero)
|
||||
|
||||
implicit val LilaCentisZero: Zero[chess.Centis] = Zero instance chess.Centis(0)
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package lila.common
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import com.typesafe.config.Config
|
||||
|
||||
object PimpedConfig {
|
||||
|
||||
implicit final class LilaPimpedConfig(val config: Config) extends AnyVal {
|
||||
|
||||
def millis(name: String): Int = config.getDuration(name, TimeUnit.MILLISECONDS).toInt
|
||||
def seconds(name: String): Int = config.getDuration(name, TimeUnit.SECONDS).toInt
|
||||
def duration(name: String): FiniteDuration = millis(name).millis
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
package lila
|
||||
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.{ Future, ExecutionContext }
|
||||
|
||||
object PimpedFuture {
|
||||
|
||||
private type Fu[A] = Future[A]
|
||||
|
||||
object DirectExecutionContext extends ExecutionContext {
|
||||
override def execute(command: Runnable): Unit = command.run()
|
||||
override def reportFailure(cause: Throwable): Unit =
|
||||
throw new IllegalStateException("lila DirectExecutionContext failure", cause)
|
||||
}
|
||||
|
||||
final class LilaPimpedFuture[A](val fua: Fu[A]) extends AnyVal {
|
||||
|
||||
def dmap[B](f: A => B): Fu[B] = fua.map(f)(DirectExecutionContext)
|
||||
def dforeach[B](f: A => Unit): Unit = fua.foreach(f)(DirectExecutionContext)
|
||||
|
||||
def >>-(sideEffect: => Unit): Fu[A] = fua andThen {
|
||||
case _ => sideEffect
|
||||
}
|
||||
|
||||
def >>[B](fub: => Fu[B]): Fu[B] = fua flatMap (_ => fub)
|
||||
|
||||
def void: Fu[Unit] = fua.map(_ => ())(DirectExecutionContext)
|
||||
|
||||
def inject[B](b: => B): Fu[B] = fua.map(_ => b)(DirectExecutionContext)
|
||||
|
||||
def injectAnyway[B](b: => B): Fu[B] = fold(_ => b, _ => b)
|
||||
|
||||
def effectFold(fail: Exception => Unit, succ: A => Unit) {
|
||||
fua onComplete {
|
||||
case scala.util.Failure(e: Exception) => fail(e)
|
||||
case scala.util.Failure(e) => throw e // Throwables
|
||||
case scala.util.Success(e) => succ(e)
|
||||
}
|
||||
}
|
||||
|
||||
def fold[B](fail: Exception => B, succ: A => B): Fu[B] =
|
||||
fua map succ recover { case e: Exception => fail(e) }
|
||||
|
||||
def flatFold[B](fail: Exception => Fu[B], succ: A => Fu[B]): Fu[B] =
|
||||
fua flatMap succ recoverWith { case e: Exception => fail(e) }
|
||||
|
||||
def logFailure(logger: => lila.log.Logger, msg: Exception => String): Fu[A] =
|
||||
addFailureEffect { e => logger.warn(msg(e), e) }
|
||||
def logFailure(logger: => lila.log.Logger): Fu[A] = logFailure(logger, _.toString)
|
||||
|
||||
def addFailureEffect(effect: Exception => Unit) = {
|
||||
fua onFailure {
|
||||
case e: Exception => effect(e)
|
||||
}
|
||||
fua
|
||||
}
|
||||
|
||||
def addEffect(effect: A => Unit): Fu[A] = {
|
||||
fua foreach effect
|
||||
fua
|
||||
}
|
||||
|
||||
def addEffects(fail: Exception => Unit, succ: A => Unit): Fu[A] = {
|
||||
fua onComplete {
|
||||
case scala.util.Failure(e: Exception) => fail(e)
|
||||
case scala.util.Failure(e) => throw e // Throwables
|
||||
case scala.util.Success(e) => succ(e)
|
||||
}
|
||||
fua
|
||||
}
|
||||
|
||||
def addEffectAnyway(inAnyCase: => Unit): Fu[A] = {
|
||||
fua onComplete {
|
||||
case _ => inAnyCase
|
||||
}
|
||||
fua
|
||||
}
|
||||
|
||||
def mapFailure(f: Exception => Exception) = fua recover {
|
||||
case cause: Exception => throw f(cause)
|
||||
}
|
||||
|
||||
def prefixFailure(p: => String) = mapFailure { e =>
|
||||
common.LilaException(s"$p ${e.getMessage}")
|
||||
}
|
||||
|
||||
def thenPp: Fu[A] = {
|
||||
effectFold(
|
||||
e => println("[failure] " + e),
|
||||
a => println("[success] " + a)
|
||||
)
|
||||
fua
|
||||
}
|
||||
|
||||
def thenPp(msg: String): Fu[A] = {
|
||||
effectFold(
|
||||
e => println(s"[$msg] [failure] $e"),
|
||||
a => println(s"[$msg] [success] $a")
|
||||
)
|
||||
fua
|
||||
}
|
||||
|
||||
def await(duration: FiniteDuration): A =
|
||||
scala.concurrent.Await.result(fua, duration)
|
||||
|
||||
def awaitOrElse(duration: FiniteDuration, default: => A): A = try {
|
||||
scala.concurrent.Await.result(fua, duration)
|
||||
} catch {
|
||||
case _: Exception => default
|
||||
}
|
||||
|
||||
def awaitSeconds(seconds: Int): A =
|
||||
await(seconds.seconds)
|
||||
|
||||
def withTimeout(duration: FiniteDuration, error: => Throwable)(implicit system: akka.actor.ActorSystem): Fu[A] = {
|
||||
Future firstCompletedOf Seq(
|
||||
fua,
|
||||
akka.pattern.after(duration, system.scheduler)(Future failed error)
|
||||
)
|
||||
}
|
||||
|
||||
def withTimeoutDefault(duration: FiniteDuration, default: => A)(implicit system: akka.actor.ActorSystem): Fu[A] = {
|
||||
Future firstCompletedOf Seq(
|
||||
fua,
|
||||
akka.pattern.after(duration, system.scheduler)(Future(default))
|
||||
)
|
||||
}
|
||||
|
||||
def chronometer = lila.common.Chronometer(fua)
|
||||
|
||||
def mon(path: lila.mon.RecPath) = chronometer.mon(path).result
|
||||
}
|
||||
}
|
|
@ -4,9 +4,10 @@ import play.api.libs.json._
|
|||
|
||||
object PimpedJson {
|
||||
|
||||
def anyValWriter[O, A: Writes](f: O => A): Writes[O] = Writes[O] { o =>
|
||||
def anyValWriter[O, A: Writes](f: O => A) = Writes[O] { o =>
|
||||
Json toJson f(o)
|
||||
}
|
||||
|
||||
def intAnyValWriter[O](f: O => Int): Writes[O] = anyValWriter[O, Int](f)
|
||||
def stringAnyValWriter[O](f: O => String): Writes[O] = anyValWriter[O, String](f)
|
||||
|
||||
|
@ -14,85 +15,4 @@ object PimpedJson {
|
|||
def intIsoWriter[O](iso: Iso[Int, O]): Writes[O] = anyValWriter[O, Int](iso.to)
|
||||
|
||||
def stringIsoReader[O](iso: Iso[String, O]): Reads[O] = Reads.of[String] map iso.from
|
||||
|
||||
implicit final class LilaPimpedJsObject(val js: JsObject) extends AnyVal {
|
||||
|
||||
def str(key: String): Option[String] =
|
||||
(js \ key).asOpt[String]
|
||||
|
||||
def int(key: String): Option[Int] =
|
||||
(js \ key).asOpt[Int]
|
||||
|
||||
def long(key: String): Option[Long] =
|
||||
(js \ key).asOpt[Long]
|
||||
|
||||
def boolean(key: String): Option[Boolean] =
|
||||
(js \ key).asOpt[Boolean]
|
||||
|
||||
def obj(key: String): Option[JsObject] =
|
||||
(js \ key).asOpt[JsObject]
|
||||
|
||||
def arr(key: String): Option[JsArray] =
|
||||
(js \ key).asOpt[JsArray]
|
||||
|
||||
def arrAs[A](key: String)(as: JsValue => Option[A]): Option[List[A]] =
|
||||
arr(key) map { j =>
|
||||
(j.value.map(as)(scala.collection.breakOut): List[Option[A]]).flatten
|
||||
}
|
||||
|
||||
def ints(key: String): Option[List[Int]] = arrAs(key)(_.asOpt[Int])
|
||||
|
||||
def strs(key: String): Option[List[String]] = arrAs(key)(_.asOpt[String])
|
||||
|
||||
def objs(key: String): Option[List[JsObject]] = arrAs(key)(_.asOpt[JsObject])
|
||||
|
||||
def get[A: Reads](key: String): Option[A] =
|
||||
(js \ key).asOpt[A]
|
||||
|
||||
def noNull = JsObject {
|
||||
js.fields collect {
|
||||
case (key, value) if value != JsNull => key -> value
|
||||
}
|
||||
}
|
||||
|
||||
def add(pair: (String, Boolean)): JsObject =
|
||||
if (pair._2) js + (pair._1 -> JsBoolean(true))
|
||||
else js
|
||||
|
||||
def add[A: Writes](pair: (String, Option[A])): JsObject =
|
||||
pair._2.fold(js) { a => js + (pair._1 -> Json.toJson(a)) }
|
||||
}
|
||||
|
||||
implicit final class LilaPimpedJsValue(val js: JsValue) extends AnyVal {
|
||||
|
||||
def str(key: String): Option[String] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[String]
|
||||
}
|
||||
|
||||
def int(key: String): Option[Int] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[Int]
|
||||
}
|
||||
|
||||
def long(key: String): Option[Long] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[Long]
|
||||
}
|
||||
|
||||
def boolean(key: String): Option[Boolean] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[Boolean]
|
||||
}
|
||||
|
||||
def obj(key: String): Option[JsObject] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[JsObject]
|
||||
}
|
||||
|
||||
def arr(key: String): Option[JsArray] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[JsArray]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
package lila
|
||||
|
||||
import ornicar.scalalib
|
||||
import ornicar.scalalib.Zero
|
||||
import org.joda.time.DateTime
|
||||
import scala.util.Try
|
||||
|
||||
|
||||
trait Steroids
|
||||
|
||||
extends scalalib.Validation
|
||||
with scalalib.Common
|
||||
with scalalib.Regex
|
||||
with scalalib.OrnicarMonoid.Instances
|
||||
with scalalib.Zero.Syntax
|
||||
with scalalib.Zero.Instances
|
||||
with scalalib.OrnicarOption
|
||||
with scalalib.OrnicarNonEmptyList
|
||||
|
||||
with scalaz.std.OptionInstances
|
||||
with scalaz.std.OptionFunctions
|
||||
with scalaz.syntax.std.ToOptionIdOps
|
||||
|
||||
with scalaz.std.ListInstances
|
||||
with scalaz.std.ListFunctions
|
||||
with scalaz.syntax.std.ToListOps
|
||||
|
||||
with scalaz.std.StringInstances
|
||||
|
||||
with scalaz.std.TupleInstances
|
||||
|
||||
with scalaz.syntax.ToIdOps
|
||||
with scalaz.syntax.ToEqualOps
|
||||
with scalaz.syntax.ToApplyOps
|
||||
with scalaz.syntax.ToValidationOps
|
||||
with scalaz.syntax.ToFunctorOps
|
||||
with scalaz.syntax.ToMonoidOps
|
||||
with scalaz.syntax.ToTraverseOps
|
||||
with scalaz.syntax.ToShowOps
|
||||
|
||||
with LilaSteroids
|
||||
|
||||
trait LilaSteroids {
|
||||
import Wrappers._
|
||||
|
||||
@inline implicit def toLilaPimpedOption[A](a: Option[A]) = new LilaPimpedOption(a)
|
||||
@inline implicit def toLilaPimpedTryList[A](l: List[Try[A]]) = new LilaPimpedTryList(l)
|
||||
@inline implicit def toLilaPimpedList[A](l: List[A]) = new LilaPimpedList(l)
|
||||
@inline implicit def toLilaPimpedSeq[A](l: List[A]) = new LilaPimpedSeq(l)
|
||||
@inline implicit def toLilaPimpedDateTime(d: DateTime) = new LilaPimpedDateTime(d)
|
||||
@inline implicit def toLilaPimpedBoolean(b: Boolean) = new LilaPimpedBoolean(b)
|
||||
@inline implicit def toLilaPimpedInt(i: Int) = new LilaPimpedInt(i)
|
||||
@inline implicit def toLilaPimpedFloat(f: Float) = new LilaPimpedFloat(f)
|
||||
@inline implicit def toLilaPimpedDouble(d: Double) = new LilaPimpedDouble(d)
|
||||
@inline implicit def toLilaPimpedByteArray(ba: Array[Byte]) = new LilaPimpedByteArray(ba)
|
||||
|
||||
implicit val dateTimeOrdering: Ordering[DateTime] = Ordering.fromLessThan(_ isBefore _)
|
||||
}
|
||||
|
||||
object Wrappers {
|
||||
final class LilaPimpedDateTime(private val date: DateTime) extends AnyVal {
|
||||
def getSeconds: Long = date.getMillis / 1000
|
||||
def getCentis: Long = date.getMillis / 10
|
||||
}
|
||||
|
||||
final class LilaPimpedTryList[A](private val list: List[Try[A]]) extends AnyVal {
|
||||
def sequence: Try[List[A]] = (Try(List[A]()) /: list) {
|
||||
(a, b) => a flatMap (c => b map (d => d :: c))
|
||||
} map (_.reverse)
|
||||
}
|
||||
|
||||
final class LilaPimpedList[A](private val list: List[A]) extends AnyVal {
|
||||
def sortLike[B](other: List[B], f: A => B): List[A] = list.sortWith {
|
||||
case (x, y) => other.indexOf(f(x)) < other.indexOf(f(y))
|
||||
}
|
||||
}
|
||||
|
||||
final class LilaPimpedSeq[A](private val seq: Seq[A]) extends AnyVal {
|
||||
def has(a: A) = seq contains a
|
||||
}
|
||||
|
||||
/*
|
||||
* Replaces scalaz boolean ops
|
||||
* so ?? works on Zero and not Monoid
|
||||
*/
|
||||
final class LilaPimpedBoolean(private val self: Boolean) extends AnyVal {
|
||||
|
||||
def ??[A](a: => A)(implicit z: Zero[A]): A = if (self) a else Zero[A].zero
|
||||
|
||||
def !(f: => Unit) = if (self) f
|
||||
|
||||
def fold[A](t: => A, f: => A): A = if (self) t else f
|
||||
|
||||
def ?[X](t: => X) = new { def |(f: => X) = if (self) t else f }
|
||||
|
||||
def option[A](a: => A): Option[A] = if (self) Some(a) else None
|
||||
}
|
||||
|
||||
final class LilaPimpedInt(private val self: Int) extends AnyVal {
|
||||
|
||||
def atLeast(bottomValue: Int): Int = self max bottomValue
|
||||
|
||||
def atMost(topValue: Int): Int = self min topValue
|
||||
}
|
||||
|
||||
final class LilaPimpedFloat(private val self: Float) extends AnyVal {
|
||||
|
||||
def atLeast(bottomValue: Float): Float = self max bottomValue
|
||||
|
||||
def atMost(topValue: Float): Float = self min topValue
|
||||
}
|
||||
|
||||
final class LilaPimpedDouble(private val self: Double) extends AnyVal {
|
||||
|
||||
def atLeast(bottomValue: Double): Double = self max bottomValue
|
||||
|
||||
def atMost(topValue: Double): Double = self min topValue
|
||||
}
|
||||
|
||||
final class LilaPimpedByteArray(private val self: Array[Byte]) extends AnyVal {
|
||||
def toBase64 = java.util.Base64.getEncoder.encodeToString(self)
|
||||
}
|
||||
|
||||
/*
|
||||
* Replaces scalaz option ops
|
||||
* so ~ works on Zero and not Monoid
|
||||
*/
|
||||
final class LilaPimpedOption[A](private val self: Option[A]) extends AnyVal {
|
||||
|
||||
import scalaz.std.{ option => o }
|
||||
|
||||
def fold[X](some: A => X, none: => X): X = self match {
|
||||
case None => none
|
||||
case Some(a) => some(a)
|
||||
}
|
||||
|
||||
def |(a: => A): A = self getOrElse a
|
||||
|
||||
def unary_~(implicit z: Zero[A]): A = self getOrElse z.zero
|
||||
def orDefault(implicit z: Zero[A]): A = self getOrElse z.zero
|
||||
|
||||
def toSuccess[E](e: => E): scalaz.Validation[E, A] = o.toSuccess(self)(e)
|
||||
|
||||
def toFailure[B](b: => B): scalaz.Validation[A, B] = o.toFailure(self)(b)
|
||||
|
||||
def err(message: => String): A = self.getOrElse(sys.error(message))
|
||||
|
||||
def ifNone(n: => Unit): Unit = if (self.isEmpty) n
|
||||
|
||||
def has(a: A) = self contains a
|
||||
}
|
||||
}
|
18
modules/common/src/main/base/LilaTypes.scala
Normal file
18
modules/common/src/main/base/LilaTypes.scala
Normal file
|
@ -0,0 +1,18 @@
|
|||
package lila.common.base
|
||||
|
||||
import ornicar.scalalib
|
||||
import scala.concurrent.Future
|
||||
import lila.common.LilaException
|
||||
|
||||
trait LilaTypes extends scalalib.Validation {
|
||||
type Fu[+A] = Future[A]
|
||||
type Funit = Fu[Unit]
|
||||
|
||||
def fuccess[A](a: A) = Future successful a
|
||||
def fufail[A <: Throwable, B](a: A): Fu[B] = Future failed a
|
||||
def fufail[A](a: String): Fu[A] = fufail(LilaException(a))
|
||||
def fufail[A](a: Failures): Fu[A] = fufail(LilaException(a))
|
||||
val funit = fuccess(())
|
||||
}
|
||||
|
||||
object LilaTypes extends LilaTypes
|
169
modules/common/src/main/implicits/PimpedFutures.scala
Normal file
169
modules/common/src/main/implicits/PimpedFutures.scala
Normal file
|
@ -0,0 +1,169 @@
|
|||
package lila.common.implicits
|
||||
|
||||
import play.api.libs.concurrent.Execution.Implicits._
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.{ Future, ExecutionContext }
|
||||
import lila.common.base.LilaTypes._
|
||||
import ornicar.scalalib.Zero
|
||||
|
||||
object DirectExecutionContext extends ExecutionContext {
|
||||
override def execute(command: Runnable): Unit = command.run()
|
||||
override def reportFailure(cause: Throwable): Unit =
|
||||
throw new IllegalStateException("lila DirectExecutionContext failure", cause)
|
||||
}
|
||||
|
||||
final class PimpedFuture[A](private val fua: Fu[A]) extends AnyVal {
|
||||
private type Fu[A] = Future[A]
|
||||
|
||||
def dmap[B](f: A => B): Fu[B] = fua.map(f)(DirectExecutionContext)
|
||||
def dforeach[B](f: A => Unit): Unit = fua.foreach(f)(DirectExecutionContext)
|
||||
|
||||
def >>-(sideEffect: => Unit): Fu[A] = fua andThen {
|
||||
case _ => sideEffect
|
||||
}
|
||||
|
||||
def >>[B](fub: => Fu[B]): Fu[B] = fua flatMap (_ => fub)
|
||||
|
||||
def void: Fu[Unit] = fua.map(_ => ())(DirectExecutionContext)
|
||||
|
||||
def inject[B](b: => B): Fu[B] = fua.map(_ => b)(DirectExecutionContext)
|
||||
|
||||
def injectAnyway[B](b: => B): Fu[B] = fold(_ => b, _ => b)
|
||||
|
||||
def effectFold(fail: Exception => Unit, succ: A => Unit) {
|
||||
fua onComplete {
|
||||
case scala.util.Failure(e: Exception) => fail(e)
|
||||
case scala.util.Failure(e) => throw e // Throwables
|
||||
case scala.util.Success(e) => succ(e)
|
||||
}
|
||||
}
|
||||
|
||||
def fold[B](fail: Exception => B, succ: A => B): Fu[B] =
|
||||
fua map succ recover { case e: Exception => fail(e) }
|
||||
|
||||
def flatFold[B](fail: Exception => Fu[B], succ: A => Fu[B]): Fu[B] =
|
||||
fua flatMap succ recoverWith { case e: Exception => fail(e) }
|
||||
|
||||
def logFailure(logger: => lila.log.Logger, msg: Exception => String): Fu[A] =
|
||||
addFailureEffect { e => logger.warn(msg(e), e) }
|
||||
def logFailure(logger: => lila.log.Logger): Fu[A] = logFailure(logger, _.toString)
|
||||
|
||||
def addFailureEffect(effect: Exception => Unit) = {
|
||||
fua onFailure {
|
||||
case e: Exception => effect(e)
|
||||
}
|
||||
fua
|
||||
}
|
||||
|
||||
def addEffect(effect: A => Unit): Fu[A] = {
|
||||
fua foreach effect
|
||||
fua
|
||||
}
|
||||
|
||||
def addEffects(fail: Exception => Unit, succ: A => Unit): Fu[A] = {
|
||||
fua onComplete {
|
||||
case scala.util.Failure(e: Exception) => fail(e)
|
||||
case scala.util.Failure(e) => throw e // Throwables
|
||||
case scala.util.Success(e) => succ(e)
|
||||
}
|
||||
fua
|
||||
}
|
||||
|
||||
def addEffectAnyway(inAnyCase: => Unit): Fu[A] = {
|
||||
fua onComplete {
|
||||
case _ => inAnyCase
|
||||
}
|
||||
fua
|
||||
}
|
||||
|
||||
def mapFailure(f: Exception => Exception) = fua recover {
|
||||
case cause: Exception => throw f(cause)
|
||||
}
|
||||
|
||||
def prefixFailure(p: => String) = mapFailure { e =>
|
||||
lila.common.LilaException(s"$p ${e.getMessage}")
|
||||
}
|
||||
|
||||
def thenPp: Fu[A] = {
|
||||
effectFold(
|
||||
e => println("[failure] " + e),
|
||||
a => println("[success] " + a)
|
||||
)
|
||||
fua
|
||||
}
|
||||
|
||||
def thenPp(msg: String): Fu[A] = {
|
||||
effectFold(
|
||||
e => println(s"[$msg] [failure] $e"),
|
||||
a => println(s"[$msg] [success] $a")
|
||||
)
|
||||
fua
|
||||
}
|
||||
|
||||
def await(duration: FiniteDuration): A =
|
||||
scala.concurrent.Await.result(fua, duration)
|
||||
|
||||
def awaitOrElse(duration: FiniteDuration, default: => A): A = try {
|
||||
scala.concurrent.Await.result(fua, duration)
|
||||
} catch {
|
||||
case _: Exception => default
|
||||
}
|
||||
|
||||
def awaitSeconds(seconds: Int): A =
|
||||
await(seconds.seconds)
|
||||
|
||||
def withTimeout(duration: FiniteDuration, error: => Throwable)(implicit system: akka.actor.ActorSystem): Fu[A] = {
|
||||
Future firstCompletedOf Seq(
|
||||
fua,
|
||||
akka.pattern.after(duration, system.scheduler)(Future failed error)
|
||||
)
|
||||
}
|
||||
|
||||
def withTimeoutDefault(duration: FiniteDuration, default: => A)(implicit system: akka.actor.ActorSystem): Fu[A] = {
|
||||
Future firstCompletedOf Seq(
|
||||
fua,
|
||||
akka.pattern.after(duration, system.scheduler)(Future(default))
|
||||
)
|
||||
}
|
||||
|
||||
def chronometer = lila.common.Chronometer(fua)
|
||||
|
||||
def mon(path: lila.mon.RecPath) = chronometer.mon(path).result
|
||||
|
||||
def nevermind(implicit z: Zero[A]): Fu[A] = fua recover {
|
||||
case e: lila.common.LilaException => z.zero
|
||||
case e: java.util.concurrent.TimeoutException => z.zero
|
||||
case e: Exception =>
|
||||
lila.log("common").warn("Future.nevermind", e)
|
||||
z.zero
|
||||
}
|
||||
}
|
||||
|
||||
final class PimpedFutureBoolean(private val fua: Fu[Boolean]) extends AnyVal {
|
||||
|
||||
def >>&(fub: => Fu[Boolean]): Fu[Boolean] =
|
||||
fua flatMap { if (_) fub else fuccess(false) }
|
||||
|
||||
def >>|(fub: => Fu[Boolean]): Fu[Boolean] =
|
||||
fua flatMap { if (_) fuccess(true) else fub }
|
||||
|
||||
def unary_! = fua.map { !_ }(DirectExecutionContext)
|
||||
}
|
||||
|
||||
final class PimpedFutureOption[A](private val fua: Fu[Option[A]]) extends AnyVal {
|
||||
|
||||
def flatten(msg: => String): Fu[A] = fua flatMap {
|
||||
_.fold[Fu[A]](fufail(msg))(fuccess(_))
|
||||
}
|
||||
|
||||
def orElse(other: => Fu[Option[A]]): Fu[Option[A]] = fua flatMap {
|
||||
_.fold(other) { x => fuccess(Some(x)) }
|
||||
}
|
||||
|
||||
def getOrElse(other: => Fu[A]): Fu[A] = fua flatMap { _.fold(other)(fuccess) }
|
||||
}
|
||||
|
||||
final class PimpedFutureValid[A](private val fua: Fu[Valid[A]]) extends AnyVal {
|
||||
|
||||
def flatten: Fu[A] = fua flatMap { _.fold[Fu[A]](fufail(_), fuccess(_)) }
|
||||
}
|
84
modules/common/src/main/implicits/PimpedJsObjects.scala
Normal file
84
modules/common/src/main/implicits/PimpedJsObjects.scala
Normal file
|
@ -0,0 +1,84 @@
|
|||
package lila.common.implicits
|
||||
|
||||
import play.api.libs.json._
|
||||
|
||||
final class PimpedJsObject(private val js: JsObject) extends AnyVal {
|
||||
|
||||
def str(key: String): Option[String] =
|
||||
(js \ key).asOpt[String]
|
||||
|
||||
def int(key: String): Option[Int] =
|
||||
(js \ key).asOpt[Int]
|
||||
|
||||
def long(key: String): Option[Long] =
|
||||
(js \ key).asOpt[Long]
|
||||
|
||||
def boolean(key: String): Option[Boolean] =
|
||||
(js \ key).asOpt[Boolean]
|
||||
|
||||
def obj(key: String): Option[JsObject] =
|
||||
(js \ key).asOpt[JsObject]
|
||||
|
||||
def arr(key: String): Option[JsArray] =
|
||||
(js \ key).asOpt[JsArray]
|
||||
|
||||
def arrAs[A](key: String)(as: JsValue => Option[A]): Option[List[A]] =
|
||||
arr(key) map { j =>
|
||||
(j.value.map(as)(scala.collection.breakOut): List[Option[A]]).flatten
|
||||
}
|
||||
|
||||
def ints(key: String): Option[List[Int]] = arrAs(key)(_.asOpt[Int])
|
||||
|
||||
def strs(key: String): Option[List[String]] = arrAs(key)(_.asOpt[String])
|
||||
|
||||
def objs(key: String): Option[List[JsObject]] = arrAs(key)(_.asOpt[JsObject])
|
||||
|
||||
def get[A: Reads](key: String): Option[A] =
|
||||
(js \ key).asOpt[A]
|
||||
|
||||
def noNull = JsObject {
|
||||
js.fields collect {
|
||||
case (key, value) if value != JsNull => key -> value
|
||||
}
|
||||
}
|
||||
|
||||
def add(pair: (String, Boolean)): JsObject =
|
||||
if (pair._2) js + (pair._1 -> JsBoolean(true))
|
||||
else js
|
||||
|
||||
def add[A: Writes](pair: (String, Option[A])): JsObject =
|
||||
pair._2.fold(js) { a => js + (pair._1 -> Json.toJson(a)) }
|
||||
}
|
||||
|
||||
final class PimpedJsValue(private val js: JsValue) extends AnyVal {
|
||||
|
||||
def str(key: String): Option[String] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[String]
|
||||
}
|
||||
|
||||
def int(key: String): Option[Int] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[Int]
|
||||
}
|
||||
|
||||
def long(key: String): Option[Long] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[Long]
|
||||
}
|
||||
|
||||
def boolean(key: String): Option[Boolean] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[Boolean]
|
||||
}
|
||||
|
||||
def obj(key: String): Option[JsObject] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[JsObject]
|
||||
}
|
||||
|
||||
def arr(key: String): Option[JsArray] =
|
||||
js.asOpt[JsObject] flatMap { obj =>
|
||||
(obj \ key).asOpt[JsArray]
|
||||
}
|
||||
}
|
54
modules/common/src/main/implicits/PimpedPrimatives.scala
Normal file
54
modules/common/src/main/implicits/PimpedPrimatives.scala
Normal file
|
@ -0,0 +1,54 @@
|
|||
package lila.common.implicits
|
||||
|
||||
import java.lang.Math.{ min, max }
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
||||
import lila.common.base.LilaTypes._
|
||||
import ornicar.scalalib.Zero
|
||||
|
||||
final class PimpedBoolean(private val self: Boolean) extends AnyVal {
|
||||
/**
|
||||
* Replaces scalaz boolean ops
|
||||
* so ?? works on Zero and not Monoid
|
||||
*/
|
||||
def ??[A](a: => A)(implicit z: Zero[A]): A = if (self) a else z.zero
|
||||
|
||||
def !(f: => Unit) = if (self) f
|
||||
|
||||
def fold[A](t: => A, f: => A): A = if (self) t else f
|
||||
|
||||
def ?[X](t: => X) = new { def |(f: => X) = if (self) t else f }
|
||||
|
||||
def option[A](a: => A): Option[A] = if (self) Some(a) else None
|
||||
|
||||
def optionFu[A](v: => Fu[A])(implicit ec: ExecutionContext): Fu[Option[A]] =
|
||||
if (self) v map { Some(_) } else fuccess(None)
|
||||
}
|
||||
|
||||
final class PimpedLong(private val self: Long) extends AnyVal {
|
||||
|
||||
def atLeast(bottomValue: Long): Long = max(self, bottomValue)
|
||||
|
||||
def atMost(topValue: Long): Long = min(self, topValue)
|
||||
}
|
||||
|
||||
final class PimpedInt(private val self: Int) extends AnyVal {
|
||||
|
||||
def atLeast(bottomValue: Int): Int = max(self, bottomValue)
|
||||
|
||||
def atMost(topValue: Int): Int = min(self, topValue)
|
||||
}
|
||||
|
||||
final class PimpedFloat(private val self: Float) extends AnyVal {
|
||||
|
||||
def atLeast(bottomValue: Float): Float = max(self, bottomValue)
|
||||
|
||||
def atMost(topValue: Float): Float = min(self, topValue)
|
||||
}
|
||||
|
||||
final class PimpedDouble(private val self: Double) extends AnyVal {
|
||||
|
||||
def atLeast(bottomValue: Double): Double = max(self, bottomValue)
|
||||
|
||||
def atMost(topValue: Double): Double = min(self, topValue)
|
||||
}
|
22
modules/common/src/main/implicits/PimpedSeqs.scala
Normal file
22
modules/common/src/main/implicits/PimpedSeqs.scala
Normal file
|
@ -0,0 +1,22 @@
|
|||
package lila.common.implicits
|
||||
|
||||
import java.util.Base64
|
||||
import scala.util.Try
|
||||
|
||||
final class PimpedTryList[A](private val list: List[Try[A]]) extends AnyVal {
|
||||
def sequence: Try[List[A]] = Try(list map { _.get })
|
||||
}
|
||||
|
||||
final class PimpedList[A](private val list: List[A]) extends AnyVal {
|
||||
def sortLike[B](other: List[B], f: A => B): List[A] = list.sortWith {
|
||||
(x, y) => other.indexOf(f(x)) < other.indexOf(f(y))
|
||||
}
|
||||
}
|
||||
|
||||
final class PimpedSeq[A](private val seq: Seq[A]) extends AnyVal {
|
||||
def has(a: A) = seq contains a
|
||||
}
|
||||
|
||||
final class PimpedByteArray(private val self: Array[Byte]) extends AnyVal {
|
||||
def toBase64 = Base64.getEncoder.encodeToString(self)
|
||||
}
|
84
modules/common/src/main/implicits/PimpedUtils.scala
Normal file
84
modules/common/src/main/implicits/PimpedUtils.scala
Normal file
|
@ -0,0 +1,84 @@
|
|||
package lila.common.implicits
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.Future
|
||||
import scala.util.Try
|
||||
|
||||
import com.typesafe.config.Config
|
||||
import org.joda.time.DateTime
|
||||
import ornicar.scalalib.Zero
|
||||
import scalaz._
|
||||
import Scalaz._
|
||||
|
||||
import lila.common.base.LilaTypes._
|
||||
|
||||
final class PimpedOption[A](private val self: Option[A]) extends AnyVal {
|
||||
|
||||
import scalaz.std.{ option => o }
|
||||
|
||||
def fold[X](some: A => X, none: => X): X = self.fold(none)(some)
|
||||
|
||||
def |(a: => A): A = self getOrElse a
|
||||
|
||||
def unary_~(implicit z: Zero[A]): A = self getOrElse z.zero
|
||||
def orDefault(implicit z: Zero[A]): A = self getOrElse z.zero
|
||||
|
||||
def toSuccess[E](e: => E): scalaz.Validation[E, A] = o.toSuccess(self)(e)
|
||||
|
||||
def toFailure[B](b: => B): scalaz.Validation[A, B] = o.toFailure(self)(b)
|
||||
|
||||
def err(message: => String): A = self.getOrElse(sys.error(message))
|
||||
|
||||
def ifNone(n: => Unit): Unit = if (self.isEmpty) n
|
||||
|
||||
def has(a: A) = self contains a
|
||||
}
|
||||
|
||||
final class PimpedString(private val s: String) extends AnyVal {
|
||||
|
||||
def boot[A](v: => A): A = lila.common.Chronometer.syncEffect(v) { lap =>
|
||||
lila.log.boot.info(s"${lap.millis}ms $s")
|
||||
}
|
||||
}
|
||||
|
||||
final class PimpedConfig(private val config: Config) extends AnyVal {
|
||||
|
||||
def millis(name: String): Int = config.getDuration(name, TimeUnit.MILLISECONDS).toInt
|
||||
def seconds(name: String): Int = config.getDuration(name, TimeUnit.SECONDS).toInt
|
||||
def duration(name: String): FiniteDuration = millis(name).millis
|
||||
}
|
||||
|
||||
final class PimpedDateTime(private val date: DateTime) extends AnyVal {
|
||||
def getSeconds: Long = date.getMillis / 1000
|
||||
def getCentis: Long = date.getMillis / 10
|
||||
}
|
||||
|
||||
final class PimpedValid[A](private val v: Valid[A]) extends AnyVal {
|
||||
|
||||
def future: Fu[A] = v fold (errs => fufail(errs.shows), fuccess)
|
||||
}
|
||||
|
||||
final class PimpedTry[A](private val v: Try[A]) extends AnyVal {
|
||||
|
||||
def fold[B](fe: Exception => B, fa: A => B): B = v match {
|
||||
case scala.util.Failure(e: Exception) => fe(e)
|
||||
case scala.util.Failure(e) => throw e
|
||||
case scala.util.Success(a) => fa(a)
|
||||
}
|
||||
|
||||
def future: Fu[A] = fold(Future.failed, fuccess)
|
||||
}
|
||||
|
||||
final class PimpedFiniteDuration(private val d: FiniteDuration) extends AnyVal {
|
||||
|
||||
def toCentis = chess.Centis {
|
||||
// divide by Double, then round, to avoid rounding issues with just `/10`!
|
||||
math.round {
|
||||
if (d.unit eq MILLISECONDS) d.length / 10d
|
||||
else d.toMillis / 10d
|
||||
}
|
||||
}
|
||||
|
||||
def abs = if (d.length < 0) -d else d
|
||||
}
|
Loading…
Reference in a new issue