1 /*
<lambda>null2  * Copyright 2023 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 package androidx.datastore.core
18 
19 import kotlinx.coroutines.flow.Flow
20 import kotlinx.coroutines.flow.MutableStateFlow
21 import kotlinx.coroutines.flow.updateAndGet
22 
23 /** This is where a [DataStoreImpl] instance keeps its actual data. */
24 internal class DataStoreInMemoryCache<T> {
25     @Suppress("UNCHECKED_CAST")
26     private val cachedValue: MutableStateFlow<State<T>> =
27         MutableStateFlow(UnInitialized as State<T>)
28 
29     val currentState: State<T>
30         get() = cachedValue.value
31 
32     val flow: Flow<State<T>>
33         get() = cachedValue
34 
35     /**
36      * Tries to update the current value if an only if the new given state's version is equal to or
37      * higher than the current state.
38      */
39     fun tryUpdate(newState: State<T>): State<T> {
40         val updated =
41             cachedValue.updateAndGet { cached ->
42                 when (cached) {
43                     is ReadException<T>,
44                     UnInitialized -> {
45                         // for ReadException and UnInitialized; we can always accept the new state.
46                         // this is especially useful when multiple reads fail so each can
47                         // send their own exception.
48                         newState
49                     }
50                     is Data<T> -> {
51                         // When overriding Data, only accept newer values.
52                         // Note that, when we have Data, we'll only every try to read again
53                         // if version changed, and it will arrive here as either new data or
54                         // new error with its new version.
55                         //
56                         // If a read happens in parallel to a write ("dirty read"), we will not
57                         // update
58                         // the cache here but make it local in the flow that does the dirty read. In
59                         // this cache we guarantee the version matches with the data because only
60                         // reads
61                         // that have file lock can set the cache.
62                         if (newState.version > cached.version) {
63                             newState
64                         } else {
65                             cached
66                         }
67                     }
68                     is Final<T> -> {
69                         // no going back from final state
70                         cached
71                     }
72                 }
73             }
74         return updated
75     }
76 }
77