summaryrefslogtreecommitdiff
path: root/src/main/scala
diff options
context:
space:
mode:
authorMathias <mathias@spray.io>2015-05-06 11:23:00 +0200
committerMathias <mathias@spray.io>2015-05-06 12:41:50 +0200
commit51e1af64175e1c01a0383e6018839fc374bca164 (patch)
tree0c3ac727a0bd96b4de1fde286dcfcf0b51901b36 /src/main/scala
parent45672ff730516dd28416cb3a5f5c2c8be1d3e0b5 (diff)
downloadspray-json-51e1af64175e1c01a0383e6018839fc374bca164.tar.gz
spray-json-51e1af64175e1c01a0383e6018839fc374bca164.tar.bz2
spray-json-51e1af64175e1c01a0383e6018839fc374bca164.zip
Improve name unmangling in ProductFormats, closes #138
Diffstat (limited to 'src/main/scala')
-rw-r--r--src/main/scala/spray/json/ProductFormats.scala63
1 files changed, 44 insertions, 19 deletions
diff --git a/src/main/scala/spray/json/ProductFormats.scala b/src/main/scala/spray/json/ProductFormats.scala
index 9e494ff..b1aac8e 100644
--- a/src/main/scala/spray/json/ProductFormats.scala
+++ b/src/main/scala/spray/json/ProductFormats.scala
@@ -17,6 +17,7 @@
package spray.json
import java.lang.reflect.Modifier
+import scala.annotation.tailrec
import scala.util.control.NonFatal
/**
@@ -87,26 +88,50 @@ trait ProductFormats extends ProductFormatsInstances {
}
object ProductFormats {
- private val operators = Map(
- "$eq" -> "=",
- "$greater" -> ">",
- "$less" -> "<",
- "$plus" -> "+",
- "$minus" -> "-",
- "$times" -> "*",
- "$div" -> "/",
- "$bang" -> "!",
- "$at" -> "@",
- "$hash" -> "#",
- "$percent" -> "%",
- "$up" -> "^",
- "$amp" -> "&",
- "$tilde" -> "~",
- "$qmark" -> "?",
- "$bar" -> "|")
- private def unmangle(name: String) = operators.foldLeft(name) { case (n, (mangled, unmangled)) =>
- if (n.indexOf(mangled) >= 0) n.replace(mangled, unmangled) else n
+ private def unmangle(name: String) = {
+ import java.lang.{StringBuilder => JStringBuilder}
+ @tailrec def rec(ix: Int, builder: JStringBuilder): String = {
+ val rem = name.length - ix
+ if (rem > 0) {
+ var ch = name.charAt(ix)
+ var ni = ix + 1
+ val sb = if (ch == '$' && rem > 1) {
+ def c(offset: Int, ch: Char) = name.charAt(ix + offset) == ch
+ ni = name.charAt(ix + 1) match {
+ case 'a' if rem > 3 && c(2, 'm') && c(3, 'p') => { ch = '&'; ix + 4 }
+ case 'a' if rem > 2 && c(2, 't') => { ch = '@'; ix + 3 }
+ case 'b' if rem > 4 && c(2, 'a') && c(3, 'n') && c(4, 'g') => { ch = '!'; ix + 5 }
+ case 'b' if rem > 3 && c(2, 'a') && c(3, 'r') => { ch = '|'; ix + 4 }
+ case 'd' if rem > 3 && c(2, 'i') && c(3, 'v') => { ch = '/'; ix + 4 }
+ case 'e' if rem > 2 && c(2, 'q') => { ch = '='; ix + 3 }
+ case 'g' if rem > 7 && c(2, 'r') && c(3, 'e') && c(4, 'a') && c(5, 't') && c(6, 'e') && c(7, 'r') => { ch = '>'; ix + 8 }
+ case 'h' if rem > 4 && c(2, 'a') && c(3, 's') && c(4, 'h') => { ch = '#'; ix + 5 }
+ case 'l' if rem > 4 && c(2, 'e') && c(3, 's') && c(4, 's') => { ch = '<'; ix + 5 }
+ case 'm' if rem > 5 && c(2, 'i') && c(3, 'n') && c(4, 'u') && c(5, 's') => { ch = '-'; ix + 6 }
+ case 'p' if rem > 7 && c(2, 'e') && c(3, 'r') && c(4, 'c') && c(5, 'e') && c(6, 'n') && c(7, 't') => { ch = '%'; ix + 8 }
+ case 'p' if rem > 4 && c(2, 'l') && c(3, 'u') && c(4, 's') => { ch = '+'; ix + 5 }
+ case 'q' if rem > 5 && c(2, 'm') && c(3, 'a') && c(4, 'r') && c(5, 'k') => { ch = '?'; ix + 6 }
+ case 't' if rem > 5 && c(2, 'i') && c(3, 'l') && c(4, 'd') && c(5, 'e') => { ch = '~'; ix + 6 }
+ case 't' if rem > 5 && c(2, 'i') && c(3, 'm') && c(4, 'e') && c(5, 's') => { ch = '*'; ix + 6 }
+ case 'u' if rem > 2 && c(2, 'p') => { ch = '^'; ix + 3 }
+ case 'u' if rem > 5 =>
+ def hexValue(offset: Int): Int = {
+ val c = name.charAt(ix + offset)
+ if ('0' <= c && c <= '9') c - '0'
+ else if ('a' <= c && c <= 'f') c - 87
+ else if ('A' <= c && c <= 'F') c - 55 else -0xFFFF
+ }
+ val ci = (hexValue(2) << 12) + (hexValue(3) << 8) + (hexValue(4) << 4) + hexValue(5)
+ if (ci >= 0) { ch = ci.toChar; ix + 6 } else ni
+ case _ => ni
+ }
+ if (ni > ix + 1 && builder == null) new JStringBuilder(name.substring(0, ix)) else builder
+ } else builder
+ rec(ni, if (sb != null) sb.append(ch) else null)
+ } else if (builder != null) builder.toString else name
+ }
+ rec(0, null)
}
}