Skip to content

Commit

Permalink
Make int and long segment parsing JS compatible (#3087) (#3090)
Browse files Browse the repository at this point in the history
  • Loading branch information
987Nabil authored Sep 6, 2024
1 parent aacca27 commit 9f455e9
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package zio.http.codec

import java.util.Objects

trait PathCodecPlatformSpecific {
private[codec] def parseLong(s: CharSequence, beginIndex: Int, endIndex: Int, radix: Int): Long = {
Objects.requireNonNull(s)
Objects.checkFromToIndex(beginIndex, endIndex, s.length)
if (radix < Character.MIN_RADIX)
throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX")
if (radix > Character.MAX_RADIX)
throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX")
var negative = false
var i = beginIndex
var limit = -Long.MaxValue
if (i < endIndex) {
val firstChar = s.charAt(i)
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true
limit = Long.MinValue
} else if (firstChar != '+') throw forCharSequence(s, beginIndex, endIndex, i)
i += 1
}
if (i >= endIndex) { // Cannot have lone "+", "-" or ""
throw forCharSequence(s, beginIndex, endIndex, i)
}
val multmin = limit / radix
var result = 0L
while (i < endIndex) {
// Accumulating negatively avoids surprises near MAX_VALUE
val digit = Character.digit(s.charAt(i), radix)
if (digit < 0 || result < multmin) throw forCharSequence(s, beginIndex, endIndex, i)
result *= radix
if (result < limit + digit) throw forCharSequence(s, beginIndex, endIndex, i)
i += 1
result -= digit
}
if (negative) result
else -result
} else throw new NumberFormatException("")
}

private[codec] def parseInt(s: CharSequence, beginIndex: Int, endIndex: Int, radix: Int): Int = {
Objects.requireNonNull(s)
Objects.checkFromToIndex(beginIndex, endIndex, s.length)
if (radix < Character.MIN_RADIX)
throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX")
if (radix > Character.MAX_RADIX)
throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX")
var negative = false
var i = beginIndex
var limit = -Int.MaxValue
if (i < endIndex) {
val firstChar = s.charAt(i)
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true
limit = Int.MinValue
} else if (firstChar != '+') throw forCharSequence(s, beginIndex, endIndex, i)
i += 1
if (i == endIndex) { // Cannot have lone "+" or "-"
throw forCharSequence(s, beginIndex, endIndex, i)
}
}
val multmin = limit / radix
var result = 0
while (i < endIndex) {
// Accumulating negatively avoids surprises near MAX_VALUE
val digit = Character.digit(s.charAt(i), radix)
if (digit < 0 || result < multmin) throw forCharSequence(s, beginIndex, endIndex, i)
result *= radix
if (result < limit + digit) throw forCharSequence(s, beginIndex, endIndex, i)
i += 1
result -= digit
}
if (negative) result
else -result
} else throw forInputString("", radix)
}

private[codec] def forCharSequence(s: CharSequence, beginIndex: Int, endIndex: Int, errorIndex: Int) =
new NumberFormatException(
"Error at index " + (errorIndex - beginIndex) + " in: \"" + s.subSequence(beginIndex, endIndex) + "\"",
)

private[codec] def forInputString(s: String, radix: Int) = new NumberFormatException(
"For input string: \"" + s + "\"" + (if (radix == 10) ""
else " under radix " + radix),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package zio.http.codec

trait PathCodecPlatformSpecific {
def parseLong(s: CharSequence, beginIndex: Int, endIndex: Int, radix: Int): Long =
java.lang.Long.parseLong(s.subSequence(beginIndex, endIndex).toString, radix)

def parseInt(s: CharSequence, beginIndex: Int, endIndex: Int, radix: Int): Int =
java.lang.Integer.parseInt(s.subSequence(beginIndex, endIndex).toString, radix)
}
8 changes: 4 additions & 4 deletions zio-http/shared/src/main/scala/zio/http/codec/PathCodec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import zio.http._
* val pathCodec = empty / "users" / int("user-id") / "posts" / string("post-id")
* }}}
*/
sealed trait PathCodec[A] { self =>
sealed trait PathCodec[A] extends codec.PathCodecPlatformSpecific { self =>
import PathCodec._

/**
Expand Down Expand Up @@ -339,7 +339,7 @@ sealed trait PathCodec[A] { self =>
} else {

try {
val int = Integer.parseInt(value, j, end, 10)
val int = parseInt(value, j, end, 10)
j = end
if (isNegative) stack.push(-int) else stack.push(int)
} catch {
Expand All @@ -358,7 +358,7 @@ sealed trait PathCodec[A] { self =>
return "Expected long path segment but found: " + value.substring(j, end)
} else {
try {
val long = java.lang.Long.parseLong(value, j, end, 10)
val long = parseLong(value, j, end, 10)
j = end
if (isNegative) stack.push(-long) else stack.push(long)
} catch {
Expand Down Expand Up @@ -663,7 +663,7 @@ sealed trait PathCodec[A] { self =>
final def transformOrFailRight[A2](f: A => A2)(g: A2 => Either[String, A]): PathCodec[A2] =
PathCodec.TransformOrFail[A, A2](self, in => Right(f(in)), g)
}
object PathCodec {
object PathCodec {

/**
* Constructs a path codec from a method and a path literal.
Expand Down

0 comments on commit 9f455e9

Please sign in to comment.