gson, gson-math
This commit is contained in:
parent
5a0f60f886
commit
f6538bd03a
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
@ -22,6 +23,8 @@
|
||||
<option value="$PROJECT_DIR$/buildSrc" />
|
||||
<option value="$PROJECT_DIR$/collect" />
|
||||
<option value="$PROJECT_DIR$/core" />
|
||||
<option value="$PROJECT_DIR$/gson" />
|
||||
<option value="$PROJECT_DIR$/gson-math" />
|
||||
<option value="$PROJECT_DIR$/guava" />
|
||||
<option value="$PROJECT_DIR$/io" />
|
||||
<option value="$PROJECT_DIR$/io-math" />
|
||||
|
77
core/src/main/kotlin/ru/dbotthepony/kommons/core/Either.kt
Normal file
77
core/src/main/kotlin/ru/dbotthepony/kommons/core/Either.kt
Normal file
@ -0,0 +1,77 @@
|
||||
package ru.dbotthepony.kommons.core
|
||||
|
||||
/**
|
||||
* Implements a value container which contain either [L] or [R] value
|
||||
*/
|
||||
class Either<L, R> private constructor(val left: KOptional<L>, val right: KOptional<R>) {
|
||||
val isLeft: Boolean get() = left.isPresent
|
||||
val isRight: Boolean get() = right.isPresent
|
||||
|
||||
inline fun <T> map(left: (L) -> T, right: (R) -> T): T {
|
||||
this.left.ifPresent {
|
||||
return left.invoke(it)
|
||||
}
|
||||
|
||||
return right.invoke(this.right.value)
|
||||
}
|
||||
|
||||
inline fun <NL, NR> flatMap(left: (L) -> NL, right: (R) -> NR): Either<NL, NR> {
|
||||
this.left.ifPresent {
|
||||
return left(left.invoke(it))
|
||||
}
|
||||
|
||||
return right(right.invoke(this.right.value))
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NoSuchElementException
|
||||
*/
|
||||
fun left(): L = left.value
|
||||
|
||||
/**
|
||||
* @throws NoSuchElementException
|
||||
*/
|
||||
fun right(): R = right.value
|
||||
|
||||
inline fun leftOrElse(orElse: () -> L): L {
|
||||
if (isLeft)
|
||||
return left()
|
||||
else
|
||||
return orElse.invoke()
|
||||
}
|
||||
|
||||
inline fun rightOrElse(orElse: () -> R): R {
|
||||
if (isRight)
|
||||
return right()
|
||||
else
|
||||
return orElse.invoke()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other === this || other is Either<*, *> && other.left == left && other.right == right
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return left.hashCode() * 31 + right.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
if (isLeft) {
|
||||
return "Either.left[${left.value}]"
|
||||
} else {
|
||||
return "Either.right[${right.value}]"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun <L, R> left(value: L): Either<L, R> {
|
||||
return Either(KOptional.of(value), KOptional.empty())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <L, R> right(value: R): Either<L, R> {
|
||||
return Either(KOptional.empty(), KOptional.of(value))
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ kotlin.code.style=official
|
||||
specifyKotlinAsDependency=false
|
||||
|
||||
projectGroup=ru.dbotthepony.kommons
|
||||
projectVersion=1.0.2
|
||||
projectVersion=1.1.0
|
||||
|
||||
guavaDepVersion=33.0.0
|
||||
gsonDepVersion=2.8.9
|
||||
|
41
gson-math/build.gradle.kts
Normal file
41
gson-math/build.gradle.kts
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val gsonDepVersion: String by project
|
||||
val specifyKotlinAsDependency: String by project
|
||||
|
||||
dependencies {
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||
|
||||
implementation("com.google.code.gson:gson:$gsonDepVersion")
|
||||
implementation(project(":gson"))
|
||||
implementation(project(":core"))
|
||||
implementation(project(":math"))
|
||||
implementation(project(":linear-algebra"))
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
from(components["java"])
|
||||
artifact(tasks["sourceJar"])
|
||||
|
||||
pom {
|
||||
dependencies {
|
||||
if (specifyKotlinAsDependency.toBoolean()) implementation(kotlin("stdlib"))
|
||||
implementation("com.google.guava:guava:[2.0,)")
|
||||
implementation(project(":gson"))
|
||||
implementation(project(":core"))
|
||||
implementation(project(":math"))
|
||||
implementation(project(":linear-algebra"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.vector.Vector2d
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
|
||||
object AABBTypeAdapter : TypeAdapter<AABB>() {
|
||||
override fun write(out: JsonWriter, value: AABB) {
|
||||
`out`.beginArray()
|
||||
`out`.value(value.mins.x)
|
||||
`out`.value(value.mins.y)
|
||||
`out`.value(value.maxs.x)
|
||||
`out`.value(value.maxs.y)
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): AABB {
|
||||
`in`.beginArray()
|
||||
val (x1, x2) = Vector2d(`in`.nextDouble(), `in`.nextDouble())
|
||||
val (y1, y2) = Vector2d(`in`.nextDouble(), `in`.nextDouble())
|
||||
`in`.endArray()
|
||||
|
||||
val xMins = x1.coerceAtMost(x2)
|
||||
val xMaxs = x1.coerceAtLeast(x2)
|
||||
|
||||
val yMins = y1.coerceAtMost(y2)
|
||||
val yMaxs = y1.coerceAtLeast(y2)
|
||||
|
||||
return AABB(
|
||||
Vector2d(xMins, yMins),
|
||||
Vector2d(xMaxs, yMaxs),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.vector.Vector2i
|
||||
import ru.dbotthepony.kvector.util2d.AABBi
|
||||
|
||||
object AABBiTypeAdapter : TypeAdapter<AABBi>() {
|
||||
override fun write(out: JsonWriter, value: AABBi) {
|
||||
`out`.beginArray()
|
||||
`out`.value(value.mins.x)
|
||||
`out`.value(value.mins.y)
|
||||
`out`.value(value.maxs.x)
|
||||
`out`.value(value.maxs.y)
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): AABBi {
|
||||
`in`.beginArray()
|
||||
val (x1, x2) = Vector2i(`in`.nextInt(), `in`.nextInt())
|
||||
val (y1, y2) = Vector2i(`in`.nextInt(), `in`.nextInt())
|
||||
`in`.endArray()
|
||||
|
||||
val xMins = x1.coerceAtMost(x2)
|
||||
val xMaxs = x1.coerceAtLeast(x2)
|
||||
|
||||
val yMins = y1.coerceAtMost(y2)
|
||||
val yMaxs = y1.coerceAtLeast(y2)
|
||||
|
||||
return AABBi(
|
||||
Vector2i(xMins, yMins),
|
||||
Vector2i(xMaxs, yMaxs),
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.math.RGBAColor
|
||||
|
||||
object ColorTypeAdapter : TypeAdapter<RGBAColor>() {
|
||||
override fun write(out: JsonWriter, value: RGBAColor) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): RGBAColor {
|
||||
when (val type = `in`.peek()) {
|
||||
JsonToken.BEGIN_ARRAY -> {
|
||||
`in`.beginArray()
|
||||
val red = `in`.nextDouble()
|
||||
val green = `in`.nextDouble()
|
||||
val blue = `in`.nextDouble()
|
||||
|
||||
if (red % 1.0 == 0.0 && green % 1.0 == 0.0 && blue % 1.0 == 0.0) {
|
||||
val alpha = `in`.peek().let { if (it == JsonToken.END_ARRAY) 255.0 else `in`.nextDouble() }
|
||||
`in`.endArray()
|
||||
|
||||
return RGBAColor(
|
||||
red.toFloat() / 255f,
|
||||
green.toFloat() / 255f,
|
||||
blue.toFloat() / 255f,
|
||||
alpha.toFloat() / 255f,
|
||||
)
|
||||
} else {
|
||||
val alpha = `in`.peek().let { if (it == JsonToken.END_ARRAY) 1.0 else `in`.nextDouble() }
|
||||
`in`.endArray()
|
||||
|
||||
return RGBAColor(
|
||||
red.toFloat(),
|
||||
green.toFloat(),
|
||||
blue.toFloat(),
|
||||
alpha.toFloat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
JsonToken.BEGIN_OBJECT -> {
|
||||
`in`.beginObject()
|
||||
|
||||
val keyed = mutableMapOf<String, Double>()
|
||||
|
||||
while (`in`.peek() != JsonToken.END_OBJECT) {
|
||||
keyed[`in`.nextName()] = `in`.nextDouble()
|
||||
}
|
||||
|
||||
if (keyed.isEmpty())
|
||||
throw IllegalArgumentException("Object is empty")
|
||||
|
||||
var values = 0
|
||||
|
||||
val red = keyed["red"]?.also { values++ } ?: keyed["r"]?.also { values++ } ?: 255.0
|
||||
val green = keyed["green"]?.also { values++ } ?: keyed["g"]?.also { values++ } ?: 255.0
|
||||
val blue = keyed["blue"]?.also { values++ } ?: keyed["b"]?.also { values++ } ?: 255.0
|
||||
val alpha = keyed["alpha"]?.also { values++ } ?: keyed["a"]?.also { values++ } ?: 255.0
|
||||
`in`.endObject()
|
||||
|
||||
if (values == 0) {
|
||||
throw IllegalArgumentException("Object is not a RGBAColor")
|
||||
}
|
||||
|
||||
if (red % 1.0 == 0.0 && green % 1.0 == 0.0 && blue % 1.0 == 0.0 && alpha % 1.0 == 0.0) {
|
||||
return RGBAColor(
|
||||
red.toFloat() / 255f,
|
||||
green.toFloat() / 255f,
|
||||
blue.toFloat() / 255f,
|
||||
alpha.toFloat() / 255f,
|
||||
)
|
||||
} else {
|
||||
return RGBAColor(
|
||||
red.toFloat(),
|
||||
green.toFloat(),
|
||||
blue.toFloat(),
|
||||
alpha.toFloat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
JsonToken.NUMBER -> return RGBAColor.rgb(`in`.nextInt())
|
||||
JsonToken.STRING -> {
|
||||
val name = `in`.nextString()
|
||||
//return RGBAColor.PRE_DEFINED_MAP[name] ?: throw IllegalArgumentException("Unknown pre defined RGBAColor name $name")
|
||||
TODO("Can't determine color from name yet")
|
||||
}
|
||||
|
||||
else -> throw IllegalArgumentException("Expected array, object or number; got $type")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.vector.Vector2d
|
||||
|
||||
object Vector2dTypeAdapter : TypeAdapter<Vector2d>() {
|
||||
override fun write(out: JsonWriter, value: Vector2d) {
|
||||
`out`.beginArray()
|
||||
`out`.value(value.x)
|
||||
`out`.value(value.y)
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Vector2d {
|
||||
`in`.beginArray()
|
||||
|
||||
val x = `in`.nextDouble()
|
||||
val y = `in`.nextDouble()
|
||||
|
||||
`in`.endArray()
|
||||
|
||||
return Vector2d(x, y)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.vector.Vector2f
|
||||
|
||||
object Vector2fTypeAdapter : TypeAdapter<Vector2f>() {
|
||||
override fun write(out: JsonWriter, value: Vector2f) {
|
||||
`out`.beginArray()
|
||||
`out`.value(value.x)
|
||||
`out`.value(value.y)
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Vector2f {
|
||||
`in`.beginArray()
|
||||
|
||||
val x = `in`.nextDouble().toFloat()
|
||||
val y = `in`.nextDouble().toFloat()
|
||||
|
||||
`in`.endArray()
|
||||
|
||||
return Vector2f(x, y)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.vector.Vector2i
|
||||
|
||||
object Vector2iTypeAdapter : TypeAdapter<Vector2i>() {
|
||||
override fun write(out: JsonWriter, value: Vector2i) {
|
||||
`out`.beginArray()
|
||||
`out`.value(value.x)
|
||||
`out`.value(value.y)
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Vector2i {
|
||||
`in`.beginArray()
|
||||
|
||||
val x = `in`.nextInt()
|
||||
val y = `in`.nextInt()
|
||||
|
||||
`in`.endArray()
|
||||
|
||||
return Vector2i(x, y)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.vector.Vector4d
|
||||
|
||||
object Vector4dTypeAdapter : TypeAdapter<Vector4d>() {
|
||||
override fun write(out: JsonWriter, value: Vector4d) {
|
||||
`out`.beginArray()
|
||||
`out`.value(value.x)
|
||||
`out`.value(value.y)
|
||||
`out`.value(value.z)
|
||||
`out`.value(value.w)
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Vector4d {
|
||||
`in`.beginArray()
|
||||
|
||||
val x = `in`.nextDouble()
|
||||
val y = `in`.nextDouble()
|
||||
val z = `in`.nextDouble()
|
||||
val w = `in`.nextDouble()
|
||||
|
||||
`in`.endArray()
|
||||
|
||||
return Vector4d(x, y, z, w)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.vector.Vector4i
|
||||
|
||||
object Vector4iTypeAdapter : TypeAdapter<Vector4i>() {
|
||||
override fun write(out: JsonWriter, value: Vector4i) {
|
||||
`out`.beginArray()
|
||||
`out`.value(value.x)
|
||||
`out`.value(value.y)
|
||||
`out`.value(value.z)
|
||||
`out`.value(value.w)
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Vector4i {
|
||||
`in`.beginArray()
|
||||
|
||||
val x = `in`.nextInt()
|
||||
val y = `in`.nextInt()
|
||||
val z = `in`.nextInt()
|
||||
val w = `in`.nextInt()
|
||||
|
||||
`in`.endArray()
|
||||
|
||||
return Vector4i(x, y, z, w)
|
||||
}
|
||||
}
|
35
gson/build.gradle.kts
Normal file
35
gson/build.gradle.kts
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val gsonDepVersion: String by project
|
||||
val specifyKotlinAsDependency: String by project
|
||||
|
||||
dependencies {
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||
|
||||
implementation("com.google.code.gson:gson:$gsonDepVersion")
|
||||
implementation(project(":core"))
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
from(components["java"])
|
||||
artifact(tasks["sourceJar"])
|
||||
|
||||
pom {
|
||||
dependencies {
|
||||
if (specifyKotlinAsDependency.toBoolean()) implementation(kotlin("stdlib"))
|
||||
implementation("com.google.guava:guava:[2.0,)")
|
||||
implementation(project(":core"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonSyntaxException
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.internal.bind.JsonTreeReader
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kommons.core.Either
|
||||
import java.lang.reflect.ParameterizedType
|
||||
|
||||
object EitherTypeAdapter : TypeAdapterFactory {
|
||||
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||
if (type.rawType == Either::class.java) {
|
||||
val params = type.type as? ParameterizedType ?: return null
|
||||
val (left, right) = params.actualTypeArguments
|
||||
|
||||
return object : TypeAdapter<Either<Any, Any>>() {
|
||||
private val leftAdapter = gson.getAdapter(TypeToken.get(left)) as TypeAdapter<Any?>
|
||||
private val rightAdapter = gson.getAdapter(TypeToken.get(right)) as TypeAdapter<Any?>
|
||||
private val elemAdapter = gson.getAdapter(JsonElement::class.java)
|
||||
|
||||
override fun write(out: JsonWriter, value: Either<Any, Any>?) {
|
||||
if (value == null)
|
||||
out.nullValue()
|
||||
else
|
||||
value.map({ leftAdapter.write(out, it) }, { rightAdapter.write(out, it) })
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Either<Any, Any>? {
|
||||
if (`in`.peek() == JsonToken.NULL)
|
||||
return null
|
||||
|
||||
val elem = elemAdapter.read(`in`)
|
||||
|
||||
return try {
|
||||
Either.left(leftAdapter.read(JsonTreeReader(elem)) ?: throw NullPointerException("left was empty"))
|
||||
} catch(leftError: Throwable) {
|
||||
try {
|
||||
Either.right(rightAdapter.read(JsonTreeReader(elem)) ?: throw NullPointerException("right was empty"))
|
||||
} catch(rightError: Throwable) {
|
||||
val error = JsonSyntaxException("Can't read Either of values (left is $left, right is $right)")
|
||||
error.addSuppressed(leftError)
|
||||
error.addSuppressed(rightError)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
} as TypeAdapter<T>
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSpliterator
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSpliterators
|
||||
import java.util.stream.Stream
|
||||
import java.util.stream.StreamSupport
|
||||
|
||||
class JsonArraySpliterator(private val obj: JsonArray, offset: Int = 0, private val maxPos: Int = obj.size()) : ObjectSpliterators.AbstractIndexBasedSpliterator<JsonElement>(offset) {
|
||||
init {
|
||||
require(offset >= 0) { "Invalid offset $offset" }
|
||||
require(offset + maxPos <= obj.size()) { "$offset -> $maxPos while having only size of ${obj.size()}!" }
|
||||
}
|
||||
|
||||
override fun get(location: Int): JsonElement {
|
||||
return obj[location]
|
||||
}
|
||||
|
||||
override fun getMaxPos(): Int {
|
||||
return maxPos
|
||||
}
|
||||
|
||||
override fun makeForSplit(pos: Int, maxPos: Int): ObjectSpliterator<JsonElement> {
|
||||
return JsonArraySpliterator(obj, pos, maxPos)
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonArray.elementSpliterator() = JsonArraySpliterator(this)
|
||||
fun JsonArray.stream(): Stream<out JsonElement> = StreamSupport.stream(elementSpliterator(), false)
|
407
gson/src/main/kotlin/ru/dbotthepony/kommons/gson/JsonUtils.kt
Normal file
407
gson/src/main/kotlin/ru/dbotthepony/kommons/gson/JsonUtils.kt
Normal file
@ -0,0 +1,407 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSyntaxException
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
|
||||
fun <T> TypeAdapter<T>.transformRead(transformer: (T) -> T): TypeAdapter<T> {
|
||||
return object : TypeAdapter<T>() {
|
||||
override fun write(out: JsonWriter, value: T) {
|
||||
return this@transformRead.write(out, value)
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): T {
|
||||
return transformer(this@transformRead.read(`in`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> TypeAdapter<T>.transformWrite(transformer: (T) -> T): TypeAdapter<T> {
|
||||
return object : TypeAdapter<T>() {
|
||||
override fun write(out: JsonWriter, value: T) {
|
||||
return this@transformWrite.write(out, transformer(value))
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): T {
|
||||
return this@transformWrite.read(`in`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <In, Out> TypeAdapter<In>.transform(read: (In) -> Out, write: (Out) -> In): TypeAdapter<Out> {
|
||||
return object : TypeAdapter<Out>() {
|
||||
override fun write(out: JsonWriter, value: Out) {
|
||||
return this@transform.write(out, write(value))
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Out {
|
||||
return read(this@transform.read(`in`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> TypeAdapter<T>.ifString(reader: (String) -> T): TypeAdapter<T> {
|
||||
return object : TypeAdapter<T>() {
|
||||
override fun write(out: JsonWriter, value: T) {
|
||||
return this@ifString.write(out, value)
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): T {
|
||||
if (`in`.peek() == JsonToken.STRING) {
|
||||
return reader(`in`.nextString())
|
||||
}
|
||||
|
||||
return this@ifString.read(`in`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> TypeAdapter<T?>.neverNull(): TypeAdapter<T> {
|
||||
return object : TypeAdapter<T>() {
|
||||
override fun write(out: JsonWriter, value: T) {
|
||||
this@neverNull.write(out, value)
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): T {
|
||||
val path = `in`.path
|
||||
return this@neverNull.read(`in`) ?: throw JsonSyntaxException("Value was null near $path")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> TypeAdapter<T>.allowNull(): TypeAdapter<T?> = nullSafe()
|
||||
|
||||
fun JsonReader.consumeNull(): Boolean {
|
||||
if (peek() == JsonToken.NULL) {
|
||||
nextNull()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun JsonWriter.value(element: JsonPrimitive) {
|
||||
if (element.isBoolean) {
|
||||
value(element.asBoolean)
|
||||
} else if (element.isNumber) {
|
||||
value(element.asNumber)
|
||||
} else if (element.isString) {
|
||||
value(element.asString)
|
||||
} else {
|
||||
throw IllegalArgumentException(element.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonWriter.value(element: JsonNull) {
|
||||
nullValue()
|
||||
}
|
||||
|
||||
fun JsonWriter.value(element: JsonArray) {
|
||||
beginArray()
|
||||
for (v in element) value(v)
|
||||
endArray()
|
||||
}
|
||||
|
||||
fun JsonWriter.value(element: JsonObject) {
|
||||
beginObject()
|
||||
for ((k, v) in element.entrySet()) {
|
||||
name(k)
|
||||
value(v)
|
||||
}
|
||||
endObject()
|
||||
}
|
||||
|
||||
fun JsonWriter.value(element: JsonElement?) {
|
||||
when (element) {
|
||||
is JsonPrimitive -> value(element)
|
||||
is JsonNull -> value(element)
|
||||
is JsonArray -> value(element)
|
||||
is JsonObject -> value(element)
|
||||
null -> nullValue()
|
||||
else -> throw IllegalArgumentException(element.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonArray(elements: Collection<JsonElement>): JsonArray {
|
||||
return JsonArray(elements.size).also { elements.forEach(it::add) }
|
||||
}
|
||||
|
||||
fun JsonArray.clear() {
|
||||
while (size() > 0) {
|
||||
remove(size() - 1)
|
||||
}
|
||||
}
|
||||
|
||||
private val TRUE = JsonPrimitive(true)
|
||||
private val FALSE = JsonPrimitive(false)
|
||||
|
||||
operator fun JsonObject.set(key: String, value: JsonElement?) { add(key, value) }
|
||||
operator fun JsonObject.set(key: String, value: String) { add(key, JsonPrimitive(value)) }
|
||||
operator fun JsonObject.set(key: String, value: Int) { add(key, JsonPrimitive(value)) }
|
||||
operator fun JsonObject.set(key: String, value: Long) { add(key, JsonPrimitive(value)) }
|
||||
operator fun JsonObject.set(key: String, value: Float) { add(key, JsonPrimitive(value)) }
|
||||
operator fun JsonObject.set(key: String, value: Double) { add(key, JsonPrimitive(value)) }
|
||||
operator fun JsonObject.set(key: String, value: Boolean) { add(key, if (value) TRUE else FALSE) }
|
||||
operator fun JsonObject.set(key: String, value: Nothing?) { add(key, JsonNull.INSTANCE) }
|
||||
operator fun JsonObject.contains(key: String): Boolean = has(key)
|
||||
|
||||
fun JsonArray.get(key: Int, default: Boolean): Boolean {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isBoolean) {
|
||||
throw JsonSyntaxException("Expected boolean at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asBoolean
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: Boolean): Boolean {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isBoolean) {
|
||||
throw JsonSyntaxException("Expected boolean at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asBoolean
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: String): String {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isString) {
|
||||
throw JsonSyntaxException("Expected string at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asString
|
||||
}
|
||||
|
||||
fun JsonArray.get(key: Int, default: String): String {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isString) {
|
||||
throw JsonSyntaxException("Expected string at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asString
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: Int): Int {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isNumber) {
|
||||
throw JsonSyntaxException("Expected integer at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asInt
|
||||
}
|
||||
|
||||
fun JsonArray.get(key: Int, default: Int): Int {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isNumber) {
|
||||
throw JsonSyntaxException("Expected integer at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asInt
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: Long): Long {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isNumber) {
|
||||
throw JsonSyntaxException("Expected long at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asLong
|
||||
}
|
||||
|
||||
fun JsonArray.get(key: Int, default: Long): Long {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isNumber) {
|
||||
throw JsonSyntaxException("Expected long at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asLong
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: Double): Double {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isNumber) {
|
||||
throw JsonSyntaxException("Expected double at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asDouble
|
||||
}
|
||||
|
||||
fun JsonArray.get(key: Int, default: Double): Double {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonPrimitive || !value.isNumber) {
|
||||
throw JsonSyntaxException("Expected double at $key; got $value")
|
||||
}
|
||||
|
||||
return value.asDouble
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: JsonObject): JsonObject {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonObject)
|
||||
throw JsonSyntaxException("Expected json object at $key; got $value")
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
inline fun <reified T : JsonElement> JsonObject.get(key: String, default: () -> T): T {
|
||||
if (!has(key))
|
||||
return default.invoke()
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is T)
|
||||
throw JsonSyntaxException("Expected json object at $key; got $value")
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
fun JsonArray.get(key: Int, default: JsonObject): JsonObject {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonObject)
|
||||
throw JsonSyntaxException("Expected json object at $key; got $value")
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
inline fun JsonArray.get(key: Int, default: () -> JsonObject): JsonObject {
|
||||
if (key !in 0 until size())
|
||||
return default.invoke()
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonObject)
|
||||
throw JsonSyntaxException("Expected json object at $key; got $value")
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: JsonArray): JsonArray {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonArray)
|
||||
throw JsonSyntaxException("Expected json array at $key; got $value")
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
fun JsonArray.get(key: Int, default: JsonArray): JsonArray {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is JsonArray)
|
||||
throw JsonSyntaxException("Expected json array at $key; got $value")
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
inline fun <reified T : JsonElement> JsonArray.get(key: Int, default: () -> T): T {
|
||||
if (key !in 0 until size())
|
||||
return default.invoke()
|
||||
|
||||
val value = this[key]
|
||||
|
||||
if (value !is T)
|
||||
throw JsonSyntaxException("Expected json array at $key; got $value")
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
fun JsonObject.get(key: String, default: JsonPrimitive): JsonElement {
|
||||
if (!has(key))
|
||||
return default
|
||||
|
||||
return this[key]
|
||||
}
|
||||
|
||||
fun JsonArray.get(key: Int, default: JsonPrimitive): JsonElement {
|
||||
if (key !in 0 until size())
|
||||
return default
|
||||
|
||||
return this[key]
|
||||
}
|
||||
|
||||
fun <T> JsonObject.get(key: String, type: TypeAdapter<T>): T {
|
||||
return get(key, type) { throw JsonSyntaxException("Expected value at $key, got nothing") }
|
||||
}
|
||||
|
||||
inline fun <T> JsonObject.get(key: String, type: TypeAdapter<out T>, orElse: () -> T): T {
|
||||
if (!has(key))
|
||||
return orElse.invoke()
|
||||
|
||||
return type.fromJsonTree(this[key])
|
||||
}
|
||||
|
||||
fun JsonObject.getArray(key: String): JsonArray {
|
||||
if (!has(key)) throw JsonSyntaxException("Expected array at $key, got nothing")
|
||||
return this[key] as? JsonArray ?: throw JsonSyntaxException("Expected array at $key, got ${this[key]}")
|
||||
}
|
||||
|
||||
fun JsonObject.getObject(key: String): JsonObject {
|
||||
if (!has(key)) throw JsonSyntaxException("Expected object at $key, got nothing")
|
||||
return this[key] as? JsonObject ?: throw JsonSyntaxException("Expected object at $key, got ${this[key]}")
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package ru.dbotthepony.kommons.gson
|
||||
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
|
||||
object NothingAdapter : TypeAdapter<Nothing>() {
|
||||
override fun write(out: JsonWriter, value: Nothing?) {
|
||||
out.nullValue()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Nothing? {
|
||||
`in`.skipValue()
|
||||
return null
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package ru.dbotthepony.kommons.math
|
||||
|
||||
import ru.dbotthepony.kommons.core.IStruct4f
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
private fun hex(value: Int): String {
|
||||
@ -12,7 +13,7 @@ private fun hex(value: Int): String {
|
||||
return v
|
||||
}
|
||||
|
||||
class RGBAColor(red: Float, green: Float, blue: Float, alpha: Float = 1f) : Comparable<RGBAColor> {
|
||||
class RGBAColor(red: Float, green: Float, blue: Float, alpha: Float = 1f) : IStruct4f, Comparable<RGBAColor> {
|
||||
constructor(r: Int, g: Int, b: Int) : this((r / 255f), (g / 255f), (b / 255f), 1f)
|
||||
constructor(r: Int, g: Int, b: Int, a: Int) : this((r / 255f), (g / 255f), (b / 255f), (a / 255f))
|
||||
constructor(r: Int, g: Int, b: Int, a: Float) : this((r / 255f), (g / 255f), (b / 255f), a)
|
||||
@ -112,10 +113,10 @@ class RGBAColor(red: Float, green: Float, blue: Float, alpha: Float = 1f) : Comp
|
||||
return "RGBAColor[$red $green $blue $alpha]"
|
||||
}
|
||||
|
||||
operator fun component1() = red
|
||||
operator fun component2() = green
|
||||
operator fun component3() = blue
|
||||
operator fun component4() = alpha
|
||||
override fun component1() = red
|
||||
override fun component2() = green
|
||||
override fun component3() = blue
|
||||
override fun component4() = alpha
|
||||
|
||||
fun toIntInv(): Int {
|
||||
return (blueInt shl 16) or (greenInt shl 8) or redInt
|
||||
|
@ -13,3 +13,5 @@ include("io-math")
|
||||
include("collect")
|
||||
include("guava")
|
||||
include("linear-algebra")
|
||||
include("gson-math")
|
||||
include("gson")
|
||||
|
Loading…
Reference in New Issue
Block a user