All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kyo.Duration.scala Maven / Gradle / Ivy

There is a newer version: 0.14.1
Show newest version
package kyo

import java.time.Duration as JavaDuration
import java.time.temporal.ChronoUnit.*
import kyo.Duration.Units
import kyo.Duration.Units.*
import scala.concurrent.duration.Duration as ScalaDuration

type Duration = Duration.Value

object Duration:

    opaque type Value = Long

    given CanEqual[Duration, Duration] = CanEqual.derived

    val Zero: Duration     = 0L
    val Infinity: Duration = Long.MaxValue

    inline def fromNanos(value: Long): Duration = value

    def fromUnits(value: Long, unit: Units): Duration =
        if value <= 0 then Duration.Zero else Duration.*(value)(unit.factor).min(Infinity)

    def fromJava(value: JavaDuration): Duration =
        (value.toNanos: @annotation.switch) match
            case 0                       => Zero
            case n if n >= Long.MaxValue => Infinity
            case n                       => n.nanos

    def fromScala(value: ScalaDuration): Duration =
        if value.isFinite then value.toNanos.nanos.max(Zero) else Infinity

    enum Units(val factor: Double):
        case Nanos   extends Units(NANOS.getDuration.toNanos.toDouble)
        case Micros  extends Units(MICROS.getDuration.toNanos.toDouble)
        case Millis  extends Units(MILLIS.getDuration.toNanos.toDouble)
        case Seconds extends Units(SECONDS.getDuration.toNanos.toDouble)
        case Minutes extends Units(MINUTES.getDuration.toNanos.toDouble)
        case Hours   extends Units(HOURS.getDuration.toNanos.toDouble)
        case Days    extends Units(DAYS.getDuration.toNanos.toDouble)
        case Weeks   extends Units(WEEKS.getDuration.toNanos.toDouble)
        case Months  extends Units(MONTHS.getDuration.toNanos.toDouble)
        case Years   extends Units(YEARS.getDuration.toNanos.toDouble)
    end Units

    extension (self: Duration)

        private inline def toLong: Long = self

        inline infix def >=(that: Duration): Boolean = self.toLong >= that.toLong
        inline infix def <=(that: Duration): Boolean = self.toLong <= that.toLong
        inline infix def >(that: Duration): Boolean  = self.toLong > that.toLong
        inline infix def <(that: Duration): Boolean  = self.toLong < that.toLong
        inline infix def ==(that: Duration): Boolean = self.toLong == that.toLong
        inline infix def !=(that: Duration): Boolean = self.toLong != that.toLong

        inline infix def +(that: Duration): Duration =
            val sum: Long = self.toLong + that.toLong
            if sum >= 0 then sum else Duration.Infinity

        inline infix def *(factor: Double): Duration =
            if factor <= 0 || self.toLong <= 0L then Duration.Zero
            else if factor <= Long.MaxValue / self.toLong.toDouble then Math.round(self.toLong.toDouble * factor)
            else Duration.Infinity

        inline def max(that: Duration): Duration = Math.max(self.toLong, that.toLong)
        inline def min(that: Duration): Duration = Math.min(self.toLong, that.toLong)

        inline def to(unit: Units): Long =
            Math.max(Math.round(self.toLong / unit.factor), Duration.Zero)

        inline def toNanos: Long   = self.toLong
        inline def toMicros: Long  = self.to(Micros)
        inline def toMillis: Long  = self.to(Millis)
        inline def toSeconds: Long = self.to(Seconds)
        inline def toMinutes: Long = self.to(Minutes)
        inline def toHours: Long   = self.to(Hours)
        inline def toDays: Long    = self.to(Days)
        inline def toWeeks: Long   = self.to(Weeks)
        inline def toMonths: Long  = self.to(Months)
        inline def toYears: Long   = self.to(Years)

        def toScala: ScalaDuration =
            (self: @annotation.switch) match
                case Duration.Zero     => ScalaDuration.Zero
                case Duration.Infinity => ScalaDuration.Inf
                case n                 => ScalaDuration.fromNanos(n.toNanos)

        def toJava: JavaDuration =
            (self: @annotation.switch) match
                case Duration.Zero => JavaDuration.ZERO
                case n             => JavaDuration.of(n.toNanos, NANOS)

        inline def render: String = s"Duration($self ns)"

        // Is this Robust enough?
        private[kyo] inline def isFinite: Boolean = self < Duration.Infinity
    end extension

end Duration

extension (value: Long)
    inline def nanos: Duration   = Duration.fromNanos(value)
    inline def micros: Duration  = value.asUnit(Micros)
    inline def millis: Duration  = value.asUnit(Millis)
    inline def seconds: Duration = value.asUnit(Seconds)
    inline def minutes: Duration = value.asUnit(Minutes)
    inline def hours: Duration   = value.asUnit(Hours)
    inline def days: Duration    = value.asUnit(Days)
    inline def weeks: Duration   = value.asUnit(Weeks)
    inline def months: Duration  = value.asUnit(Months)
    inline def years: Duration   = value.asUnit(Years)
    inline def nano: Duration    = compiletime.error("please use `.nanos`")
    inline def micro: Duration   = compiletime.error("please use `.micros`")
    inline def milli: Duration   = compiletime.error("please use `.millis`")
    inline def second: Duration  = compiletime.error("please use `.seconds`")
    inline def minute: Duration  = compiletime.error("please use `.minutes`")
    inline def hour: Duration    = compiletime.error("please use `.hours`")
    inline def day: Duration     = compiletime.error("please use `.days`")
    inline def week: Duration    = compiletime.error("please use `.weeks`")
    inline def month: Duration   = compiletime.error("please use `.months`")
    inline def year: Duration    = compiletime.error("please use `.years`")

    inline def asUnit(unit: Units): Duration =
        Duration.fromUnits(value, unit)
end extension

extension (value: 1)
    inline def nano: Duration   = Duration.fromNanos(value)
    inline def micro: Duration  = value.asUnit(Micros)
    inline def milli: Duration  = value.asUnit(Millis)
    inline def second: Duration = value.asUnit(Seconds)
    inline def minute: Duration = value.asUnit(Minutes)
    inline def hour: Duration   = value.asUnit(Hours)
    inline def day: Duration    = value.asUnit(Days)
    inline def week: Duration   = value.asUnit(Weeks)
    inline def month: Duration  = value.asUnit(Months)
    inline def year: Duration   = value.asUnit(Years)
end extension




© 2015 - 2024 Weber Informatics LLC | Privacy Policy