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

aml4s-core_2.12.0.3.0.source-code.YamlNumber.scala Maven / Gradle / Ivy

/*
 * Copyright 2023 Hossein Naderi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dev.hnaderi.yaml4s

sealed abstract class YamlNumber extends Serializable {

  /** Return this number as a [[scala.math.BigDecimal]].
    */
  def toBigDecimal: BigDecimal

  /** Return this number as a [[scala.math.BigInt]] if it's a sufficiently small
    * whole number.
    */
  def toBigInt: Option[BigInt]

  /** Convert this number to its best [[scala.Double]] approximation.
    *
    * Anything over `Double.MaxValue` will be rounded to
    * `Double.PositiveInfinity` and anything below `Double.MinValue` is rounded
    * to `Double.NegativeInfinity`.
    */
  def toDouble: Double

  /** Convert this number to its best [[scala.Float]] approximation.
    *
    * Anything over `Float.MaxValue` will be rounded to `Float.PositiveInfinity`
    * and anything below `Float.MinValue` is rounded to
    * `Float.NegativeInfinity`.
    */
  def toFloat: Float

  /** Return this number as a [[scala.Byte]] if it's a valid [[scala.Byte]].
    */
  final def toByte: Option[Byte] = toLong match {
    case Some(n) =>
      val asByte: Byte = n.toByte
      if (n == asByte) Some(asByte) else None
    case None => None
  }

  /** Return this number as a [[scala.Short]] if it's a valid [[scala.Short]].
    */
  final def toShort: Option[Short] = toLong match {
    case Some(n) =>
      val asShort: Short = n.toShort
      if (n == asShort) Some(asShort) else None
    case None => None
  }

  /** Return this number as an [[scala.Int]] if it's a valid [[scala.Int]].
    */
  final def toInt: Option[Int] = toLong match {
    case Some(n) =>
      val asInt: Int = n.toInt
      if (n == asInt) Some(asInt) else None
    case None => None
  }

  /** Return this number as a [[scala.Long]] if it's a valid [[scala.Long]].
    */
  def toLong: Option[Long]

  def isWhole: Boolean
}

object YamlNumber {
  private final case class YLong(value: Long) extends YamlNumber {
    override def toBigDecimal: BigDecimal = BigDecimal(value)
    override def toBigInt: Option[BigInt] = Some(BigInt(value))
    override def toDouble: Double = value.toDouble
    override def toFloat: Float = value.toFloat
    override def toLong: Option[Long] = Some(value)
    override def isWhole: Boolean = true
    override def toString: String = value.toString()

    override def equals(that: Any): Boolean = that match {
      case YLong(v)       => v == value
      case YDouble(v)     => v == value
      case YBigDecimal(v) => v == value
      case YFloat(v)      => v == value
      case _              => false
    }
  }

  private final case class YDouble(value: Double) extends YamlNumber {
    override def toBigDecimal: BigDecimal = BigDecimal(value)
    override def toBigInt: Option[BigInt] = toLong.map(BigInt(_))
    override def toDouble: Double = value
    override def toFloat: Float = value.toFloat
    override def toLong: Option[Long] =
      if (value.isWhole) Some(value.toLong) else None
    override def isWhole: Boolean = value.isWhole
    override def toString: String = value.toString()

    override def equals(that: Any): Boolean = that match {
      case YLong(v)       => v == value
      case YDouble(v)     => v == value
      case YBigDecimal(v) => v == value
      case YFloat(v)      => v == value
      case _              => false
    }
  }

  private final case class YFloat(value: Float) extends YamlNumber {
    override def toBigDecimal: BigDecimal = BigDecimal(value.toDouble)
    override def toBigInt: Option[BigInt] = toLong.map(BigInt(_))
    override def toDouble: Double = value.toDouble
    override def toFloat: Float = value
    override def toLong: Option[Long] =
      if (value.isValidInt) Some(value.toLong) else None
    override def isWhole: Boolean = value.isWhole
    override def toString: String = value.toString()

    override def equals(that: Any): Boolean = that match {
      case YLong(v)       => v == value
      case YDouble(v)     => v == value
      case YBigDecimal(v) => v == value
      case YFloat(v)      => v == value
      case _              => false
    }
  }

  private final case class YBigDecimal(value: BigDecimal) extends YamlNumber {
    override def toBigDecimal: BigDecimal = value
    override def toBigInt: Option[BigInt] = value.toBigIntExact
    override def toDouble: Double = value.toDouble
    override def toFloat: Float = value.toFloat
    override def toLong: Option[Long] =
      if (value.isValidLong) Some(value.toLongExact) else None
    override def isWhole: Boolean = value.isWhole
    override def toString: String = value.toString()

    override def equals(that: Any): Boolean = that match {
      case YLong(v)       => v == value
      case YDouble(v)     => v == value
      case YBigDecimal(v) => v == value
      case YFloat(v)      => v == value
      case _              => false
    }
  }

  def apply(n: Long): YamlNumber = YLong(n)
  def apply(n: Float): YamlNumber = YFloat(n)
  def apply(n: Double): YamlNumber = YDouble(n)
  def apply(n: BigDecimal): YamlNumber = YBigDecimal(n)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy