summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library/scala/concurrent/duration/Deadline.scala80
-rw-r--r--src/library/scala/concurrent/duration/Duration.scala172
-rw-r--r--src/library/scala/concurrent/duration/DurationConversions.scala86
-rw-r--r--src/library/scala/concurrent/duration/package.scala58
-rw-r--r--src/library/scala/concurrent/impl/Promise.scala12
-rw-r--r--test/files/jvm/duration-tck.scala19
6 files changed, 221 insertions, 206 deletions
diff --git a/src/library/scala/concurrent/duration/Deadline.scala b/src/library/scala/concurrent/duration/Deadline.scala
new file mode 100644
index 0000000000..beeedec7bc
--- /dev/null
+++ b/src/library/scala/concurrent/duration/Deadline.scala
@@ -0,0 +1,80 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.concurrent.duration
+
+/**
+ * This class stores a deadline, as obtained via `Deadline.now` or the
+ * duration DSL:
+ *
+ * {{{
+ * import scala.concurrent.duration._
+ * 3.seconds.fromNow
+ * }}}
+ *
+ * Its main purpose is to manage repeated attempts to achieve something (like
+ * awaiting a condition) by offering the methods `hasTimeLeft` and `timeLeft`. All
+ * durations are measured according to `System.nanoTime` aka wall-time; this
+ * does not take into account changes to the system clock (such as leap
+ * seconds).
+ */
+case class Deadline private (time: FiniteDuration) extends Ordered[Deadline] {
+ /**
+ * Return a deadline advanced (i.e. moved into the future) by the given duration.
+ */
+ def +(other: FiniteDuration): Deadline = copy(time = time + other)
+ /**
+ * Return a deadline moved backwards (i.e. towards the past) by the given duration.
+ */
+ def -(other: FiniteDuration): Deadline = copy(time = time - other)
+ /**
+ * Calculate time difference between this and the other deadline, where the result is directed (i.e. may be negative).
+ */
+ def -(other: Deadline): FiniteDuration = time - other.time
+ /**
+ * Calculate time difference between this duration and now; the result is negative if the deadline has passed.
+ *
+ * '''''Note that on some systems this operation is costly because it entails a system call.'''''
+ * Check `System.nanoTime` for your platform.
+ */
+ def timeLeft: FiniteDuration = this - Deadline.now
+ /**
+ * Determine whether the deadline still lies in the future at the point where this method is called.
+ *
+ * '''''Note that on some systems this operation is costly because it entails a system call.'''''
+ * Check `System.nanoTime` for your platform.
+ */
+ def hasTimeLeft(): Boolean = !isOverdue()
+ /**
+ * Determine whether the deadline lies in the past at the point where this method is called.
+ *
+ * '''''Note that on some systems this operation is costly because it entails a system call.'''''
+ * Check `System.nanoTime` for your platform.
+ */
+ def isOverdue(): Boolean = (time.toNanos - System.nanoTime()) < 0
+ /**
+ * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration.
+ */
+ def compare(other: Deadline) = time compare other.time
+}
+
+object Deadline {
+ /**
+ * Construct a deadline due exactly at the point where this method is called. Useful for then
+ * advancing it to obtain a future deadline, or for sampling the current time exactly once and
+ * then comparing it to multiple deadlines (using subtraction).
+ */
+ def now: Deadline = Deadline(Duration(System.nanoTime, NANOSECONDS))
+
+ /**
+ * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration.
+ */
+ implicit object DeadlineIsOrdered extends Ordering[Deadline] {
+ def compare(a: Deadline, b: Deadline) = a compare b
+ }
+}
diff --git a/src/library/scala/concurrent/duration/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala
index 273b6934d6..81efc5c117 100644
--- a/src/library/scala/concurrent/duration/Duration.scala
+++ b/src/library/scala/concurrent/duration/Duration.scala
@@ -8,82 +8,9 @@
package scala.concurrent.duration
-import java.util.concurrent.TimeUnit
-import TimeUnit._
import java.lang.{ Double => JDouble, Long => JLong }
import scala.language.implicitConversions
-/**
- * This class stores a deadline, as obtained via `Deadline.now` or the
- * duration DSL:
- *
- * {{{
- * import scala.concurrent.util.duration._
- * 3.seconds.fromNow
- * }}}
- *
- * Its main purpose is to manage repeated attempts to achieve something (like
- * awaiting a condition) by offering the methods `hasTimeLeft` and `timeLeft`. All
- * durations are measured according to `System.nanoTime` aka wall-time; this
- * does not take into account changes to the system clock (such as leap
- * seconds).
- */
-case class Deadline private (time: FiniteDuration) extends Ordered[Deadline] {
- /**
- * Return a deadline advanced (i.e. moved into the future) by the given duration.
- */
- def +(other: FiniteDuration): Deadline = copy(time = time + other)
- /**
- * Return a deadline moved backwards (i.e. towards the past) by the given duration.
- */
- def -(other: FiniteDuration): Deadline = copy(time = time - other)
- /**
- * Calculate time difference between this and the other deadline, where the result is directed (i.e. may be negative).
- */
- def -(other: Deadline): FiniteDuration = time - other.time
- /**
- * Calculate time difference between this duration and now; the result is negative if the deadline has passed.
- *
- * '''''Note that on some systems this operation is costly because it entails a system call.'''''
- * Check `System.nanoTime` for your platform.
- */
- def timeLeft: FiniteDuration = this - Deadline.now
- /**
- * Determine whether the deadline still lies in the future at the point where this method is called.
- *
- * '''''Note that on some systems this operation is costly because it entails a system call.'''''
- * Check `System.nanoTime` for your platform.
- */
- def hasTimeLeft(): Boolean = !isOverdue()
- /**
- * Determine whether the deadline lies in the past at the point where this method is called.
- *
- * '''''Note that on some systems this operation is costly because it entails a system call.'''''
- * Check `System.nanoTime` for your platform.
- */
- def isOverdue(): Boolean = (time.toNanos - System.nanoTime()) < 0
- /**
- * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration.
- */
- def compare(other: Deadline) = time compare other.time
-}
-
-object Deadline {
- /**
- * Construct a deadline due exactly at the point where this method is called. Useful for then
- * advancing it to obtain a future deadline, or for sampling the current time exactly once and
- * then comparing it to multiple deadlines (using subtraction).
- */
- def now: Deadline = Deadline(Duration(System.nanoTime, NANOSECONDS))
-
- /**
- * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration.
- */
- implicit object DeadlineIsOrdered extends Ordering[Deadline] {
- def compare(a: Deadline, b: Deadline) = a compare b
- }
-}
-
object Duration {
/**
* This implicit conversion allows the use of a Deadline in place of a Duration, which will
@@ -380,8 +307,7 @@ object Duration {
* <p/>
* Examples:
* {{{
- * import scala.concurrent.util.Duration
- * import java.util.concurrent.TimeUnit
+ * import scala.concurrent.duration._
*
* val duration = Duration(100, MILLISECONDS)
* val duration = Duration(100, "millis")
@@ -396,7 +322,7 @@ object Duration {
* <p/>
* Implicits are also provided for Int, Long and Double. Example usage:
* {{{
- * import scala.concurrent.util.Duration._
+ * import scala.concurrent.duration._
*
* val duration = 100 millis
* }}}
@@ -772,97 +698,3 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio
}
override def hashCode = toNanos.toInt
}
-
-trait DurationConversions extends Any {
- protected def durationIn(unit: TimeUnit): FiniteDuration
-
- def nanoseconds = durationIn(NANOSECONDS)
- def nanos = nanoseconds
- def nanosecond = nanoseconds
- def nano = nanoseconds
-
- def microseconds = durationIn(MICROSECONDS)
- def micros = microseconds
- def microsecond = microseconds
- def micro = microseconds
-
- def milliseconds = durationIn(MILLISECONDS)
- def millis = milliseconds
- def millisecond = milliseconds
- def milli = milliseconds
-
- def seconds = durationIn(SECONDS)
- def second = seconds
-
- def minutes = durationIn(MINUTES)
- def minute = minutes
-
- def hours = durationIn(HOURS)
- def hour = hours
-
- def days = durationIn(DAYS)
- def day = days
-
- def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(nanoseconds)
- def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c)
- def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c)
- def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c)
-
- def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(microseconds)
- def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c)
- def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c)
- def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c)
-
- def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(milliseconds)
- def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c)
- def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c)
- def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c)
-
- def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(seconds)
- def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = seconds(c)
-
- def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(minutes)
- def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = minutes(c)
-
- def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(hours)
- def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = hours(c)
-
- def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(days)
- def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = days(c)
-}
-
-final class DurationInt(val n: Int) extends AnyVal with DurationConversions {
- override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit)
-}
-
-final class DurationLong(val n: Long) extends AnyVal with DurationConversions {
- override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit)
-}
-
-final class DurationDouble(val d: Double) extends AnyVal with DurationConversions {
- override protected def durationIn(unit: TimeUnit): FiniteDuration =
- Duration(d, unit) match {
- case f: FiniteDuration => f
- case _ => throw new IllegalArgumentException("Duration DSL not applicable to " + d)
- }
-}
-
-trait Classifier[C] {
- type R
- def convert(d: FiniteDuration): R
-}
-
-/*
- * Avoid reflection based invocation by using non-duck type
- */
-protected[duration] class IntMult(i: Int) {
- def *(d: Duration) = d * i
-}
-
-protected[duration] class LongMult(i: Long) {
- def *(d: Duration) = d * i
-}
-
-protected[duration] class DoubleMult(f: Double) {
- def *(d: Duration) = d * f
-}
diff --git a/src/library/scala/concurrent/duration/DurationConversions.scala b/src/library/scala/concurrent/duration/DurationConversions.scala
new file mode 100644
index 0000000000..14f26e05b2
--- /dev/null
+++ b/src/library/scala/concurrent/duration/DurationConversions.scala
@@ -0,0 +1,86 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.concurrent.duration
+
+import DurationConversions._
+
+// Would be nice to limit the visibility of this trait a little bit,
+// but it crashes scalac to do so.
+trait DurationConversions extends Any {
+ protected def durationIn(unit: TimeUnit): FiniteDuration
+
+ def nanoseconds = durationIn(NANOSECONDS)
+ def nanos = nanoseconds
+ def nanosecond = nanoseconds
+ def nano = nanoseconds
+
+ def microseconds = durationIn(MICROSECONDS)
+ def micros = microseconds
+ def microsecond = microseconds
+ def micro = microseconds
+
+ def milliseconds = durationIn(MILLISECONDS)
+ def millis = milliseconds
+ def millisecond = milliseconds
+ def milli = milliseconds
+
+ def seconds = durationIn(SECONDS)
+ def second = seconds
+
+ def minutes = durationIn(MINUTES)
+ def minute = minutes
+
+ def hours = durationIn(HOURS)
+ def hour = hours
+
+ def days = durationIn(DAYS)
+ def day = days
+
+ def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(nanoseconds)
+ def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c)
+ def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c)
+ def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c)
+
+ def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(microseconds)
+ def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c)
+ def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c)
+ def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c)
+
+ def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(milliseconds)
+ def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c)
+ def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c)
+ def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c)
+
+ def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(seconds)
+ def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = seconds(c)
+
+ def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(minutes)
+ def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = minutes(c)
+
+ def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(hours)
+ def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = hours(c)
+
+ def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(days)
+ def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = days(c)
+}
+
+object DurationConversions {
+ trait Classifier[C] {
+ type R
+ def convert(d: FiniteDuration): R
+ }
+ implicit object spanConvert extends Classifier[span.type] {
+ type R = FiniteDuration
+ def convert(d: FiniteDuration) = d
+ }
+ implicit object fromNowConvert extends Classifier[fromNow.type] {
+ type R = Deadline
+ def convert(d: FiniteDuration) = Deadline.now + d
+ }
+}
diff --git a/src/library/scala/concurrent/duration/package.scala b/src/library/scala/concurrent/duration/package.scala
index 31f222c3a2..1a62a01b03 100644
--- a/src/library/scala/concurrent/duration/package.scala
+++ b/src/library/scala/concurrent/duration/package.scala
@@ -1,31 +1,53 @@
package scala.concurrent
-import java.util.concurrent.TimeUnit
import scala.language.implicitConversions
package object duration {
-
+ // FIXME - these need documenting.
object span
- implicit object spanConvert extends Classifier[span.type] {
- type R = FiniteDuration
- def convert(d: FiniteDuration) = d
+ object fromNow
+
+ type TimeUnit = java.util.concurrent.TimeUnit
+ final val DAYS = java.util.concurrent.TimeUnit.DAYS
+ final val HOURS = java.util.concurrent.TimeUnit.HOURS
+ final val MICROSECONDS = java.util.concurrent.TimeUnit.MICROSECONDS
+ final val MILLISECONDS = java.util.concurrent.TimeUnit.MILLISECONDS
+ final val MINUTES = java.util.concurrent.TimeUnit.MINUTES
+ final val NANOSECONDS = java.util.concurrent.TimeUnit.NANOSECONDS
+ final val SECONDS = java.util.concurrent.TimeUnit.SECONDS
+
+ implicit def pairIntToDuration(p: (Int, TimeUnit)): Duration = Duration(p._1, p._2)
+ implicit def pairLongToDuration(p: (Long, TimeUnit)): FiniteDuration = Duration(p._1, p._2)
+ implicit def durationToPair(d: Duration): (Long, TimeUnit) = (d.length, d.unit)
+
+ implicit final class DurationInt(val n: Int) extends AnyVal with DurationConversions {
+ override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit)
}
- object fromNow
- implicit object fromNowConvert extends Classifier[fromNow.type] {
- type R = Deadline
- def convert(d: FiniteDuration) = Deadline.now + d
+ implicit final class DurationLong(val n: Long) extends AnyVal with DurationConversions {
+ override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit)
}
- implicit def intToDurationInt(n: Int) = new DurationInt(n)
- implicit def longToDurationLong(n: Long) = new DurationLong(n)
- implicit def doubleToDurationDouble(d: Double) = new DurationDouble(d)
+ implicit final class DurationDouble(val d: Double) extends AnyVal with DurationConversions {
+ override protected def durationIn(unit: TimeUnit): FiniteDuration =
+ Duration(d, unit) match {
+ case f: FiniteDuration => f
+ case _ => throw new IllegalArgumentException("Duration DSL not applicable to " + d)
+ }
+ }
- implicit def pairIntToDuration(p: (Int, TimeUnit)) = Duration(p._1, p._2)
- implicit def pairLongToDuration(p: (Long, TimeUnit)) = Duration(p._1, p._2)
- implicit def durationToPair(d: Duration) = (d.length, d.unit)
+ /*
+ * Avoid reflection based invocation by using non-duck type
+ */
+ implicit final class IntMult(val i: Int) extends AnyVal {
+ def *(d: Duration) = d * i
+ }
- implicit def intMult(i: Int) = new IntMult(i)
- implicit def longMult(l: Long) = new LongMult(l)
- implicit def doubleMult(f: Double) = new DoubleMult(f)
+ implicit final class LongMult(val i: Long) extends AnyVal {
+ def *(d: Duration) = d * i
+ }
+
+ implicit final class DoubleMult(val f: Double) extends AnyVal {
+ def *(d: Duration) = d * f
+ }
}
diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala
index 99c274dc29..a1a3305db0 100644
--- a/src/library/scala/concurrent/impl/Promise.scala
+++ b/src/library/scala/concurrent/impl/Promise.scala
@@ -8,16 +8,12 @@
package scala.concurrent.impl
-
-
-import java.util.concurrent.TimeUnit.NANOSECONDS
import scala.concurrent.{ ExecutionContext, CanAwait, OnCompleteRunnable, TimeoutException, ExecutionException }
-import scala.concurrent.duration.{ Duration, Deadline, FiniteDuration }
+import scala.concurrent.duration.{ Duration, Deadline, FiniteDuration, NANOSECONDS }
import scala.annotation.tailrec
import scala.util.control.NonFatal
import scala.util.{ Try, Success, Failure }
-
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
@@ -48,7 +44,7 @@ private[concurrent] object Promise {
case Failure(t) => resolver(t)
case _ => source
}
-
+
private def resolver[T](throwable: Throwable): Try[T] = throwable match {
case t: scala.runtime.NonLocalReturnControl[_] => Success(t.value.asInstanceOf[T])
case t: scala.util.control.ControlThrowable => Failure(new ExecutionException("Boxed ControlThrowable", t))
@@ -56,12 +52,12 @@ private[concurrent] object Promise {
case e: Error => Failure(new ExecutionException("Boxed Error", e))
case t => Failure(t)
}
-
+
/** Default promise implementation.
*/
class DefaultPromise[T] extends AbstractPromise with Promise[T] { self =>
updateState(null, Nil) // Start at "No callbacks"
-
+
protected final def tryAwait(atMost: Duration): Boolean = {
@tailrec
def awaitUnsafe(deadline: Deadline, nextWait: FiniteDuration): Boolean = {
diff --git a/test/files/jvm/duration-tck.scala b/test/files/jvm/duration-tck.scala
index 1a09007dc9..40073c0b3f 100644
--- a/test/files/jvm/duration-tck.scala
+++ b/test/files/jvm/duration-tck.scala
@@ -1,10 +1,9 @@
/**
* Copyright (C) 2012 Typesafe Inc. <http://www.typesafe.com>
*/
-
+
import scala.concurrent.duration._
import scala.reflect._
-import java.util.concurrent.TimeUnit._
import scala.tools.partest.TestUtil.intercept
object Test extends App {
@@ -38,7 +37,7 @@ object Test extends App {
two / one mustBe 2
one + zero mustBe one
one / 1000000 mustBe 1.micro
-
+
// test infinities
@@ -90,7 +89,7 @@ object Test extends App {
minf.toUnit(MINUTES) mustBe Double.NegativeInfinity
Duration.fromNanos(Double.PositiveInfinity) mustBe inf
Duration.fromNanos(Double.NegativeInfinity) mustBe minf
-
+
// test undefined & NaN
@@ -121,7 +120,7 @@ object Test extends App {
undef.toUnit(DAYS) mustBe nan
Duration.fromNanos(nan) mustBe undef
-
+
// test overflow protection
for (unit ← Seq(DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS)) {
@@ -152,21 +151,21 @@ object Test extends App {
}
intercept[IllegalArgumentException] { Duration.fromNanos(1e20) }
intercept[IllegalArgumentException] { Duration.fromNanos(-1e20) }
-
+
// test precision
1.second + 1.millisecond mustBe 1001.milliseconds
100000.days + 1.nanosecond mustBe 8640000000000000001L.nanoseconds
1.5.seconds.toSeconds mustBe 1
(-1.5).seconds.toSeconds mustBe -1
-
+
// test unit stability
1000.millis.unit mustBe MILLISECONDS
(1000.millis + 0.days).unit mustBe MILLISECONDS
1.second.unit mustBe SECONDS
(1.second + 1.millisecond).unit mustBe MILLISECONDS
-
+
// test Deadline
val dead = 2.seconds.fromNow
@@ -183,10 +182,10 @@ object Test extends App {
(500.millis * 2).unit mustBe MILLISECONDS
1.second / 2 mustBe 500.millis
(1.second / 2).unit mustBe MILLISECONDS
-
+
// check statically retaining finite-ness
val finiteDuration: FiniteDuration = 1.second * 2 / 3 mul 5 div 4 plus 3.seconds minus 1.millisecond min 1.second max 1.second
-
+
}