forked from circe/circe
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CirceSupportParser.scala
133 lines (118 loc) · 5.09 KB
/
CirceSupportParser.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package io.circe.jawn
import io.circe.{ Json, JsonNumber, JsonObject }
import java.io.Serializable
import java.util.LinkedHashMap
import org.typelevel.jawn.{ FContext, Facade, SupportParser }
object CirceSupportParser extends CirceSupportParser(None, true)
class CirceSupportParser(maxValueSize: Option[Int], allowDuplicateKeys: Boolean)
extends SupportParser[Json]
with Serializable {
implicit final val facade: Facade[Json] = maxValueSize match {
case Some(size) =>
if (allowDuplicateKeys) {
new LimitedFacade(size) with DuplicatesFacade
} else {
new LimitedFacade(size) with NoDuplicatesFacade
}
case None =>
if (allowDuplicateKeys) {
new UnlimitedFacade with DuplicatesFacade
} else {
new UnlimitedFacade with NoDuplicatesFacade
}
}
private[this] abstract class BaseFacade extends Facade[Json] with Serializable {
final def jnull(index: Int): Json = Json.Null
final def jfalse(index: Int): Json = Json.False
final def jtrue(index: Int): Json = Json.True
final def singleContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final var value: Json = null
final def add(s: CharSequence, index: Int): Unit = value = jstring(s.toString, index)
final def add(v: Json, index: Int): Unit = value = v
final def finish(index: Int): Json = value
final def isObj: Boolean = false
}
final def arrayContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final val vs = Vector.newBuilder[Json]
final def add(s: CharSequence, index: Int): Unit = vs += jstring(s.toString, index)
final def add(v: Json, index: Int): Unit = vs += v
final def finish(index: Int): Json = Json.fromValues(vs.result())
final def isObj: Boolean = false
}
protected[this] def mapPut(map: LinkedHashMap[String, Json], key: String, value: Json): Unit
}
private[this] abstract class LimitedFacade(maxValueSize: Int) extends BaseFacade {
final def jnum(s: CharSequence, decIndex: Int, expIndex: Int, index: Int): Json =
if (s.length > maxValueSize) {
throw new IllegalArgumentException(s"JSON number length (${s.length}) exceeds limit ($maxValueSize)")
} else {
if (decIndex < 0 && expIndex < 0) {
Json.fromJsonNumber(JsonNumber.fromIntegralStringUnsafe(s.toString))
} else {
Json.fromJsonNumber(JsonNumber.fromDecimalStringUnsafe(s.toString))
}
}
final def jstring(s: CharSequence, index: Int): Json = if (s.length > maxValueSize) {
throw new IllegalArgumentException(s"JSON string length (${s.length}) exceeds limit ($maxValueSize)")
} else {
Json.fromString(s.toString)
}
final def objectContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final var key: String = null
private[this] final val m = new LinkedHashMap[String, Json]
final def add(s: CharSequence, index: Int): Unit =
if (key.eq(null)) {
if (s.length > maxValueSize) {
throw new IllegalArgumentException(s"JSON key length (${s.length}) exceeds limit ($maxValueSize)")
} else {
key = s.toString
}
} else {
mapPut(m, key, jstring(s, index))
key = null
}
final def add(v: Json, index: Int): Unit = {
mapPut(m, key, v)
key = null
}
final def finish(index: Int): Json = Json.fromJsonObject(JsonObject.fromLinkedHashMap(m))
final def isObj: Boolean = true
}
}
private[this] abstract class UnlimitedFacade extends BaseFacade {
final def jnum(s: CharSequence, decIndex: Int, expIndex: Int, index: Int): Json =
if (decIndex < 0 && expIndex < 0) {
Json.fromJsonNumber(JsonNumber.fromIntegralStringUnsafe(s.toString))
} else {
Json.fromJsonNumber(JsonNumber.fromDecimalStringUnsafe(s.toString))
}
final def jstring(s: CharSequence, index: Int): Json = Json.fromString(s.toString)
final def objectContext(index: Int): FContext[Json] = new FContext[Json] {
private[this] final var key: String = null
private[this] final val m = new LinkedHashMap[String, Json]
final def add(s: CharSequence, index: Int): Unit =
if (key.eq(null)) {
key = s.toString
} else {
mapPut(m, key, jstring(s, index))
key = null
}
final def add(v: Json, index: Int): Unit = {
mapPut(m, key, v)
key = null
}
final def finish(index: Int): Json = Json.fromJsonObject(JsonObject.fromLinkedHashMap(m))
final def isObj: Boolean = true
}
}
private[this] trait DuplicatesFacade extends BaseFacade {
protected[this] final def mapPut(map: LinkedHashMap[String, Json], key: String, value: Json): Unit =
map.put(key, value)
}
private[this] trait NoDuplicatesFacade extends BaseFacade {
protected[this] final def mapPut(map: LinkedHashMap[String, Json], key: String, value: Json): Unit =
if (map.put(key, value).ne(null)) {
throw new IllegalArgumentException(s"Invalid json, duplicate key name found: $key")
}
}
}