russhwolf / multiplatform-settings

A Kotlin Multiplatform library for saving simple key-value data
Apache License 2.0
1.69k stars 67 forks source link

Serialization support for FlowSettings #72

Open xsveda opened 3 years ago

xsveda commented 3 years ago

Are there any ideas or plans how to introduce kotlinx.serialization support also for FlowSettings?

As both multiplatform-settings-serialization and multiplatform-settings-coroutines are independent it might end up in a completely new module, actually maybe more than one as we have also native-mt and datastore variants.

Or is there any other option that would not lead to module number explosion?

russhwolf commented 3 years ago

I haven't given this much thought yet. I want to get a sense of what is and isn't working about each part separately first. Serialization, like the original Settings API, is by nature synchronous which complicates things. For now, you can probably do something like val settings = flowSettings.toBlockingSettings() and use the serialization extensions from there. This will wrap all suspend and flow calls in runBlocking.

xsveda commented 3 years ago

My idea is to have serialization support when observing certain value using getXxxFlow(). So next to fun <T> Settings.decodeValue(serializer, key, defaultValue: T, serializersModule): T we would have fun <T> FlowSettings.getDecodedValueFlow(serializer, key, defaultValue: T, serializersModule): Flow<T>

russhwolf commented 3 years ago

Oh I see. That's worth some thought but I still want to let everything settle a bit in it's current form first.

In the meantime it should be fairly easy to get something working by hand if you look at what the Flow extensions are doing currently. They're all powered by this one simple function which is private but you could copy it into your project and call it or modify as needed.

kansson commented 1 year ago

Oh I see. That's worth some thought but I still want to let everything settle a bit in it's current form first.

In the meantime it should be fairly easy to get something working by hand if you look at what the Flow extensions are doing currently. They're all powered by this one simple function which is private but you could copy it into your project and call it or modify as needed.

Do you have an example of a working function that combines a serialized value with a flow? Thanks!

russhwolf commented 1 year ago

Oh, the original workaround I had in mind here breaks in 1.0 with the untyped addListener() no longer present. Will need to think about this some more. It's an awkward tradeoff between the needs of ObservableSettings, SuspendSettings/FlowSettings, and the serialization extensions.

Giuliopime commented 1 year ago

Wouldn't it be better to use kotlinx serialization to serialize and deserialize stuff, so implementing it on flows would be as simple as

@OptIn(ExperimentalSettingsApi::class)
inline fun <reified T> FlowSettings.getDecodeValueFlow(
    key: String,
    defaultValue: T
): Flow<T> =  getStringOrNullFlow(key).map {
    it?.let {
        Json.decodeFromString<T>(it)
    } ?: defaultValue
}

@OptIn(ExperimentalSettingsApi::class)
inline fun <reified T> Settings.encodeValue(
    key: String,
    value: T,
) = set(key, Json.encodeToString(value))

kotlinx serialization supports kotlin multiplatform so there should be no compatibility issues

russhwolf commented 1 year ago

@Giuliopime Something like that is easy to implement yourself if you want it. The purpose here is to use the settings store itself as the serialization format, rather than JSON.