mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-17 14:29:24 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
c9e320b72a | |||
555956087d | |||
b3f468f901 | |||
f5f7511781 | |||
4be1d93f60 | |||
7d684608ef | |||
2c7fd320eb | |||
88ee82e1c6 | |||
d6402c624e | |||
8b9c93bc10 | |||
4f5e261d01 | |||
cf455aebe6 |
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,5 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
## 0.17.4
|
||||
|
||||
* `Serialization`:
|
||||
* `Mapper`:
|
||||
* Module inited
|
||||
* `Versions`:
|
||||
* `Compose`: `1.3.1-rc02` -> `1.3.1`
|
||||
|
||||
## 0.17.3
|
||||
|
||||
* `Common`:
|
||||
* Add `fixed` extensions for `Float` and `Double`
|
||||
* New function `emptyDiff`
|
||||
* Now you may pass custom `comparisonFun` to all `diff` functions
|
||||
|
||||
## 0.17.2
|
||||
|
||||
* `FSM`:
|
||||
|
@@ -34,7 +34,11 @@ data class Diff<T> internal constructor(
|
||||
*/
|
||||
val replaced: List<Pair<@Serializable(IndexedValueSerializer::class) IndexedValue<T>, @Serializable(IndexedValueSerializer::class) IndexedValue<T>>>,
|
||||
val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>
|
||||
)
|
||||
) {
|
||||
fun isEmpty(): Boolean = removed.isEmpty() && replaced.isEmpty() && added.isEmpty()
|
||||
}
|
||||
|
||||
fun <T> emptyDiff(): Diff<T> = Diff(emptyList(), emptyList(), emptyList())
|
||||
|
||||
private inline fun <T> performChanges(
|
||||
potentialChanges: MutableList<Pair<IndexedValue<T>?, IndexedValue<T>?>>,
|
||||
@@ -43,14 +47,14 @@ private inline fun <T> performChanges(
|
||||
changedList: MutableList<Pair<IndexedValue<T>, IndexedValue<T>>>,
|
||||
removedList: MutableList<IndexedValue<T>>,
|
||||
addedList: MutableList<IndexedValue<T>>,
|
||||
strictComparison: Boolean
|
||||
comparisonFun: (T?, T?) -> Boolean
|
||||
) {
|
||||
var i = -1
|
||||
val (oldObject, newObject) = potentialChanges.lastOrNull() ?: return
|
||||
for ((old, new) in potentialChanges.take(potentialChanges.size - 1)) {
|
||||
i++
|
||||
val oldOneEqualToNewObject = old ?.value === newObject ?.value || (old ?.value == newObject ?.value && !strictComparison)
|
||||
val newOneEqualToOldObject = new ?.value === oldObject ?.value || (new ?.value == oldObject ?.value && !strictComparison)
|
||||
val oldOneEqualToNewObject = comparisonFun(old ?.value, newObject ?.value)
|
||||
val newOneEqualToOldObject = comparisonFun(new ?.value, oldObject ?.value)
|
||||
if (oldOneEqualToNewObject || newOneEqualToOldObject) {
|
||||
changedList.addAll(
|
||||
potentialChanges.take(i).mapNotNull {
|
||||
@@ -104,7 +108,7 @@ private inline fun <T> performChanges(
|
||||
*/
|
||||
fun <T> Iterable<T>.calculateDiff(
|
||||
other: Iterable<T>,
|
||||
strictComparison: Boolean = false
|
||||
comparisonFun: (T?, T?) -> Boolean
|
||||
): Diff<T> {
|
||||
var i = -1
|
||||
var j = -1
|
||||
@@ -132,7 +136,7 @@ fun <T> Iterable<T>.calculateDiff(
|
||||
}
|
||||
|
||||
when {
|
||||
oldObject === newObject || (oldObject == newObject && !strictComparison) -> {
|
||||
comparisonFun(oldObject, newObject) -> {
|
||||
changedObjects.addAll(potentiallyChangedObjects.map {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
it as Pair<IndexedValue<T>, IndexedValue<T>>
|
||||
@@ -143,23 +147,49 @@ fun <T> Iterable<T>.calculateDiff(
|
||||
potentiallyChangedObjects.add(oldObject ?.let { IndexedValue(i, oldObject) } to newObject ?.let { IndexedValue(j, newObject) })
|
||||
val previousOldsAdditionsSize = additionalInOld.size
|
||||
val previousNewsAdditionsSize = additionalInNew.size
|
||||
performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, strictComparison)
|
||||
performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, comparisonFun)
|
||||
i -= (additionalInOld.size - previousOldsAdditionsSize)
|
||||
j -= (additionalInNew.size - previousNewsAdditionsSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
potentiallyChangedObjects.add(null to null)
|
||||
performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, strictComparison)
|
||||
performChanges(potentiallyChangedObjects, additionalInOld, additionalInNew, changedObjects, removedObjects, addedObjects, comparisonFun)
|
||||
|
||||
return Diff(removedObjects.toList(), changedObjects.toList(), addedObjects.toList())
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculating [Diff] object
|
||||
*
|
||||
* @param strictComparison If this parameter set to true, objects which are not equal by links will be used as different
|
||||
* objects. For example, in case of two "Example" string they will be equal by value, but CAN be different by links
|
||||
*/
|
||||
fun <T> Iterable<T>.calculateDiff(
|
||||
other: Iterable<T>,
|
||||
strictComparison: Boolean = false
|
||||
): Diff<T> = calculateDiff(
|
||||
other,
|
||||
comparisonFun = if (strictComparison) {
|
||||
{ t1, t2 ->
|
||||
t1 === t2
|
||||
}
|
||||
} else {
|
||||
{ t1, t2 ->
|
||||
t1 === t2 || t1 == t2 // small optimization for cases when t1 and t2 are the same - comparison will be faster potentially
|
||||
}
|
||||
}
|
||||
)
|
||||
inline fun <T> Iterable<T>.diff(
|
||||
other: Iterable<T>,
|
||||
strictComparison: Boolean = false
|
||||
): Diff<T> = calculateDiff(other, strictComparison)
|
||||
inline fun <T> Iterable<T>.diff(
|
||||
other: Iterable<T>,
|
||||
noinline comparisonFun: (T?, T?) -> Boolean
|
||||
): Diff<T> = calculateDiff(other, comparisonFun)
|
||||
|
||||
inline fun <T> Diff(old: Iterable<T>, new: Iterable<T>) = old.calculateDiff(new)
|
||||
inline fun <T> Diff(old: Iterable<T>, new: Iterable<T>) = old.calculateDiff(new, strictComparison = false)
|
||||
inline fun <T> StrictDiff(old: Iterable<T>, new: Iterable<T>) = old.calculateDiff(new, true)
|
||||
|
||||
/**
|
||||
@@ -187,3 +217,22 @@ fun <T> MutableList<T>.applyDiff(
|
||||
set(new.index, new.value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method call [calculateDiff] with strict mode [strictComparison] and then apply differences to [this]
|
||||
* mutable list
|
||||
*/
|
||||
fun <T> MutableList<T>.applyDiff(
|
||||
source: Iterable<T>,
|
||||
comparisonFun: (T?, T?) -> Boolean
|
||||
): Diff<T> = calculateDiff(source, comparisonFun).also {
|
||||
for (i in it.removed.indices.sortedDescending()) {
|
||||
removeAt(it.removed[i].index)
|
||||
}
|
||||
it.added.forEach { (i, t) ->
|
||||
add(i, t)
|
||||
}
|
||||
it.replaced.forEach { (_, new) ->
|
||||
set(new.index, new.value)
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
val FixedSignsRange = 0 .. 100
|
||||
|
||||
expect fun Float.fixed(signs: Int): Float
|
||||
expect fun Double.fixed(signs: Int): Double
|
@@ -0,0 +1,4 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
actual fun Float.fixed(signs: Int): Float = this.asDynamic().toFixed(signs.coerceIn(FixedSignsRange)).unsafeCast<String>().toFloat()
|
||||
actual fun Double.fixed(signs: Int): Double = this.asDynamic().toFixed(signs.coerceIn(FixedSignsRange)).unsafeCast<String>().toDouble()
|
@@ -0,0 +1,12 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
actual fun Float.fixed(signs: Int): Float = BigDecimal.valueOf(this.toDouble())
|
||||
.setScale(signs.coerceIn(FixedSignsRange), RoundingMode.HALF_UP)
|
||||
.toFloat();
|
||||
|
||||
actual fun Double.fixed(signs: Int): Double = BigDecimal.valueOf(this)
|
||||
.setScale(signs.coerceIn(FixedSignsRange), RoundingMode.HALF_UP)
|
||||
.toDouble();
|
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
|
||||
# Project data
|
||||
|
||||
group=dev.inmo
|
||||
version=0.17.2
|
||||
android_code_version=184
|
||||
version=0.17.4
|
||||
android_code_version=186
|
||||
|
@@ -6,7 +6,7 @@ kt-coroutines = "1.6.4"
|
||||
|
||||
kslog = "1.0.0"
|
||||
|
||||
jb-compose = "1.3.1-rc01"
|
||||
jb-compose = "1.3.1"
|
||||
jb-exposed = "0.41.1"
|
||||
jb-dokka = "1.7.20"
|
||||
|
||||
|
7
serialization/mapper/build.gradle
Normal file
7
serialization/mapper/build.gradle
Normal file
@@ -0,0 +1,7 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "org.jetbrains.kotlin.plugin.serialization"
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppProjectWithSerializationPresetPath"
|
99
serialization/mapper/src/commonMain/kotlin/Extensions.kt
Normal file
99
serialization/mapper/src/commonMain/kotlin/Extensions.kt
Normal file
@@ -0,0 +1,99 @@
|
||||
package dev.inmo.micro_utils.serialization.mapper
|
||||
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.InternalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
import kotlinx.serialization.serializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Will create [MapperSerializationStrategy] to allow you to map [O] to [I] using [serialize] lambda during
|
||||
* serialization process
|
||||
*/
|
||||
inline fun <reified I : Any, O> SerializationStrategy<I>.mapSerialization(
|
||||
noinline serialize: (O) -> I
|
||||
) = MapperSerializationStrategy(
|
||||
this,
|
||||
serialize
|
||||
)
|
||||
|
||||
/**
|
||||
* Will create [MapperDeserializationStrategy] to allow you to map [I] to [O] using [deserialize] lambda during
|
||||
* deserialization process
|
||||
*/
|
||||
inline fun <reified I : Any, O> DeserializationStrategy<I>.mapDeserialization(
|
||||
noinline deserialize: (I) -> O
|
||||
) = MapperDeserializationStrategy(
|
||||
this,
|
||||
deserialize
|
||||
)
|
||||
|
||||
/**
|
||||
* Will create [MapperSerializer] to allow you to map [O] to [I] and vice verse using [serialize]/[deserialize] lambda during
|
||||
* serialization/deserialization process
|
||||
*/
|
||||
inline fun <reified I : Any, O> KSerializer<I>.mapFullSerialization(
|
||||
noinline serialize: (O) -> I,
|
||||
noinline deserialize: (I) -> O
|
||||
) = MapperSerializer(
|
||||
this,
|
||||
serialize,
|
||||
deserialize
|
||||
)
|
||||
|
||||
/**
|
||||
* Will create [MapperSerializationStrategy] to allow you to map [O] to [I] using [serialize] lambda during
|
||||
* serialization process
|
||||
*/
|
||||
@OptIn(InternalSerializationApi::class)
|
||||
inline fun <reified I : Any, O> KClass<I>.mapSerialization(
|
||||
serializer: SerializationStrategy<I> = serializer(),
|
||||
noinline serialize: (O) -> I
|
||||
) = serializer.mapSerialization(serialize)
|
||||
|
||||
/**
|
||||
* Will create [MapperDeserializationStrategy] to allow you to map [I] to [O] using [deserialize] lambda during
|
||||
* deserialization process
|
||||
*/
|
||||
@OptIn(InternalSerializationApi::class)
|
||||
inline fun <reified I : Any, O> KClass<I>.mapDeserialization(
|
||||
serializer: DeserializationStrategy<I> = serializer(),
|
||||
noinline deserialize: (I) -> O
|
||||
) = serializer.mapDeserialization(deserialize)
|
||||
|
||||
/**
|
||||
* Will create [MapperSerializer] to allow you to map [O] to [I] and vice verse using [serialize]/[deserialize] lambda during
|
||||
* serialization/deserialization process
|
||||
*/
|
||||
@OptIn(InternalSerializationApi::class)
|
||||
inline fun <reified I : Any, O> KClass<I>.mapFullSerialization(
|
||||
serializer: KSerializer<I> = serializer(),
|
||||
noinline serialize: (O) -> I,
|
||||
noinline deserialize: (I) -> O
|
||||
) = serializer.mapFullSerialization(serialize, deserialize)
|
||||
|
||||
/**
|
||||
* Will create [MapperSerializationStrategy] to allow you to map [O] to [I] using [serialize] lambda during
|
||||
* serialization process
|
||||
*/
|
||||
inline fun <reified I : Any, O> mappedSerializationStrategy(
|
||||
noinline serialize: (O) -> I,
|
||||
) = serializer<I>().mapSerialization(serialize)
|
||||
|
||||
/**
|
||||
* Will create [MapperDeserializationStrategy] to allow you to map [I] to [O] using [deserialize] lambda during
|
||||
* deserialization process
|
||||
*/
|
||||
inline fun <reified I : Any, O> mappedDeserializationStrategy(
|
||||
noinline deserialize: (I) -> O
|
||||
) = serializer<I>().mapDeserialization(deserialize)
|
||||
|
||||
/**
|
||||
* Will create [MapperSerializer] to allow you to map [O] to [I] and vice verse using [serialize]/[deserialize] lambda during
|
||||
* serialization/deserialization process
|
||||
*/
|
||||
inline fun <reified I : Any, O> mappedSerializer(
|
||||
noinline serialize: (O) -> I,
|
||||
noinline deserialize: (I) -> O
|
||||
) = serializer<I>().mapFullSerialization(serialize, deserialize)
|
@@ -0,0 +1,26 @@
|
||||
package dev.inmo.micro_utils.serialization.mapper
|
||||
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
/**
|
||||
* Use this serializer when you have deserializable type [I] and want to map it to some [O] in process of
|
||||
* deserialization
|
||||
*
|
||||
* @param base Serializer for [I]
|
||||
* @param deserialize Will be used in [deserialize] method to convert deserialized by [base] [I] to [O]
|
||||
*/
|
||||
open class MapperDeserializationStrategy<I, O>(
|
||||
private val base: DeserializationStrategy<I>,
|
||||
private val deserialize: (I) -> O
|
||||
) : DeserializationStrategy<O> {
|
||||
override val descriptor: SerialDescriptor = base.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): O {
|
||||
return deserialize(base.deserialize(decoder))
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package dev.inmo.micro_utils.serialization.mapper
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
/**
|
||||
* Use this serializer when you have serializable type [I] and want to map it to some [O] in process of
|
||||
* serialization
|
||||
*
|
||||
* @param base Serializer for [I]
|
||||
* @param serialize Will be used in [serialize] method to convert incoming [O] to [I] and serialize with [base]
|
||||
*/
|
||||
open class MapperSerializationStrategy<I, O>(
|
||||
private val base: SerializationStrategy<I>,
|
||||
private val serialize: (O) -> I
|
||||
) : SerializationStrategy<O> {
|
||||
override val descriptor: SerialDescriptor = base.descriptor
|
||||
|
||||
override fun serialize(encoder: Encoder, value: O) {
|
||||
base.serialize(encoder, serialize(value))
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package dev.inmo.micro_utils.serialization.mapper
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
/**
|
||||
* Use this serializer when you have serializable type [I] and want to map it to some [O] in process of
|
||||
* serialization/deserialization
|
||||
*
|
||||
* @param base Serializer for [I]
|
||||
* @param serialize Will be used in [serialize] method to convert incoming [O] to [I] and serialize with [base]
|
||||
* @param deserialize Will be used in [deserialize] method to convert deserialized by [base] [I] to [O]
|
||||
*/
|
||||
open class MapperSerializer<I, O>(
|
||||
private val base: KSerializer<I>,
|
||||
private val serialize: (O) -> I,
|
||||
private val deserialize: (I) -> O
|
||||
) : KSerializer<O> {
|
||||
override val descriptor: SerialDescriptor = base.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): O {
|
||||
return deserialize(base.deserialize(decoder))
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: O) {
|
||||
base.serialize(encoder, serialize(value))
|
||||
}
|
||||
}
|
1
serialization/mapper/src/main/AndroidManifest.xml
Normal file
1
serialization/mapper/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest package="dev.inmo.micro_utils.serialization.mapper"/>
|
@@ -37,6 +37,7 @@ String[] includes = [
|
||||
":serialization:base64",
|
||||
":serialization:encapsulator",
|
||||
":serialization:typed_serializer",
|
||||
":serialization:mapper",
|
||||
":startup:plugin",
|
||||
":startup:launcher",
|
||||
|
||||
|
Reference in New Issue
Block a user