SnapshotFloatState.kt
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("PrimitiveSnapshotStateKt")
@file:JvmMultifileClass
package androidx.compose.runtime
import androidx.compose.runtime.snapshots.AutoboxingStateValueProperty
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.snapshots.SnapshotMutableState
import androidx.compose.runtime.snapshots.StateObject
import androidx.compose.runtime.snapshots.StateRecord
import androidx.compose.runtime.snapshots.overwritable
import androidx.compose.runtime.snapshots.readable
import androidx.compose.runtime.snapshots.withCurrent
import kotlin.reflect.KProperty
/**
* Return a new [MutableFloatState] initialized with the passed in [value]
*
* The MutableFloatState class is a single value holder whose reads and writes are observed by
* Compose. Additionally, writes to it are transacted as part of the [Snapshot] system. On the JVM,
* values are stored in memory as the primitive `float` type, avoiding the autoboxing that occurs
* when using `MutableState<Float>`.
*
* @param value the initial value for the [MutableFloatState]
*
* @see FloatState
* @see MutableFloatState
*/
fun mutableStateOf(
value: Float
): MutableFloatState = createSnapshotMutableFloatState(value)
/**
* A value holder where reads to the [floatValue] property during the execution of a [Composable]
* function cause the current [RecomposeScope] to subscribe to changes of that value.
*
* @see MutableFloatState
* @see mutableStateOf
*/
@Stable
@JvmDefaultWithCompatibility
interface FloatState : State<Float> {
@AutoboxingStateValueProperty("floatValue")
override val value: Float
@Suppress("AutoBoxing") get() = floatValue
val floatValue: Float
}
/**
* Permits property delegation of `val`s using `by` for [FloatState].
*/
@Suppress("NOTHING_TO_INLINE")
inline operator fun FloatState.getValue(thisObj: Any?, property: KProperty<*>): Float = floatValue
/**
* A value holder where reads to the [floatValue] property during the execution of a [Composable]
* function cause the current [RecomposeScope] to subscribe to changes of that value. When the
* [floatValue] property is written to and changed, a recomposition of any subscribed [RecomposeScope]s
* will be scheduled. If [floatValue] is written to with the same value, no recompositions will be
* scheduled.
*
* @see [FloatState]
* @see [mutableStateOf]
*/
@Stable
@JvmDefaultWithCompatibility
interface MutableFloatState : FloatState, MutableState<Float> {
@AutoboxingStateValueProperty("floatValue")
override var value: Float
@Suppress("AutoBoxing") get() = floatValue
set(value) { floatValue = value }
override var floatValue: Float
}
/**
* Permits property delegation of `var`s using `by` for [MutableFloatState].
*/
@Suppress("NOTHING_TO_INLINE")
inline operator fun MutableFloatState.setValue(
thisObj: Any?,
property: KProperty<*>,
value: Float
) {
this.floatValue = value
}
internal expect fun createSnapshotMutableFloatState(
value: Float
): MutableFloatState
/**
* A single value holder whose reads and writes are observed by Compose.
*
* Additionally, writes to it are transacted as part of the [Snapshot] system.
*
* @param value the wrapped value
*
* @see [mutableStateOf]
*/
internal open class SnapshotMutableFloatStateImpl(
value: Float
) : StateObject, MutableFloatState, SnapshotMutableState<Float> {
private var next = FloatStateStateRecord(value)
override val firstStateRecord: StateRecord
get() = next
override var floatValue: Float
get() = next.readable(this).value
set(value) = next.withCurrent {
if (it.value != value) {
next.overwritable(this, it) { this.value = value }
}
}
// Arbitrary policies are not allowed. The underlying `==` implementation
// for primitive types corresponds to structural equality
override val policy: SnapshotMutationPolicy<Float>
get() = structuralEqualityPolicy()
override fun component1(): Float = floatValue
override fun component2(): (Float) -> Unit = { floatValue = it }
override fun prependStateRecord(value: StateRecord) {
next = value as FloatStateStateRecord
}
override fun mergeRecords(
previous: StateRecord,
current: StateRecord,
applied: StateRecord
): StateRecord? {
val currentRecord = current as FloatStateStateRecord
val appliedRecord = applied as FloatStateStateRecord
return if (currentRecord.value == appliedRecord.value) {
current
} else {
null
}
}
override fun toString(): String = next.withCurrent {
"MutableFloatState(value=${it.value})@${hashCode()}"
}
private class FloatStateStateRecord(
var value: Float
) : StateRecord() {
override fun assign(value: StateRecord) {
this.value = (value as FloatStateStateRecord).value
}
override fun create(): StateRecord = FloatStateStateRecord(value)
}
}