1 /*
2  * Copyright 2021 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.compose.runtime.tooling
18 
19 import androidx.compose.runtime.CompositionContext
20 import androidx.compose.runtime.internal.JvmDefaultWithCompatibility
21 import androidx.compose.runtime.rememberCompositionContext
22 
23 /**
24  * A [CompositionData] is the data tracked by the composer during composition.
25  *
26  * This interface is not intended to be used directly and is provided to allow the tools API to have
27  * access to data tracked during composition. The tools API should be used instead which provides a
28  * more usable interpretation of the slot table.
29  */
30 interface CompositionData {
31     /**
32      * Iterate the composition data in the group. The composition data is structured as a tree of
33      * values that corresponds to the call graph of the functions that produced the tree.
34      * Interspersed are groups that represents the nodes themselves.
35      */
36     val compositionGroups: Iterable<CompositionGroup>
37 
38     /**
39      * Returns true if no composition data has been collected. This occurs when the first
40      * composition into this composition data has not completed yet or, if it is a group, it doesn't
41      * contain any child groups.
42      */
43     val isEmpty: Boolean
44 
45     /**
46      * Find a sub-group by identity. Returns `null` if the group is not found or the implementation
47      * of this interface does not support finding groups by their identity. In other words, a `null`
48      * result from this method should not be interpreted as the identity is not a group in the
49      * composition data.
50      */
findnull51     fun find(identityToFind: Any): CompositionGroup? = null
52 }
53 
54 /**
55  * [CompositionGroup] is a group of data slots tracked independently by composition. These groups
56  * correspond to flow control branches (such as if statements and function calls) as well as
57  * emitting of a node to the tree.
58  *
59  * This interface is not intended to be used directly and is provided to allow the tools API to have
60  * access to data tracked during composition. The tools API should be used instead which provides a
61  * more usable interpretation of the slot table.
62  */
63 @JvmDefaultWithCompatibility
64 interface CompositionGroup : CompositionData {
65     /**
66      * A value used to identify the group within its siblings and is typically a compiler generated
67      * integer but can be an object if the [key] composable is used.
68      */
69     val key: Any
70 
71     /**
72      * Information recorded by the compiler to help tooling identify the source that generated the
73      * group. The format of this string is internal and is interpreted by the tools API which
74      * translates this information into source file name and offsets.
75      */
76     val sourceInfo: String?
77 
78     /**
79      * If the group represents a node this returns a non-null value which is the node that was
80      * emitted for the group.
81      */
82     val node: Any?
83 
84     /**
85      * The data stored in the slot table for this group. This information includes the values stored
86      * for parameters that are checked for change, any value passed as a parameter for
87      * [androidx.compose.runtime.remember] and the last value returned by
88      * [androidx.compose.runtime.remember], etc.
89      */
90     val data: Iterable<Any?>
91 
92     /** A value that identifies a Group independently of movement caused by recompositions. */
93     val identity: Any?
94         get() = null
95 
96     /** The total number of groups, including itself, that this group contains. */
97     val groupSize: Int
98         get() = 0
99 
100     val slotsSize: Int
101         get() = 0
102 }
103 
104 /**
105  * [CompositionInstance] provides information about the composition of which a [CompositionData] is
106  * part.
107  */
108 interface CompositionInstance {
109     /**
110      * The parent composition instance, if the instance is part of a sub-composition. If this is the
111      * root of a composition (such as the content of a ComposeView), then [parent] will be `null`.
112      */
113     val parent: CompositionInstance?
114 
115     /** The [CompositionData] for the instance */
116     val data: CompositionData
117 
118     /**
119      * Find the [CompositionGroup] that contains the [CompositionContext] created by a call to
120      * [rememberCompositionContext] that is the parent context for this composition. If this is the
121      * root of the composition (e.g. [parent] is `null`) then this method also returns `null`.
122      */
findContextGroupnull123     fun findContextGroup(): CompositionGroup?
124 }
125 
126 /**
127  * Find the [CompositionInstance] associated with the root [CompositionData]. This is only valid for
128  * instances of [CompositionData] that are recorded in a [LocalInspectionTables] table directly.
129  *
130  * Even though [CompositionGroup]s implement the [CompositionData] interface, only the root
131  * [CompositionData] has an associated [CompositionInstance]. All [CompositionGroup] instances will
132  * return `null`.
133  */
134 fun CompositionData.findCompositionInstance(): CompositionInstance? = this as? CompositionInstance
135