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

jvmMain.com.squareup.wire.internal.DurationJsonFormatter.kt Maven / Gradle / Ivy

/*
 * Copyright 2020 Square Inc.
 *
 * 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 com.squareup.wire.internal

import com.squareup.wire.Duration

/**
 * Encode a duration as a JSON string like "1.200s". From the spec:
 *
 * > Generated output always contains 0, 3, 6, or 9 fractional digits, depending on required
 * > precision, followed by the suffix "s". Accepted are any fractional digits (also none) as long
 * > as they fit into nano-seconds precision and the suffix "s" is required.
 *
 * Note that [Duration] always returns a positive nanosPart, so "-1.200s" is represented as -2
 * seconds and 800_000_000 nanoseconds.
 */
object DurationJsonFormatter : JsonFormatter {
  override fun toStringOrNumber(value: Duration): String {
    var seconds = value.seconds
    var nanos = value.nano
    var prefix = ""
    if (seconds < 0L) {
      if (seconds == Long.MIN_VALUE) {
        prefix = "-922337203685477580" // Avoid overflow inverting MIN_VALUE.
        seconds = 8
      } else {
        prefix = "-"
        seconds = -seconds
      }
      if (nanos != 0) {
        seconds -= 1L
        nanos = 1_000_000_000 - nanos
      }
    }
    return when {
      nanos == 0 -> "%s%ds".format(prefix, seconds)
      nanos % 1_000_000 == 0 -> "%s%d.%03ds".format(prefix, seconds, nanos / 1_000_000L)
      nanos % 1_000 == 0 -> "%s%d.%06ds".format(prefix, seconds, nanos / 1_000L)
      else -> "%s%d.%09ds".format(prefix, seconds, nanos / 1L)
    }
  }

  /** Throws a NumberFormatException if the string isn't a number like "1s" or "1.23456789s". */
  override fun fromString(value: String): Duration {
    val sIndex = value.indexOf('s')
    if (sIndex != value.length - 1) throw NumberFormatException()

    val dotIndex = value.indexOf('.')
    if (dotIndex == -1) {
      val seconds = value.substring(0, sIndex).toLong()
      return Duration.ofSeconds(seconds)
    }

    val seconds = value.substring(0, dotIndex).toLong()
    var nanos = value.substring(dotIndex + 1, sIndex).toLong()
    if (value.startsWith("-")) nanos = -nanos
    val nanosDigits = sIndex - (dotIndex + 1)
    for (i in nanosDigits until 9) nanos *= 10
    for (i in 9 until nanosDigits) nanos /= 10
    return Duration.ofSeconds(seconds, nanos)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy