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

codecs.extended.ClosedRangeJSONCodec.kt Maven / Gradle / Ivy

There is a newer version: 0.9.24
Show newest version
package com.github.fluidsonic.fluid.json


object ClosedRangeJSONCodec : AbstractJSONCodec, JSONCodingContext>() {

	override fun JSONDecoder.decode(valueType: JSONCodingType>): ClosedRange<*> {
		@Suppress("UNCHECKED_CAST")
		val elementType = valueType.arguments.single() as JSONCodingType>

		return when (elementType.rawClass) {
			Char::class -> decodeCharRange()
			Comparable::class -> decodeComparableRange()
			Double::class -> decodeDoubleRange()
			Float::class -> decodeFloatRange()
			Int::class -> decodeIntRange()
			Long::class -> decodeLongRange()
			else -> decodeOtherRange(elementType = elementType)
		}
	}


	@Suppress("UNCHECKED_CAST")
	private fun JSONDecoder.decodeComparableRange(): ClosedRange<*> {
		var endInclusive: Comparable? = null
		var start: Comparable? = null

		readFromMapByElementValue { key ->
			when (key) {
				Fields.endInclusive -> endInclusive = readValue() as? Comparable
					?: invalidPropertyError(key, details = "expected a comparable value")

				Fields.start -> start = readValue() as? Comparable
					?: invalidPropertyError(key, details = "expected a comparable value")

				else -> skipValue()
			}
		}

		return (start ?: missingPropertyError(Fields.start)) .. (endInclusive ?: missingPropertyError(Fields.endInclusive))
	}


	private fun JSONDecoder.decodeCharRange() =
		CharRangeJSONCodec.run { decode(valueType = CharRangeJSONCodec.decodableType) }


	private fun JSONDecoder.decodeDoubleRange(): ClosedFloatingPointRange {
		var endInclusive = 0.0
		var endInclusiveProvided = false
		var start = 0.0
		var startProvided = false

		readFromMapByElementValue { key ->
			when (key) {
				Fields.endInclusive -> {
					endInclusive = readDouble()
					endInclusiveProvided = true
				}
				Fields.start -> {
					start = readDouble()
					startProvided = true
				}
				else -> skipValue()
			}
		}

		if (!startProvided) missingPropertyError(Fields.start)
		if (!endInclusiveProvided) missingPropertyError(Fields.endInclusive)

		return start .. endInclusive
	}


	private fun JSONDecoder.decodeFloatRange(): ClosedFloatingPointRange {
		var endInclusive = 0.0f
		var endInclusiveProvided = false
		var start = 0.0f
		var startProvided = false

		readFromMapByElementValue { key ->
			when (key) {
				Fields.endInclusive -> {
					endInclusive = readFloat()
					endInclusiveProvided = true
				}
				Fields.start -> {
					start = readFloat()
					startProvided = true
				}
				else -> skipValue()
			}
		}

		if (!startProvided) missingPropertyError(Fields.start)
		if (!endInclusiveProvided) missingPropertyError(Fields.endInclusive)

		return start .. endInclusive
	}


	private fun JSONDecoder.decodeIntRange() =
		IntRangeJSONCodec.run { decode(valueType = IntRangeJSONCodec.decodableType) }


	private fun JSONDecoder.decodeLongRange() =
		LongRangeJSONCodec.run { decode(valueType = LongRangeJSONCodec.decodableType) }


	private fun JSONDecoder.decodeOtherRange(elementType: JSONCodingType>): ClosedRange<*> {
		var endInclusive: Comparable? = null
		var start: Comparable? = null

		readFromMapByElementValue { key ->
			when (key) {
				Fields.endInclusive -> endInclusive = readValueOfType(elementType)
				Fields.start -> start = readValueOfType(elementType)
				else -> skipValue()
			}
		}

		return (start ?: missingPropertyError(Fields.start)) .. (endInclusive ?: missingPropertyError(Fields.endInclusive))
	}


	override fun JSONEncoder.encode(value: ClosedRange<*>) {
		writeIntoMap {
			writeMapElement(Fields.start, value = value.start)
			writeMapElement(Fields.endInclusive, value = value.endInclusive)
		}
	}


	private object Fields {

		const val endInclusive = "endInclusive"
		const val start = "start"
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy