1 /*
<lambda>null2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 @file:JvmName("SnapshotStateKt")
18 @file:JvmMultifileClass
19 
20 package androidx.compose.runtime
21 
22 import androidx.compose.runtime.snapshots.GlobalSnapshot
23 import androidx.compose.runtime.snapshots.Snapshot
24 import androidx.compose.runtime.snapshots.SnapshotId
25 import androidx.compose.runtime.snapshots.SnapshotMutableState
26 import androidx.compose.runtime.snapshots.SnapshotStateList
27 import androidx.compose.runtime.snapshots.SnapshotStateMap
28 import androidx.compose.runtime.snapshots.SnapshotStateSet
29 import androidx.compose.runtime.snapshots.StateFactoryMarker
30 import androidx.compose.runtime.snapshots.StateObjectImpl
31 import androidx.compose.runtime.snapshots.StateRecord
32 import androidx.compose.runtime.snapshots.currentSnapshot
33 import androidx.compose.runtime.snapshots.overwritable
34 import androidx.compose.runtime.snapshots.readable
35 import androidx.compose.runtime.snapshots.toSnapshotId
36 import androidx.compose.runtime.snapshots.withCurrent
37 import kotlin.jvm.JvmMultifileClass
38 import kotlin.jvm.JvmName
39 import kotlin.reflect.KProperty
40 
41 /**
42  * Return a new [MutableState] initialized with the passed in [value]
43  *
44  * The MutableState class is a single value holder whose reads and writes are observed by Compose.
45  * Additionally, writes to it are transacted as part of the [Snapshot] system.
46  *
47  * @param value the initial value for the [MutableState]
48  * @param policy a policy to controls how changes are handled in mutable snapshots.
49  * @sample androidx.compose.runtime.samples.SimpleStateSample
50  * @sample androidx.compose.runtime.samples.DestructuredStateSample
51  * @sample androidx.compose.runtime.samples.observeUserSample
52  * @sample androidx.compose.runtime.samples.stateSample
53  * @see State
54  * @see MutableState
55  * @see SnapshotMutationPolicy
56  * @see mutableIntStateOf
57  * @see mutableLongStateOf
58  * @see mutableFloatStateOf
59  * @see mutableDoubleStateOf
60  */
61 @StateFactoryMarker
62 fun <T> mutableStateOf(
63     value: T,
64     policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
65 ): MutableState<T> = createSnapshotMutableState(value, policy)
66 
67 /**
68  * A value holder where reads to the [value] property during the execution of a [Composable]
69  * function, the current [RecomposeScope] will be subscribed to changes of that value.
70  *
71  * @see [MutableState]
72  * @see [mutableStateOf]
73  */
74 @Stable
75 interface State<out T> {
76     val value: T
77 }
78 
79 /**
80  * Permits property delegation of `val`s using `by` for [State].
81  *
82  * @sample androidx.compose.runtime.samples.DelegatedReadOnlyStateSample
83  */
84 @Suppress("NOTHING_TO_INLINE")
getValuenull85 inline operator fun <T> State<T>.getValue(thisObj: Any?, property: KProperty<*>): T = value
86 
87 /**
88  * A mutable value holder where reads to the [value] property during the execution of a [Composable]
89  * function, the current [RecomposeScope] will be subscribed to changes of that value. When the
90  * [value] property is written to and changed, a recomposition of any subscribed [RecomposeScope]s
91  * will be scheduled. If [value] is written to with the same value, no recompositions will be
92  * scheduled.
93  *
94  * @see [State]
95  * @see [mutableStateOf]
96  */
97 @Stable
98 interface MutableState<T> : State<T> {
99     override var value: T
100 
101     operator fun component1(): T
102 
103     operator fun component2(): (T) -> Unit
104 }
105 
106 /**
107  * Permits property delegation of `var`s using `by` for [MutableState].
108  *
109  * @sample androidx.compose.runtime.samples.DelegatedStateSample
110  */
111 @Suppress("NOTHING_TO_INLINE")
setValuenull112 inline operator fun <T> MutableState<T>.setValue(thisObj: Any?, property: KProperty<*>, value: T) {
113     this.value = value
114 }
115 
116 /** Returns platform specific implementation based on [SnapshotMutableStateImpl]. */
createSnapshotMutableStatenull117 internal expect fun <T> createSnapshotMutableState(
118     value: T,
119     policy: SnapshotMutationPolicy<T>
120 ): SnapshotMutableState<T>
121 
122 /**
123  * A single value holder whose reads and writes are observed by Compose.
124  *
125  * Additionally, writes to it are transacted as part of the [Snapshot] system.
126  *
127  * @param value the wrapped value
128  * @param policy a policy to control how changes are handled in a mutable snapshot.
129  * @see mutableStateOf
130  * @see SnapshotMutationPolicy
131  */
132 internal open class SnapshotMutableStateImpl<T>(
133     value: T,
134     override val policy: SnapshotMutationPolicy<T>
135 ) : StateObjectImpl(), SnapshotMutableState<T> {
136     @Suppress("UNCHECKED_CAST")
137     override var value: T
138         get() = next.readable(this).value
139         set(value) =
140             next.withCurrent {
141                 if (!policy.equivalent(it.value, value)) {
142                     next.overwritable(this, it) { this.value = value }
143                 }
144             }
145 
146     private var next: StateStateRecord<T> =
147         currentSnapshot().let { snapshot ->
148             StateStateRecord(snapshot.snapshotId, value).also {
149                 if (snapshot !is GlobalSnapshot) {
150                     it.next = StateStateRecord(Snapshot.PreexistingSnapshotId.toSnapshotId(), value)
151                 }
152             }
153         }
154 
155     override val firstStateRecord: StateRecord
156         get() = next
157 
158     override fun prependStateRecord(value: StateRecord) {
159         @Suppress("UNCHECKED_CAST")
160         next = value as StateStateRecord<T>
161     }
162 
163     @Suppress("UNCHECKED_CAST")
164     override fun mergeRecords(
165         previous: StateRecord,
166         current: StateRecord,
167         applied: StateRecord
168     ): StateRecord? {
169         val previousRecord = previous as StateStateRecord<T>
170         val currentRecord = current as StateStateRecord<T>
171         val appliedRecord = applied as StateStateRecord<T>
172         return if (policy.equivalent(currentRecord.value, appliedRecord.value)) current
173         else {
174             val merged =
175                 policy.merge(previousRecord.value, currentRecord.value, appliedRecord.value)
176             if (merged != null) {
177                 appliedRecord.create(appliedRecord.snapshotId).also { it.value = merged }
178             } else {
179                 null
180             }
181         }
182     }
183 
184     override fun toString(): String =
185         next.withCurrent { "MutableState(value=${it.value})@${hashCode()}" }
186 
187     private class StateStateRecord<T>(snapshotId: SnapshotId, myValue: T) :
188         StateRecord(snapshotId) {
189         override fun assign(value: StateRecord) {
190             @Suppress("UNCHECKED_CAST")
191             this.value = (value as StateStateRecord<T>).value
192         }
193 
194         override fun create() = StateStateRecord(currentSnapshot().snapshotId, value)
195 
196         override fun create(snapshotId: SnapshotId) =
197             StateStateRecord(currentSnapshot().snapshotId, value)
198 
199         var value: T = myValue
200     }
201 
202     /**
203      * The componentN() operators allow state objects to be used with the property destructuring
204      * syntax
205      *
206      * ```
207      * var (foo, setFoo) = remember { mutableStateOf(0) }
208      * setFoo(123) // set
209      * foo == 123 // get
210      * ```
211      */
212     override operator fun component1(): T = value
213 
214     override operator fun component2(): (T) -> Unit = { value = it }
215 
216     /**
217      * A function used by the debugger to display the value of the current value of the mutable
218      * state object without triggering read observers.
219      */
220     @Suppress("unused")
221     val debuggerDisplayValue: T
222         @JvmName("getDebuggerDisplayValue") get() = next.withCurrent { it }.value
223 }
224 
225 /**
226  * Create a instance of [MutableList]<T> that is observable and can be snapshot.
227  *
228  * @sample androidx.compose.runtime.samples.stateListSample
229  * @see mutableStateOf
230  * @see mutableListOf
231  * @see MutableList
232  * @see Snapshot.takeSnapshot
233  */
mutableStateListOfnull234 @StateFactoryMarker fun <T> mutableStateListOf() = SnapshotStateList<T>()
235 
236 /**
237  * Create an instance of [MutableList]<T> that is observable and can be snapshot.
238  *
239  * @see mutableStateOf
240  * @see mutableListOf
241  * @see MutableList
242  * @see Snapshot.takeSnapshot
243  */
244 @StateFactoryMarker
245 fun <T> mutableStateListOf(vararg elements: T) =
246     SnapshotStateList<T>().also { it.addAll(elements.toList()) }
247 
248 /**
249  * Create an instance of [MutableList]<T> from a collection that is observable and can be snapshot.
250  */
<lambda>null251 fun <T> Collection<T>.toMutableStateList() = SnapshotStateList<T>().also { it.addAll(this) }
252 
253 /**
254  * Create a instance of [MutableMap]<K, V> that is observable and can be snapshot.
255  *
256  * @sample androidx.compose.runtime.samples.stateMapSample
257  * @see mutableStateOf
258  * @see mutableMapOf
259  * @see MutableMap
260  * @see Snapshot.takeSnapshot
261  */
mutableStateMapOfnull262 @StateFactoryMarker fun <K, V> mutableStateMapOf() = SnapshotStateMap<K, V>()
263 
264 /**
265  * Create a instance of [MutableMap]<K, V> that is observable and can be snapshot.
266  *
267  * @see mutableStateOf
268  * @see mutableMapOf
269  * @see MutableMap
270  * @see Snapshot.takeSnapshot
271  */
272 @StateFactoryMarker
273 fun <K, V> mutableStateMapOf(vararg pairs: Pair<K, V>) =
274     SnapshotStateMap<K, V>().apply { putAll(pairs.toMap()) }
275 
276 /**
277  * Create an instance of [MutableMap]<K, V> from a collection of pairs that is observable and can be
278  * snapshot.
279  */
280 @Suppress("unused")
toMutableStateMapnull281 fun <K, V> Iterable<Pair<K, V>>.toMutableStateMap() =
282     SnapshotStateMap<K, V>().also { it.putAll(this.toMap()) }
283 
284 /**
285  * Create a instance of [MutableSet]<T> that is observable and can be snapshot.
286  *
287  * @sample androidx.compose.runtime.samples.stateListSample
288  * @see mutableStateOf
289  * @see mutableSetOf
290  * @see MutableSet
291  * @see Snapshot.takeSnapshot
292  */
mutableStateSetOfnull293 @StateFactoryMarker fun <T> mutableStateSetOf() = SnapshotStateSet<T>()
294 
295 /**
296  * Create an instance of [MutableSet]<T> that is observable and can be snapshot.
297  *
298  * @see mutableStateOf
299  * @see mutableSetOf
300  * @see MutableSet
301  * @see Snapshot.takeSnapshot
302  */
303 @StateFactoryMarker
304 fun <T> mutableStateSetOf(vararg elements: T) =
305     SnapshotStateSet<T>().also { it.addAll(elements.toSet()) }
306 
307 /**
308  * [remember] a [mutableStateOf] [newValue] and update its value to [newValue] on each recomposition
309  * of the [rememberUpdatedState] call.
310  *
311  * [rememberUpdatedState] should be used when parameters or values computed during composition are
312  * referenced by a long-lived lambda or object expression. Recomposition will update the resulting
313  * [State] without recreating the long-lived lambda or object, allowing that object to persist
314  * without cancelling and resubscribing, or relaunching a long-lived operation that may be expensive
315  * or prohibitive to recreate and restart. This may be common when working with [DisposableEffect]
316  * or [LaunchedEffect], for example:
317  *
318  * @sample androidx.compose.runtime.samples.rememberUpdatedStateSampleWithDisposableEffect
319  *
320  * [LaunchedEffect]s often describe state machines that should not be reset and restarted if a
321  * parameter or event callback changes, but they should have the current value available when
322  * needed. For example:
323  *
324  * @sample androidx.compose.runtime.samples.rememberUpdatedStateSampleWithLaunchedEffect
325  *
326  * By using [rememberUpdatedState] a composable function can update these operations in progress.
327  */
328 @Composable
rememberUpdatedStatenull329 fun <T> rememberUpdatedState(newValue: T): State<T> =
330     remember { mutableStateOf(newValue) }.apply { value = newValue }
331