xref: /aosp_15_r20/system/media/camera/docs/metadata_model.py (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1*b9df5ad1SAndroid Build Coastguard Worker#!/usr/bin/python
2*b9df5ad1SAndroid Build Coastguard Worker
3*b9df5ad1SAndroid Build Coastguard Worker#
4*b9df5ad1SAndroid Build Coastguard Worker# Copyright (C) 2012 The Android Open Source Project
5*b9df5ad1SAndroid Build Coastguard Worker#
6*b9df5ad1SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
7*b9df5ad1SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
8*b9df5ad1SAndroid Build Coastguard Worker# You may obtain a copy of the License at
9*b9df5ad1SAndroid Build Coastguard Worker#
10*b9df5ad1SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
11*b9df5ad1SAndroid Build Coastguard Worker#
12*b9df5ad1SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
13*b9df5ad1SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
14*b9df5ad1SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*b9df5ad1SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
16*b9df5ad1SAndroid Build Coastguard Worker# limitations under the License.
17*b9df5ad1SAndroid Build Coastguard Worker#
18*b9df5ad1SAndroid Build Coastguard Worker
19*b9df5ad1SAndroid Build Coastguard Worker"""
20*b9df5ad1SAndroid Build Coastguard WorkerA set of classes (models) each closely representing an XML node in the
21*b9df5ad1SAndroid Build Coastguard Workermetadata_definitions.xml file.
22*b9df5ad1SAndroid Build Coastguard Worker
23*b9df5ad1SAndroid Build Coastguard Worker  Node: Base class for most nodes.
24*b9df5ad1SAndroid Build Coastguard Worker  Entry: A node corresponding to <entry> elements.
25*b9df5ad1SAndroid Build Coastguard Worker  Clone: A node corresponding to <clone> elements.
26*b9df5ad1SAndroid Build Coastguard Worker  MergedEntry: A node corresponding to either <entry> or <clone> elements.
27*b9df5ad1SAndroid Build Coastguard Worker  Kind: A node corresponding to <dynamic>, <static>, <controls> elements.
28*b9df5ad1SAndroid Build Coastguard Worker  InnerNamespace: A node corresponding to a <namespace> nested under a <kind>.
29*b9df5ad1SAndroid Build Coastguard Worker  OuterNamespace: A node corresponding to a <namespace> with <kind> children.
30*b9df5ad1SAndroid Build Coastguard Worker  Section: A node corresponding to a <section> element.
31*b9df5ad1SAndroid Build Coastguard Worker  Enum: A class corresponding an <enum> element within an <entry>
32*b9df5ad1SAndroid Build Coastguard Worker  EnumValue: A class corresponding to a <value> element within an Enum
33*b9df5ad1SAndroid Build Coastguard Worker  Metadata: Root node that also provides tree construction functionality.
34*b9df5ad1SAndroid Build Coastguard Worker  Tag: A node corresponding to a top level <tag> element.
35*b9df5ad1SAndroid Build Coastguard Worker  Typedef: A node corresponding to a <typedef> element under <types>.
36*b9df5ad1SAndroid Build Coastguard Worker"""
37*b9df5ad1SAndroid Build Coastguard Worker
38*b9df5ad1SAndroid Build Coastguard Workerimport sys
39*b9df5ad1SAndroid Build Coastguard Workerimport functools
40*b9df5ad1SAndroid Build Coastguard Workerimport itertools
41*b9df5ad1SAndroid Build Coastguard Workerfrom collections import OrderedDict
42*b9df5ad1SAndroid Build Coastguard Worker
43*b9df5ad1SAndroid Build Coastguard Workerclass Node(object):
44*b9df5ad1SAndroid Build Coastguard Worker  """
45*b9df5ad1SAndroid Build Coastguard Worker  Base class for most nodes that are part of the Metadata graph.
46*b9df5ad1SAndroid Build Coastguard Worker
47*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
48*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to a parent Node.
49*b9df5ad1SAndroid Build Coastguard Worker    name: A string describing the name, usually but not always the 'name'
50*b9df5ad1SAndroid Build Coastguard Worker          attribute of the corresponding XML node.
51*b9df5ad1SAndroid Build Coastguard Worker  """
52*b9df5ad1SAndroid Build Coastguard Worker
53*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self):
54*b9df5ad1SAndroid Build Coastguard Worker    self._parent = None
55*b9df5ad1SAndroid Build Coastguard Worker    self._name = None
56*b9df5ad1SAndroid Build Coastguard Worker
57*b9df5ad1SAndroid Build Coastguard Worker  @property
58*b9df5ad1SAndroid Build Coastguard Worker  def parent(self):
59*b9df5ad1SAndroid Build Coastguard Worker    return self._parent
60*b9df5ad1SAndroid Build Coastguard Worker
61*b9df5ad1SAndroid Build Coastguard Worker  @property
62*b9df5ad1SAndroid Build Coastguard Worker  def name(self):
63*b9df5ad1SAndroid Build Coastguard Worker    return self._name
64*b9df5ad1SAndroid Build Coastguard Worker
65*b9df5ad1SAndroid Build Coastguard Worker  def find_all(self, pred):
66*b9df5ad1SAndroid Build Coastguard Worker    """
67*b9df5ad1SAndroid Build Coastguard Worker    Find all descendants that match the predicate.
68*b9df5ad1SAndroid Build Coastguard Worker
69*b9df5ad1SAndroid Build Coastguard Worker    Args:
70*b9df5ad1SAndroid Build Coastguard Worker      pred: a predicate function that acts as a filter for a Node
71*b9df5ad1SAndroid Build Coastguard Worker
72*b9df5ad1SAndroid Build Coastguard Worker    Yields:
73*b9df5ad1SAndroid Build Coastguard Worker      A sequence of all descendants for which pred(node) is true,
74*b9df5ad1SAndroid Build Coastguard Worker      in a pre-order visit order.
75*b9df5ad1SAndroid Build Coastguard Worker    """
76*b9df5ad1SAndroid Build Coastguard Worker    if pred(self):
77*b9df5ad1SAndroid Build Coastguard Worker      yield self
78*b9df5ad1SAndroid Build Coastguard Worker
79*b9df5ad1SAndroid Build Coastguard Worker    if self._get_children() is None:
80*b9df5ad1SAndroid Build Coastguard Worker      return
81*b9df5ad1SAndroid Build Coastguard Worker
82*b9df5ad1SAndroid Build Coastguard Worker    for i in self._get_children():
83*b9df5ad1SAndroid Build Coastguard Worker      for j in i.find_all(pred):
84*b9df5ad1SAndroid Build Coastguard Worker        yield j
85*b9df5ad1SAndroid Build Coastguard Worker
86*b9df5ad1SAndroid Build Coastguard Worker  def find_first(self, pred):
87*b9df5ad1SAndroid Build Coastguard Worker    """
88*b9df5ad1SAndroid Build Coastguard Worker    Find the first descendant that matches the predicate.
89*b9df5ad1SAndroid Build Coastguard Worker
90*b9df5ad1SAndroid Build Coastguard Worker    Args:
91*b9df5ad1SAndroid Build Coastguard Worker      pred: a predicate function that acts as a filter for a Node
92*b9df5ad1SAndroid Build Coastguard Worker
93*b9df5ad1SAndroid Build Coastguard Worker    Returns:
94*b9df5ad1SAndroid Build Coastguard Worker      The first Node from find_all(pred), or None if there were no results.
95*b9df5ad1SAndroid Build Coastguard Worker    """
96*b9df5ad1SAndroid Build Coastguard Worker    for i in self.find_all(pred):
97*b9df5ad1SAndroid Build Coastguard Worker      return i
98*b9df5ad1SAndroid Build Coastguard Worker
99*b9df5ad1SAndroid Build Coastguard Worker    return None
100*b9df5ad1SAndroid Build Coastguard Worker
101*b9df5ad1SAndroid Build Coastguard Worker  def find_parent_first(self, pred):
102*b9df5ad1SAndroid Build Coastguard Worker    """
103*b9df5ad1SAndroid Build Coastguard Worker    Find the first ancestor that matches the predicate.
104*b9df5ad1SAndroid Build Coastguard Worker
105*b9df5ad1SAndroid Build Coastguard Worker    Args:
106*b9df5ad1SAndroid Build Coastguard Worker      pred: A predicate function that acts as a filter for a Node
107*b9df5ad1SAndroid Build Coastguard Worker
108*b9df5ad1SAndroid Build Coastguard Worker    Returns:
109*b9df5ad1SAndroid Build Coastguard Worker      The first ancestor closest to the node for which pred(node) is true.
110*b9df5ad1SAndroid Build Coastguard Worker    """
111*b9df5ad1SAndroid Build Coastguard Worker    for i in self.find_parents(pred):
112*b9df5ad1SAndroid Build Coastguard Worker      return i
113*b9df5ad1SAndroid Build Coastguard Worker
114*b9df5ad1SAndroid Build Coastguard Worker    return None
115*b9df5ad1SAndroid Build Coastguard Worker
116*b9df5ad1SAndroid Build Coastguard Worker  def find_parents(self, pred):
117*b9df5ad1SAndroid Build Coastguard Worker    """
118*b9df5ad1SAndroid Build Coastguard Worker    Find all ancestors that match the predicate.
119*b9df5ad1SAndroid Build Coastguard Worker
120*b9df5ad1SAndroid Build Coastguard Worker    Args:
121*b9df5ad1SAndroid Build Coastguard Worker      pred: A predicate function that acts as a filter for a Node
122*b9df5ad1SAndroid Build Coastguard Worker
123*b9df5ad1SAndroid Build Coastguard Worker    Yields:
124*b9df5ad1SAndroid Build Coastguard Worker      A sequence of all ancestors (closest to furthest) from the node,
125*b9df5ad1SAndroid Build Coastguard Worker      where pred(node) is true.
126*b9df5ad1SAndroid Build Coastguard Worker    """
127*b9df5ad1SAndroid Build Coastguard Worker    parent = self.parent
128*b9df5ad1SAndroid Build Coastguard Worker
129*b9df5ad1SAndroid Build Coastguard Worker    while parent is not None:
130*b9df5ad1SAndroid Build Coastguard Worker      if pred(parent):
131*b9df5ad1SAndroid Build Coastguard Worker        yield parent
132*b9df5ad1SAndroid Build Coastguard Worker      parent = parent.parent
133*b9df5ad1SAndroid Build Coastguard Worker
134*b9df5ad1SAndroid Build Coastguard Worker  def sort_children(self):
135*b9df5ad1SAndroid Build Coastguard Worker    """
136*b9df5ad1SAndroid Build Coastguard Worker    Sorts the immediate children in-place.
137*b9df5ad1SAndroid Build Coastguard Worker    """
138*b9df5ad1SAndroid Build Coastguard Worker    self._sort_by_name(self._children)
139*b9df5ad1SAndroid Build Coastguard Worker
140*b9df5ad1SAndroid Build Coastguard Worker  def _sort_by_name(self, what):
141*b9df5ad1SAndroid Build Coastguard Worker    what.sort(key=lambda x: x.name)
142*b9df5ad1SAndroid Build Coastguard Worker
143*b9df5ad1SAndroid Build Coastguard Worker  def _get_name(self):
144*b9df5ad1SAndroid Build Coastguard Worker    return lambda x: x.name
145*b9df5ad1SAndroid Build Coastguard Worker
146*b9df5ad1SAndroid Build Coastguard Worker  # Iterate over all children nodes. None when node doesn't support children.
147*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
148*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._children)
149*b9df5ad1SAndroid Build Coastguard Worker
150*b9df5ad1SAndroid Build Coastguard Worker  def _children_name_map_matching(self, match=lambda x: True):
151*b9df5ad1SAndroid Build Coastguard Worker    d = {}
152*b9df5ad1SAndroid Build Coastguard Worker    for i in self._get_children():
153*b9df5ad1SAndroid Build Coastguard Worker      if match(i):
154*b9df5ad1SAndroid Build Coastguard Worker        d[i.name] = i
155*b9df5ad1SAndroid Build Coastguard Worker    return d
156*b9df5ad1SAndroid Build Coastguard Worker
157*b9df5ad1SAndroid Build Coastguard Worker  @staticmethod
158*b9df5ad1SAndroid Build Coastguard Worker  def _dictionary_by_name(values):
159*b9df5ad1SAndroid Build Coastguard Worker    d = OrderedDict()
160*b9df5ad1SAndroid Build Coastguard Worker    for i in values:
161*b9df5ad1SAndroid Build Coastguard Worker      d[i.name] = i
162*b9df5ad1SAndroid Build Coastguard Worker
163*b9df5ad1SAndroid Build Coastguard Worker    return d
164*b9df5ad1SAndroid Build Coastguard Worker
165*b9df5ad1SAndroid Build Coastguard Worker  def validate_tree(self):
166*b9df5ad1SAndroid Build Coastguard Worker    """
167*b9df5ad1SAndroid Build Coastguard Worker    Sanity check the tree recursively, ensuring for a node n, all children's
168*b9df5ad1SAndroid Build Coastguard Worker    parents are also n.
169*b9df5ad1SAndroid Build Coastguard Worker
170*b9df5ad1SAndroid Build Coastguard Worker    Returns:
171*b9df5ad1SAndroid Build Coastguard Worker      True if validation succeeds, False otherwise.
172*b9df5ad1SAndroid Build Coastguard Worker    """
173*b9df5ad1SAndroid Build Coastguard Worker    succ = True
174*b9df5ad1SAndroid Build Coastguard Worker    children = self._get_children()
175*b9df5ad1SAndroid Build Coastguard Worker    if children is None:
176*b9df5ad1SAndroid Build Coastguard Worker      return True
177*b9df5ad1SAndroid Build Coastguard Worker
178*b9df5ad1SAndroid Build Coastguard Worker    for child in self._get_children():
179*b9df5ad1SAndroid Build Coastguard Worker      if child.parent != self:
180*b9df5ad1SAndroid Build Coastguard Worker        print("ERROR: Node '%s' doesn't match the parent (expected: %s, actual %s)" \
181*b9df5ad1SAndroid Build Coastguard Worker              % (child, self, child.parent), file=sys.stderr)
182*b9df5ad1SAndroid Build Coastguard Worker        succ = False
183*b9df5ad1SAndroid Build Coastguard Worker
184*b9df5ad1SAndroid Build Coastguard Worker      succ = child.validate_tree() and succ
185*b9df5ad1SAndroid Build Coastguard Worker
186*b9df5ad1SAndroid Build Coastguard Worker    return succ
187*b9df5ad1SAndroid Build Coastguard Worker
188*b9df5ad1SAndroid Build Coastguard Worker  def __str__(self):
189*b9df5ad1SAndroid Build Coastguard Worker    return "<%s name='%s'>" %(self.__class__, self.name)
190*b9df5ad1SAndroid Build Coastguard Worker
191*b9df5ad1SAndroid Build Coastguard Workerclass Metadata(Node):
192*b9df5ad1SAndroid Build Coastguard Worker  """
193*b9df5ad1SAndroid Build Coastguard Worker  A node corresponding to a <metadata> entry.
194*b9df5ad1SAndroid Build Coastguard Worker
195*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
196*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent Node. This is always None for Metadata.
197*b9df5ad1SAndroid Build Coastguard Worker    outer_namespaces: A sequence of immediate OuterNamespace children.
198*b9df5ad1SAndroid Build Coastguard Worker    tags: A sequence of all Tag instances available in the graph.
199*b9df5ad1SAndroid Build Coastguard Worker    types: An iterable of all Typedef instances available in the graph.
200*b9df5ad1SAndroid Build Coastguard Worker  """
201*b9df5ad1SAndroid Build Coastguard Worker
202*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self):
203*b9df5ad1SAndroid Build Coastguard Worker    """
204*b9df5ad1SAndroid Build Coastguard Worker    Initialize with no children. Use insert_* functions and then
205*b9df5ad1SAndroid Build Coastguard Worker    construct_graph() to build up the Metadata from some source.
206*b9df5ad1SAndroid Build Coastguard Worker    """
207*b9df5ad1SAndroid Build Coastguard Worker# Private
208*b9df5ad1SAndroid Build Coastguard Worker    self._entries = []
209*b9df5ad1SAndroid Build Coastguard Worker    # kind => { name => entry }
210*b9df5ad1SAndroid Build Coastguard Worker    self._entry_map = { 'static': {}, 'dynamic': {}, 'controls': {} }
211*b9df5ad1SAndroid Build Coastguard Worker    self._entries_ordered = [] # list of ordered Entry/Clone instances
212*b9df5ad1SAndroid Build Coastguard Worker    self._clones = []
213*b9df5ad1SAndroid Build Coastguard Worker
214*b9df5ad1SAndroid Build Coastguard Worker# Public (Read Only)
215*b9df5ad1SAndroid Build Coastguard Worker    self._name = None
216*b9df5ad1SAndroid Build Coastguard Worker    self._parent = None
217*b9df5ad1SAndroid Build Coastguard Worker    self._outer_namespaces = None
218*b9df5ad1SAndroid Build Coastguard Worker    self._tags = []
219*b9df5ad1SAndroid Build Coastguard Worker    self._types = []
220*b9df5ad1SAndroid Build Coastguard Worker
221*b9df5ad1SAndroid Build Coastguard Worker  @property
222*b9df5ad1SAndroid Build Coastguard Worker  def outer_namespaces(self):
223*b9df5ad1SAndroid Build Coastguard Worker    if self._outer_namespaces is None:
224*b9df5ad1SAndroid Build Coastguard Worker      return None
225*b9df5ad1SAndroid Build Coastguard Worker    else:
226*b9df5ad1SAndroid Build Coastguard Worker      return (i for i in self._outer_namespaces)
227*b9df5ad1SAndroid Build Coastguard Worker
228*b9df5ad1SAndroid Build Coastguard Worker  @property
229*b9df5ad1SAndroid Build Coastguard Worker  def tags(self):
230*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._tags)
231*b9df5ad1SAndroid Build Coastguard Worker
232*b9df5ad1SAndroid Build Coastguard Worker  @property
233*b9df5ad1SAndroid Build Coastguard Worker  def types(self):
234*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._types)
235*b9df5ad1SAndroid Build Coastguard Worker
236*b9df5ad1SAndroid Build Coastguard Worker  def _get_properties(self):
237*b9df5ad1SAndroid Build Coastguard Worker
238*b9df5ad1SAndroid Build Coastguard Worker    for i in self._entries:
239*b9df5ad1SAndroid Build Coastguard Worker      yield i
240*b9df5ad1SAndroid Build Coastguard Worker
241*b9df5ad1SAndroid Build Coastguard Worker    for i in self._clones:
242*b9df5ad1SAndroid Build Coastguard Worker      yield i
243*b9df5ad1SAndroid Build Coastguard Worker
244*b9df5ad1SAndroid Build Coastguard Worker  def insert_tag(self, tag, description=""):
245*b9df5ad1SAndroid Build Coastguard Worker    """
246*b9df5ad1SAndroid Build Coastguard Worker    Insert a tag into the metadata.
247*b9df5ad1SAndroid Build Coastguard Worker
248*b9df5ad1SAndroid Build Coastguard Worker    Args:
249*b9df5ad1SAndroid Build Coastguard Worker      tag: A string identifier for a tag.
250*b9df5ad1SAndroid Build Coastguard Worker      description: A string description for a tag.
251*b9df5ad1SAndroid Build Coastguard Worker
252*b9df5ad1SAndroid Build Coastguard Worker    Example:
253*b9df5ad1SAndroid Build Coastguard Worker      metadata.insert_tag("BC", "Backwards Compatibility for old API")
254*b9df5ad1SAndroid Build Coastguard Worker
255*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
256*b9df5ad1SAndroid Build Coastguard Worker      Subsequent calls to insert_tag with the same tag are safe (they will
257*b9df5ad1SAndroid Build Coastguard Worker      be ignored).
258*b9df5ad1SAndroid Build Coastguard Worker    """
259*b9df5ad1SAndroid Build Coastguard Worker    tag_ids = [tg.name for tg in self.tags if tg.name == tag]
260*b9df5ad1SAndroid Build Coastguard Worker    if not tag_ids:
261*b9df5ad1SAndroid Build Coastguard Worker      self._tags.append(Tag(tag, self, description))
262*b9df5ad1SAndroid Build Coastguard Worker
263*b9df5ad1SAndroid Build Coastguard Worker  def insert_type(self, type_name, type_selector="typedef", **kwargs):
264*b9df5ad1SAndroid Build Coastguard Worker    """
265*b9df5ad1SAndroid Build Coastguard Worker    Insert a type into the metadata.
266*b9df5ad1SAndroid Build Coastguard Worker
267*b9df5ad1SAndroid Build Coastguard Worker    Args:
268*b9df5ad1SAndroid Build Coastguard Worker      type_name: A type's name
269*b9df5ad1SAndroid Build Coastguard Worker      type_selector: The selector for the type, e.g. 'typedef'
270*b9df5ad1SAndroid Build Coastguard Worker
271*b9df5ad1SAndroid Build Coastguard Worker    Args (if type_selector == 'typedef'):
272*b9df5ad1SAndroid Build Coastguard Worker      languages: A map of 'language name' -> 'fully qualified class path'
273*b9df5ad1SAndroid Build Coastguard Worker
274*b9df5ad1SAndroid Build Coastguard Worker    Example:
275*b9df5ad1SAndroid Build Coastguard Worker      metadata.insert_type('rectangle', 'typedef',
276*b9df5ad1SAndroid Build Coastguard Worker                           { 'java': 'android.graphics.Rect' })
277*b9df5ad1SAndroid Build Coastguard Worker
278*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
279*b9df5ad1SAndroid Build Coastguard Worker      Subsequent calls to insert_type with the same type name are safe (they
280*b9df5ad1SAndroid Build Coastguard Worker      will be ignored)
281*b9df5ad1SAndroid Build Coastguard Worker    """
282*b9df5ad1SAndroid Build Coastguard Worker
283*b9df5ad1SAndroid Build Coastguard Worker    if type_selector != 'typedef':
284*b9df5ad1SAndroid Build Coastguard Worker      raise ValueError("Unsupported type_selector given " + type_selector)
285*b9df5ad1SAndroid Build Coastguard Worker
286*b9df5ad1SAndroid Build Coastguard Worker    type_names = [tp.name for tp in self.types if tp.name == tp]
287*b9df5ad1SAndroid Build Coastguard Worker    if not type_names:
288*b9df5ad1SAndroid Build Coastguard Worker      self._types.append(Typedef(type_name, self, kwargs.get('languages')))
289*b9df5ad1SAndroid Build Coastguard Worker
290*b9df5ad1SAndroid Build Coastguard Worker  def insert_entry(self, entry):
291*b9df5ad1SAndroid Build Coastguard Worker    """
292*b9df5ad1SAndroid Build Coastguard Worker    Insert an entry into the metadata.
293*b9df5ad1SAndroid Build Coastguard Worker
294*b9df5ad1SAndroid Build Coastguard Worker    Args:
295*b9df5ad1SAndroid Build Coastguard Worker      entry: A key-value dictionary describing an entry. Refer to
296*b9df5ad1SAndroid Build Coastguard Worker             Entry#__init__ for the keys required/optional.
297*b9df5ad1SAndroid Build Coastguard Worker
298*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
299*b9df5ad1SAndroid Build Coastguard Worker      Subsequent calls to insert_entry with the same entry+kind name are safe
300*b9df5ad1SAndroid Build Coastguard Worker      (they will be ignored).
301*b9df5ad1SAndroid Build Coastguard Worker    """
302*b9df5ad1SAndroid Build Coastguard Worker    e = Entry(**entry)
303*b9df5ad1SAndroid Build Coastguard Worker    self._entries.append(e)
304*b9df5ad1SAndroid Build Coastguard Worker    self._entry_map[e.kind][e.name] = e
305*b9df5ad1SAndroid Build Coastguard Worker    self._entries_ordered.append(e)
306*b9df5ad1SAndroid Build Coastguard Worker
307*b9df5ad1SAndroid Build Coastguard Worker  def insert_clone(self, clone):
308*b9df5ad1SAndroid Build Coastguard Worker    """
309*b9df5ad1SAndroid Build Coastguard Worker    Insert a clone into the metadata.
310*b9df5ad1SAndroid Build Coastguard Worker
311*b9df5ad1SAndroid Build Coastguard Worker    Args:
312*b9df5ad1SAndroid Build Coastguard Worker      clone: A key-value dictionary describing a clone. Refer to
313*b9df5ad1SAndroid Build Coastguard Worker            Clone#__init__ for the keys required/optional.
314*b9df5ad1SAndroid Build Coastguard Worker
315*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
316*b9df5ad1SAndroid Build Coastguard Worker      Subsequent calls to insert_clone with the same clone+kind name are safe
317*b9df5ad1SAndroid Build Coastguard Worker      (they will be ignored). Also the target entry need not be inserted
318*b9df5ad1SAndroid Build Coastguard Worker      ahead of the clone entry.
319*b9df5ad1SAndroid Build Coastguard Worker    """
320*b9df5ad1SAndroid Build Coastguard Worker    # figure out corresponding entry later. allow clone insert, entry insert
321*b9df5ad1SAndroid Build Coastguard Worker    entry = None
322*b9df5ad1SAndroid Build Coastguard Worker    c = Clone(entry, **clone)
323*b9df5ad1SAndroid Build Coastguard Worker    self._entry_map[c.kind][c.name] = c
324*b9df5ad1SAndroid Build Coastguard Worker    self._clones.append(c)
325*b9df5ad1SAndroid Build Coastguard Worker    self._entries_ordered.append(c)
326*b9df5ad1SAndroid Build Coastguard Worker
327*b9df5ad1SAndroid Build Coastguard Worker  def prune_clones(self):
328*b9df5ad1SAndroid Build Coastguard Worker    """
329*b9df5ad1SAndroid Build Coastguard Worker    Remove all clones that don't point to an existing entry.
330*b9df5ad1SAndroid Build Coastguard Worker
331*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
332*b9df5ad1SAndroid Build Coastguard Worker      This should be called after all insert_entry/insert_clone calls have
333*b9df5ad1SAndroid Build Coastguard Worker      finished.
334*b9df5ad1SAndroid Build Coastguard Worker    """
335*b9df5ad1SAndroid Build Coastguard Worker    remove_list = []
336*b9df5ad1SAndroid Build Coastguard Worker    for p in self._clones:
337*b9df5ad1SAndroid Build Coastguard Worker      if p.entry is None:
338*b9df5ad1SAndroid Build Coastguard Worker        remove_list.append(p)
339*b9df5ad1SAndroid Build Coastguard Worker
340*b9df5ad1SAndroid Build Coastguard Worker    for p in remove_list:
341*b9df5ad1SAndroid Build Coastguard Worker
342*b9df5ad1SAndroid Build Coastguard Worker      # remove from parent's entries list
343*b9df5ad1SAndroid Build Coastguard Worker      if p.parent is not None:
344*b9df5ad1SAndroid Build Coastguard Worker        p.parent._entries.remove(p)
345*b9df5ad1SAndroid Build Coastguard Worker      # remove from parents' _leafs list
346*b9df5ad1SAndroid Build Coastguard Worker      for ancestor in p.find_parents(lambda x: not isinstance(x, Metadata)):
347*b9df5ad1SAndroid Build Coastguard Worker        ancestor._leafs.remove(p)
348*b9df5ad1SAndroid Build Coastguard Worker
349*b9df5ad1SAndroid Build Coastguard Worker      # remove from global list
350*b9df5ad1SAndroid Build Coastguard Worker      self._clones.remove(p)
351*b9df5ad1SAndroid Build Coastguard Worker      self._entry_map[p.kind].pop(p.name)
352*b9df5ad1SAndroid Build Coastguard Worker      self._entries_ordered.remove(p)
353*b9df5ad1SAndroid Build Coastguard Worker
354*b9df5ad1SAndroid Build Coastguard Worker  def is_entry_this_kind(self, entry, kind):
355*b9df5ad1SAndroid Build Coastguard Worker    """
356*b9df5ad1SAndroid Build Coastguard Worker    Check if input entry if of input kind
357*b9df5ad1SAndroid Build Coastguard Worker
358*b9df5ad1SAndroid Build Coastguard Worker    Args:
359*b9df5ad1SAndroid Build Coastguard Worker      entry: an Entry object
360*b9df5ad1SAndroid Build Coastguard Worker      kind: a string. Possible values are "static", "dynamic", "controls"
361*b9df5ad1SAndroid Build Coastguard Worker
362*b9df5ad1SAndroid Build Coastguard Worker    Returns:
363*b9df5ad1SAndroid Build Coastguard Worker      A boolean indicating whether input entry is of input kind.
364*b9df5ad1SAndroid Build Coastguard Worker    """
365*b9df5ad1SAndroid Build Coastguard Worker    if kind not in ("static", "dynamic", "controls"):
366*b9df5ad1SAndroid Build Coastguard Worker      assert(False), "Unknown kind value " + kind
367*b9df5ad1SAndroid Build Coastguard Worker
368*b9df5ad1SAndroid Build Coastguard Worker    return entry.name in self._entry_map[kind]
369*b9df5ad1SAndroid Build Coastguard Worker
370*b9df5ad1SAndroid Build Coastguard Worker  # After all entries/clones are inserted,
371*b9df5ad1SAndroid Build Coastguard Worker  # invoke this to generate the parent/child node graph all these objects
372*b9df5ad1SAndroid Build Coastguard Worker  def construct_graph(self):
373*b9df5ad1SAndroid Build Coastguard Worker    """
374*b9df5ad1SAndroid Build Coastguard Worker    Generate the graph recursively, after which all Entry nodes will be
375*b9df5ad1SAndroid Build Coastguard Worker    accessible recursively by crawling through the outer_namespaces sequence.
376*b9df5ad1SAndroid Build Coastguard Worker
377*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
378*b9df5ad1SAndroid Build Coastguard Worker      This is safe to be called multiple times at any time. It should be done at
379*b9df5ad1SAndroid Build Coastguard Worker      least once or there will be no graph.
380*b9df5ad1SAndroid Build Coastguard Worker    """
381*b9df5ad1SAndroid Build Coastguard Worker    self.validate_tree()
382*b9df5ad1SAndroid Build Coastguard Worker    self._construct_tags()
383*b9df5ad1SAndroid Build Coastguard Worker    self.validate_tree()
384*b9df5ad1SAndroid Build Coastguard Worker    self._construct_types()
385*b9df5ad1SAndroid Build Coastguard Worker    self.validate_tree()
386*b9df5ad1SAndroid Build Coastguard Worker    self._construct_clones()
387*b9df5ad1SAndroid Build Coastguard Worker    self.validate_tree()
388*b9df5ad1SAndroid Build Coastguard Worker    self._construct_outer_namespaces()
389*b9df5ad1SAndroid Build Coastguard Worker    self.validate_tree()
390*b9df5ad1SAndroid Build Coastguard Worker
391*b9df5ad1SAndroid Build Coastguard Worker  def _construct_tags(self):
392*b9df5ad1SAndroid Build Coastguard Worker    tag_dict = self._dictionary_by_name(self.tags)
393*b9df5ad1SAndroid Build Coastguard Worker    for p in self._get_properties():
394*b9df5ad1SAndroid Build Coastguard Worker      p._tags = []
395*b9df5ad1SAndroid Build Coastguard Worker      for tag_id in p._tag_ids:
396*b9df5ad1SAndroid Build Coastguard Worker        tag = tag_dict.get(tag_id)
397*b9df5ad1SAndroid Build Coastguard Worker
398*b9df5ad1SAndroid Build Coastguard Worker        if tag not in p._tags:
399*b9df5ad1SAndroid Build Coastguard Worker          p._tags.append(tag)
400*b9df5ad1SAndroid Build Coastguard Worker
401*b9df5ad1SAndroid Build Coastguard Worker        if p not in tag.entries:
402*b9df5ad1SAndroid Build Coastguard Worker          tag._entries.append(p)
403*b9df5ad1SAndroid Build Coastguard Worker
404*b9df5ad1SAndroid Build Coastguard Worker  def _construct_types(self):
405*b9df5ad1SAndroid Build Coastguard Worker    type_dict = self._dictionary_by_name(self.types)
406*b9df5ad1SAndroid Build Coastguard Worker    for p in self._get_properties():
407*b9df5ad1SAndroid Build Coastguard Worker      if p._type_name:
408*b9df5ad1SAndroid Build Coastguard Worker        type_node = type_dict.get(p._type_name)
409*b9df5ad1SAndroid Build Coastguard Worker        p._typedef = type_node
410*b9df5ad1SAndroid Build Coastguard Worker
411*b9df5ad1SAndroid Build Coastguard Worker        if p not in type_node.entries:
412*b9df5ad1SAndroid Build Coastguard Worker          type_node._entries.append(p)
413*b9df5ad1SAndroid Build Coastguard Worker
414*b9df5ad1SAndroid Build Coastguard Worker  def _construct_clones(self):
415*b9df5ad1SAndroid Build Coastguard Worker    for p in self._clones:
416*b9df5ad1SAndroid Build Coastguard Worker      target_kind = p.target_kind
417*b9df5ad1SAndroid Build Coastguard Worker      target_entry = self._entry_map[target_kind].get(p.name)
418*b9df5ad1SAndroid Build Coastguard Worker      p._entry = target_entry
419*b9df5ad1SAndroid Build Coastguard Worker      if (p.hal_major_version == 0):
420*b9df5ad1SAndroid Build Coastguard Worker        p._hal_major_version = target_entry._hal_major_version
421*b9df5ad1SAndroid Build Coastguard Worker        p._hal_minor_version = target_entry._hal_minor_version
422*b9df5ad1SAndroid Build Coastguard Worker      # should not throw if we pass validation
423*b9df5ad1SAndroid Build Coastguard Worker      # but can happen when importing obsolete CSV entries
424*b9df5ad1SAndroid Build Coastguard Worker      if target_entry is None:
425*b9df5ad1SAndroid Build Coastguard Worker        print("WARNING: Clone entry '%s' target kind '%s' has no corresponding entry" \
426*b9df5ad1SAndroid Build Coastguard Worker              % (p.name, p.target_kind), file=sys.stderr)
427*b9df5ad1SAndroid Build Coastguard Worker
428*b9df5ad1SAndroid Build Coastguard Worker  def _construct_outer_namespaces(self):
429*b9df5ad1SAndroid Build Coastguard Worker
430*b9df5ad1SAndroid Build Coastguard Worker    if self._outer_namespaces is None: #the first time this runs
431*b9df5ad1SAndroid Build Coastguard Worker      self._outer_namespaces = []
432*b9df5ad1SAndroid Build Coastguard Worker
433*b9df5ad1SAndroid Build Coastguard Worker    root = self._dictionary_by_name(self._outer_namespaces)
434*b9df5ad1SAndroid Build Coastguard Worker    for ons_name, ons in root.items():
435*b9df5ad1SAndroid Build Coastguard Worker      ons._leafs = []
436*b9df5ad1SAndroid Build Coastguard Worker
437*b9df5ad1SAndroid Build Coastguard Worker    for p in self._entries_ordered:
438*b9df5ad1SAndroid Build Coastguard Worker      ons_name = p.get_outer_namespace()
439*b9df5ad1SAndroid Build Coastguard Worker      ons = root.get(ons_name, OuterNamespace(ons_name, self))
440*b9df5ad1SAndroid Build Coastguard Worker      root[ons_name] = ons
441*b9df5ad1SAndroid Build Coastguard Worker
442*b9df5ad1SAndroid Build Coastguard Worker      if p not in ons._leafs:
443*b9df5ad1SAndroid Build Coastguard Worker        ons._leafs.append(p)
444*b9df5ad1SAndroid Build Coastguard Worker
445*b9df5ad1SAndroid Build Coastguard Worker    for ons_name, ons in root.items():
446*b9df5ad1SAndroid Build Coastguard Worker
447*b9df5ad1SAndroid Build Coastguard Worker      ons.validate_tree()
448*b9df5ad1SAndroid Build Coastguard Worker
449*b9df5ad1SAndroid Build Coastguard Worker      self._construct_sections(ons)
450*b9df5ad1SAndroid Build Coastguard Worker
451*b9df5ad1SAndroid Build Coastguard Worker      if ons not in self._outer_namespaces:
452*b9df5ad1SAndroid Build Coastguard Worker        self._outer_namespaces.append(ons)
453*b9df5ad1SAndroid Build Coastguard Worker
454*b9df5ad1SAndroid Build Coastguard Worker      ons.validate_tree()
455*b9df5ad1SAndroid Build Coastguard Worker
456*b9df5ad1SAndroid Build Coastguard Worker  def _construct_sections(self, outer_namespace):
457*b9df5ad1SAndroid Build Coastguard Worker
458*b9df5ad1SAndroid Build Coastguard Worker    sections_dict = self._dictionary_by_name(outer_namespace.sections)
459*b9df5ad1SAndroid Build Coastguard Worker    for sec_name, sec in sections_dict.items():
460*b9df5ad1SAndroid Build Coastguard Worker      sec._leafs = []
461*b9df5ad1SAndroid Build Coastguard Worker      sec.validate_tree()
462*b9df5ad1SAndroid Build Coastguard Worker
463*b9df5ad1SAndroid Build Coastguard Worker    for p in outer_namespace._leafs:
464*b9df5ad1SAndroid Build Coastguard Worker      does_exist = sections_dict.get(p.get_section())
465*b9df5ad1SAndroid Build Coastguard Worker
466*b9df5ad1SAndroid Build Coastguard Worker      sec = sections_dict.get(p.get_section(), \
467*b9df5ad1SAndroid Build Coastguard Worker          Section(p.get_section(), outer_namespace))
468*b9df5ad1SAndroid Build Coastguard Worker      sections_dict[p.get_section()] = sec
469*b9df5ad1SAndroid Build Coastguard Worker
470*b9df5ad1SAndroid Build Coastguard Worker      sec.validate_tree()
471*b9df5ad1SAndroid Build Coastguard Worker
472*b9df5ad1SAndroid Build Coastguard Worker      if p not in sec._leafs:
473*b9df5ad1SAndroid Build Coastguard Worker        sec._leafs.append(p)
474*b9df5ad1SAndroid Build Coastguard Worker
475*b9df5ad1SAndroid Build Coastguard Worker    for sec_name, sec in sections_dict.items():
476*b9df5ad1SAndroid Build Coastguard Worker
477*b9df5ad1SAndroid Build Coastguard Worker      if not sec.validate_tree():
478*b9df5ad1SAndroid Build Coastguard Worker        print("ERROR: Failed to validate tree in construct_sections (start), with section = '%s'"
479*b9df5ad1SAndroid Build Coastguard Worker              % (sec), file=sys.stderr)
480*b9df5ad1SAndroid Build Coastguard Worker
481*b9df5ad1SAndroid Build Coastguard Worker      self._construct_kinds(sec)
482*b9df5ad1SAndroid Build Coastguard Worker
483*b9df5ad1SAndroid Build Coastguard Worker      if sec not in outer_namespace.sections:
484*b9df5ad1SAndroid Build Coastguard Worker        outer_namespace._sections.append(sec)
485*b9df5ad1SAndroid Build Coastguard Worker
486*b9df5ad1SAndroid Build Coastguard Worker      if not sec.validate_tree():
487*b9df5ad1SAndroid Build Coastguard Worker        print("ERROR: Failed to validate tree in construct_sections (end), with section = '%s'"
488*b9df5ad1SAndroid Build Coastguard Worker              % (sec), file=sys.stderr)
489*b9df5ad1SAndroid Build Coastguard Worker
490*b9df5ad1SAndroid Build Coastguard Worker  # 'controls', 'static' 'dynamic'. etc
491*b9df5ad1SAndroid Build Coastguard Worker  def _construct_kinds(self, section):
492*b9df5ad1SAndroid Build Coastguard Worker    for kind in section.kinds:
493*b9df5ad1SAndroid Build Coastguard Worker      kind._leafs = []
494*b9df5ad1SAndroid Build Coastguard Worker      section.validate_tree()
495*b9df5ad1SAndroid Build Coastguard Worker
496*b9df5ad1SAndroid Build Coastguard Worker    group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
497*b9df5ad1SAndroid Build Coastguard Worker    leaf_it = ((k, g) for k, g in group_entry_by_kind)
498*b9df5ad1SAndroid Build Coastguard Worker
499*b9df5ad1SAndroid Build Coastguard Worker    # allow multiple kinds with the same name. merge if adjacent
500*b9df5ad1SAndroid Build Coastguard Worker    # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
501*b9df5ad1SAndroid Build Coastguard Worker    # this helps maintain ABI compatibility when adding an entry in a new kind
502*b9df5ad1SAndroid Build Coastguard Worker    for idx, (kind_name, entry_it) in enumerate(leaf_it):
503*b9df5ad1SAndroid Build Coastguard Worker      if idx >= len(section._kinds):
504*b9df5ad1SAndroid Build Coastguard Worker        kind = Kind(kind_name, section)
505*b9df5ad1SAndroid Build Coastguard Worker        section._kinds.append(kind)
506*b9df5ad1SAndroid Build Coastguard Worker        section.validate_tree()
507*b9df5ad1SAndroid Build Coastguard Worker
508*b9df5ad1SAndroid Build Coastguard Worker      kind = section._kinds[idx]
509*b9df5ad1SAndroid Build Coastguard Worker
510*b9df5ad1SAndroid Build Coastguard Worker      for p in entry_it:
511*b9df5ad1SAndroid Build Coastguard Worker        if p not in kind._leafs:
512*b9df5ad1SAndroid Build Coastguard Worker          kind._leafs.append(p)
513*b9df5ad1SAndroid Build Coastguard Worker
514*b9df5ad1SAndroid Build Coastguard Worker    for kind in section._kinds:
515*b9df5ad1SAndroid Build Coastguard Worker      kind.validate_tree()
516*b9df5ad1SAndroid Build Coastguard Worker      self._construct_inner_namespaces(kind)
517*b9df5ad1SAndroid Build Coastguard Worker      kind.validate_tree()
518*b9df5ad1SAndroid Build Coastguard Worker      self._construct_entries(kind)
519*b9df5ad1SAndroid Build Coastguard Worker      kind.validate_tree()
520*b9df5ad1SAndroid Build Coastguard Worker
521*b9df5ad1SAndroid Build Coastguard Worker      if not section.validate_tree():
522*b9df5ad1SAndroid Build Coastguard Worker        print("ERROR: Failed to validate tree in construct_kinds, with kind = '%s'" % (kind),
523*b9df5ad1SAndroid Build Coastguard Worker              file=sys.stderr)
524*b9df5ad1SAndroid Build Coastguard Worker
525*b9df5ad1SAndroid Build Coastguard Worker      if not kind.validate_tree():
526*b9df5ad1SAndroid Build Coastguard Worker        print("ERROR: Failed to validate tree in construct_kinds, with kind = '%s'" % (kind),
527*b9df5ad1SAndroid Build Coastguard Worker              file=sys.stderr)
528*b9df5ad1SAndroid Build Coastguard Worker
529*b9df5ad1SAndroid Build Coastguard Worker  def _construct_inner_namespaces(self, parent, depth=0):
530*b9df5ad1SAndroid Build Coastguard Worker    #parent is InnerNamespace or Kind
531*b9df5ad1SAndroid Build Coastguard Worker    ins_dict = self._dictionary_by_name(parent.namespaces)
532*b9df5ad1SAndroid Build Coastguard Worker    for name, ins in ins_dict.items():
533*b9df5ad1SAndroid Build Coastguard Worker      ins._leafs = []
534*b9df5ad1SAndroid Build Coastguard Worker
535*b9df5ad1SAndroid Build Coastguard Worker    for p in parent._leafs:
536*b9df5ad1SAndroid Build Coastguard Worker      ins_list = p.get_inner_namespace_list()
537*b9df5ad1SAndroid Build Coastguard Worker
538*b9df5ad1SAndroid Build Coastguard Worker      if len(ins_list) > depth:
539*b9df5ad1SAndroid Build Coastguard Worker        ins_str = ins_list[depth]
540*b9df5ad1SAndroid Build Coastguard Worker        ins = ins_dict.get(ins_str, InnerNamespace(ins_str, parent))
541*b9df5ad1SAndroid Build Coastguard Worker        ins_dict[ins_str] = ins
542*b9df5ad1SAndroid Build Coastguard Worker
543*b9df5ad1SAndroid Build Coastguard Worker        if p not in ins._leafs:
544*b9df5ad1SAndroid Build Coastguard Worker          ins._leafs.append(p)
545*b9df5ad1SAndroid Build Coastguard Worker
546*b9df5ad1SAndroid Build Coastguard Worker    for name, ins in ins_dict.items():
547*b9df5ad1SAndroid Build Coastguard Worker      ins.validate_tree()
548*b9df5ad1SAndroid Build Coastguard Worker      # construct children INS
549*b9df5ad1SAndroid Build Coastguard Worker      self._construct_inner_namespaces(ins, depth + 1)
550*b9df5ad1SAndroid Build Coastguard Worker      ins.validate_tree()
551*b9df5ad1SAndroid Build Coastguard Worker      # construct children entries
552*b9df5ad1SAndroid Build Coastguard Worker      self._construct_entries(ins, depth + 1)
553*b9df5ad1SAndroid Build Coastguard Worker
554*b9df5ad1SAndroid Build Coastguard Worker      if ins not in parent.namespaces:
555*b9df5ad1SAndroid Build Coastguard Worker        parent._namespaces.append(ins)
556*b9df5ad1SAndroid Build Coastguard Worker
557*b9df5ad1SAndroid Build Coastguard Worker      if not ins.validate_tree():
558*b9df5ad1SAndroid Build Coastguard Worker        print("ERROR: Failed to validate tree in construct_inner_namespaces, with ins = '%s'"
559*b9df5ad1SAndroid Build Coastguard Worker              % (ins), file=sys.stderr)
560*b9df5ad1SAndroid Build Coastguard Worker
561*b9df5ad1SAndroid Build Coastguard Worker  # doesnt construct the entries, so much as links them
562*b9df5ad1SAndroid Build Coastguard Worker  def _construct_entries(self, parent, depth=0):
563*b9df5ad1SAndroid Build Coastguard Worker    #parent is InnerNamespace or Kind
564*b9df5ad1SAndroid Build Coastguard Worker    entry_dict = self._dictionary_by_name(parent.entries)
565*b9df5ad1SAndroid Build Coastguard Worker    for p in parent._leafs:
566*b9df5ad1SAndroid Build Coastguard Worker      ins_list = p.get_inner_namespace_list()
567*b9df5ad1SAndroid Build Coastguard Worker
568*b9df5ad1SAndroid Build Coastguard Worker      if len(ins_list) == depth:
569*b9df5ad1SAndroid Build Coastguard Worker        entry = entry_dict.get(p.name, p)
570*b9df5ad1SAndroid Build Coastguard Worker        entry_dict[p.name] = entry
571*b9df5ad1SAndroid Build Coastguard Worker
572*b9df5ad1SAndroid Build Coastguard Worker    for name, entry in entry_dict.items():
573*b9df5ad1SAndroid Build Coastguard Worker
574*b9df5ad1SAndroid Build Coastguard Worker      old_parent = entry.parent
575*b9df5ad1SAndroid Build Coastguard Worker      entry._parent = parent
576*b9df5ad1SAndroid Build Coastguard Worker
577*b9df5ad1SAndroid Build Coastguard Worker      if entry not in parent.entries:
578*b9df5ad1SAndroid Build Coastguard Worker        parent._entries.append(entry)
579*b9df5ad1SAndroid Build Coastguard Worker
580*b9df5ad1SAndroid Build Coastguard Worker      if old_parent is not None and old_parent != parent:
581*b9df5ad1SAndroid Build Coastguard Worker        print("ERROR: Parent changed from '%s' to '%s' for entry '%s'"
582*b9df5ad1SAndroid Build Coastguard Worker              % (old_parent.name, parent.name, entry.name), file = sys.stderr)
583*b9df5ad1SAndroid Build Coastguard Worker
584*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
585*b9df5ad1SAndroid Build Coastguard Worker    if self.outer_namespaces is not None:
586*b9df5ad1SAndroid Build Coastguard Worker      for i in self.outer_namespaces:
587*b9df5ad1SAndroid Build Coastguard Worker        yield i
588*b9df5ad1SAndroid Build Coastguard Worker
589*b9df5ad1SAndroid Build Coastguard Worker    if self.tags is not None:
590*b9df5ad1SAndroid Build Coastguard Worker      for i in self.tags:
591*b9df5ad1SAndroid Build Coastguard Worker        yield i
592*b9df5ad1SAndroid Build Coastguard Worker
593*b9df5ad1SAndroid Build Coastguard Workerclass Tag(Node):
594*b9df5ad1SAndroid Build Coastguard Worker  """
595*b9df5ad1SAndroid Build Coastguard Worker  A tag Node corresponding to a top-level <tag> element.
596*b9df5ad1SAndroid Build Coastguard Worker
597*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
598*b9df5ad1SAndroid Build Coastguard Worker    name: alias for id
599*b9df5ad1SAndroid Build Coastguard Worker    id: The name of the tag, e.g. for <tag id="BC"/> id = 'BC'
600*b9df5ad1SAndroid Build Coastguard Worker    description: The description of the tag, the contents of the <tag> element.
601*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, which is always the Metadata root node.
602*b9df5ad1SAndroid Build Coastguard Worker    entries: A sequence of edges to entries/clones that are using this Tag.
603*b9df5ad1SAndroid Build Coastguard Worker  """
604*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, name, parent, description=""):
605*b9df5ad1SAndroid Build Coastguard Worker    self._name        = name  # 'id' attribute in XML
606*b9df5ad1SAndroid Build Coastguard Worker    self._id          = name
607*b9df5ad1SAndroid Build Coastguard Worker    self._description = description
608*b9df5ad1SAndroid Build Coastguard Worker    self._parent      = parent
609*b9df5ad1SAndroid Build Coastguard Worker
610*b9df5ad1SAndroid Build Coastguard Worker    # all entries that have this tag, including clones
611*b9df5ad1SAndroid Build Coastguard Worker    self._entries     = []  # filled in by Metadata#construct_tags
612*b9df5ad1SAndroid Build Coastguard Worker
613*b9df5ad1SAndroid Build Coastguard Worker  @property
614*b9df5ad1SAndroid Build Coastguard Worker  def id(self):
615*b9df5ad1SAndroid Build Coastguard Worker    return self._id
616*b9df5ad1SAndroid Build Coastguard Worker
617*b9df5ad1SAndroid Build Coastguard Worker  @property
618*b9df5ad1SAndroid Build Coastguard Worker  def description(self):
619*b9df5ad1SAndroid Build Coastguard Worker    return self._description
620*b9df5ad1SAndroid Build Coastguard Worker
621*b9df5ad1SAndroid Build Coastguard Worker  @property
622*b9df5ad1SAndroid Build Coastguard Worker  def entries(self):
623*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._entries)
624*b9df5ad1SAndroid Build Coastguard Worker
625*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
626*b9df5ad1SAndroid Build Coastguard Worker    return None
627*b9df5ad1SAndroid Build Coastguard Worker
628*b9df5ad1SAndroid Build Coastguard Workerclass Typedef(Node):
629*b9df5ad1SAndroid Build Coastguard Worker  """
630*b9df5ad1SAndroid Build Coastguard Worker  A typedef Node corresponding to a <typedef> element under a top-level <types>.
631*b9df5ad1SAndroid Build Coastguard Worker
632*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
633*b9df5ad1SAndroid Build Coastguard Worker    name: The name of this typedef as a string.
634*b9df5ad1SAndroid Build Coastguard Worker    languages: A dictionary of 'language name' -> 'fully qualified class'.
635*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, which is always the Metadata root node.
636*b9df5ad1SAndroid Build Coastguard Worker    entries: An iterable over all entries which reference this typedef.
637*b9df5ad1SAndroid Build Coastguard Worker  """
638*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, name, parent, languages=None):
639*b9df5ad1SAndroid Build Coastguard Worker    self._name        = name
640*b9df5ad1SAndroid Build Coastguard Worker    self._parent      = parent
641*b9df5ad1SAndroid Build Coastguard Worker
642*b9df5ad1SAndroid Build Coastguard Worker    # all entries that have this typedef
643*b9df5ad1SAndroid Build Coastguard Worker    self._entries     = []  # filled in by Metadata#construct_types
644*b9df5ad1SAndroid Build Coastguard Worker
645*b9df5ad1SAndroid Build Coastguard Worker    self._languages   = languages or {}
646*b9df5ad1SAndroid Build Coastguard Worker
647*b9df5ad1SAndroid Build Coastguard Worker  @property
648*b9df5ad1SAndroid Build Coastguard Worker  def languages(self):
649*b9df5ad1SAndroid Build Coastguard Worker    return self._languages
650*b9df5ad1SAndroid Build Coastguard Worker
651*b9df5ad1SAndroid Build Coastguard Worker  @property
652*b9df5ad1SAndroid Build Coastguard Worker  def entries(self):
653*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._entries)
654*b9df5ad1SAndroid Build Coastguard Worker
655*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
656*b9df5ad1SAndroid Build Coastguard Worker    return None
657*b9df5ad1SAndroid Build Coastguard Worker
658*b9df5ad1SAndroid Build Coastguard Workerclass OuterNamespace(Node):
659*b9df5ad1SAndroid Build Coastguard Worker  """
660*b9df5ad1SAndroid Build Coastguard Worker  A node corresponding to a <namespace> element under <metadata>
661*b9df5ad1SAndroid Build Coastguard Worker
662*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
663*b9df5ad1SAndroid Build Coastguard Worker    name: The name attribute of the <namespace name="foo"> element.
664*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, which is always the Metadata root node.
665*b9df5ad1SAndroid Build Coastguard Worker    sections: A sequence of Section children.
666*b9df5ad1SAndroid Build Coastguard Worker  """
667*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, name, parent, sections=[]):
668*b9df5ad1SAndroid Build Coastguard Worker    self._name = name
669*b9df5ad1SAndroid Build Coastguard Worker    self._parent = parent # MetadataSet
670*b9df5ad1SAndroid Build Coastguard Worker    self._sections = sections[:]
671*b9df5ad1SAndroid Build Coastguard Worker    self._leafs = []
672*b9df5ad1SAndroid Build Coastguard Worker
673*b9df5ad1SAndroid Build Coastguard Worker    self._children = self._sections
674*b9df5ad1SAndroid Build Coastguard Worker
675*b9df5ad1SAndroid Build Coastguard Worker  @property
676*b9df5ad1SAndroid Build Coastguard Worker  def sections(self):
677*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._sections)
678*b9df5ad1SAndroid Build Coastguard Worker
679*b9df5ad1SAndroid Build Coastguard Workerclass Section(Node):
680*b9df5ad1SAndroid Build Coastguard Worker  """
681*b9df5ad1SAndroid Build Coastguard Worker  A node corresponding to a <section> element under <namespace>
682*b9df5ad1SAndroid Build Coastguard Worker
683*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
684*b9df5ad1SAndroid Build Coastguard Worker    name: The name attribute of the <section name="foo"> element.
685*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, which is always an OuterNamespace instance.
686*b9df5ad1SAndroid Build Coastguard Worker    description: A string description of the section, or None.
687*b9df5ad1SAndroid Build Coastguard Worker    kinds: A sequence of Kind children.
688*b9df5ad1SAndroid Build Coastguard Worker    merged_kinds: A sequence of virtual Kind children,
689*b9df5ad1SAndroid Build Coastguard Worker                  with each Kind's children merged by the kind.name
690*b9df5ad1SAndroid Build Coastguard Worker    hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
691*b9df5ad1SAndroid Build Coastguard Worker  """
692*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, name, parent, description=None, kinds=[]):
693*b9df5ad1SAndroid Build Coastguard Worker    self._name = name
694*b9df5ad1SAndroid Build Coastguard Worker    self._parent = parent
695*b9df5ad1SAndroid Build Coastguard Worker    self._description = description
696*b9df5ad1SAndroid Build Coastguard Worker    self._kinds = kinds[:]
697*b9df5ad1SAndroid Build Coastguard Worker
698*b9df5ad1SAndroid Build Coastguard Worker    self._leafs = []
699*b9df5ad1SAndroid Build Coastguard Worker
700*b9df5ad1SAndroid Build Coastguard Worker  @property
701*b9df5ad1SAndroid Build Coastguard Worker  def description(self):
702*b9df5ad1SAndroid Build Coastguard Worker    return self._description
703*b9df5ad1SAndroid Build Coastguard Worker
704*b9df5ad1SAndroid Build Coastguard Worker  @property
705*b9df5ad1SAndroid Build Coastguard Worker  def kinds(self):
706*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._kinds)
707*b9df5ad1SAndroid Build Coastguard Worker
708*b9df5ad1SAndroid Build Coastguard Worker  @property
709*b9df5ad1SAndroid Build Coastguard Worker  def hal_versions(self):
710*b9df5ad1SAndroid Build Coastguard Worker    hal_versions = set()
711*b9df5ad1SAndroid Build Coastguard Worker    for i in self._kinds:
712*b9df5ad1SAndroid Build Coastguard Worker      for entry in i.entries:
713*b9df5ad1SAndroid Build Coastguard Worker        hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
714*b9df5ad1SAndroid Build Coastguard Worker      for namespace in i.namespaces:
715*b9df5ad1SAndroid Build Coastguard Worker        hal_versions.update(namespace.hal_versions)
716*b9df5ad1SAndroid Build Coastguard Worker    return hal_versions
717*b9df5ad1SAndroid Build Coastguard Worker
718*b9df5ad1SAndroid Build Coastguard Worker  def sort_children(self):
719*b9df5ad1SAndroid Build Coastguard Worker    self.validate_tree()
720*b9df5ad1SAndroid Build Coastguard Worker    # order is always controls,static,dynamic
721*b9df5ad1SAndroid Build Coastguard Worker    find_child = lambda x: [i for i in self._get_children() if i.name == x]
722*b9df5ad1SAndroid Build Coastguard Worker    new_lst = find_child('controls') \
723*b9df5ad1SAndroid Build Coastguard Worker            + find_child('static')   \
724*b9df5ad1SAndroid Build Coastguard Worker            + find_child('dynamic')
725*b9df5ad1SAndroid Build Coastguard Worker    self._kinds = new_lst
726*b9df5ad1SAndroid Build Coastguard Worker    self.validate_tree()
727*b9df5ad1SAndroid Build Coastguard Worker
728*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
729*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self.kinds)
730*b9df5ad1SAndroid Build Coastguard Worker
731*b9df5ad1SAndroid Build Coastguard Worker  @property
732*b9df5ad1SAndroid Build Coastguard Worker  def merged_kinds(self):
733*b9df5ad1SAndroid Build Coastguard Worker
734*b9df5ad1SAndroid Build Coastguard Worker    def aggregate_by_name(acc, el):
735*b9df5ad1SAndroid Build Coastguard Worker      existing = [i for i in acc if i.name == el.name]
736*b9df5ad1SAndroid Build Coastguard Worker      if existing:
737*b9df5ad1SAndroid Build Coastguard Worker        k = existing[0]
738*b9df5ad1SAndroid Build Coastguard Worker      else:
739*b9df5ad1SAndroid Build Coastguard Worker        k = Kind(el.name, el.parent)
740*b9df5ad1SAndroid Build Coastguard Worker        acc.append(k)
741*b9df5ad1SAndroid Build Coastguard Worker
742*b9df5ad1SAndroid Build Coastguard Worker      k._namespaces.extend(el._namespaces)
743*b9df5ad1SAndroid Build Coastguard Worker      k._entries.extend(el._entries)
744*b9df5ad1SAndroid Build Coastguard Worker
745*b9df5ad1SAndroid Build Coastguard Worker      return acc
746*b9df5ad1SAndroid Build Coastguard Worker
747*b9df5ad1SAndroid Build Coastguard Worker    new_kinds_lst = functools.reduce(aggregate_by_name, self.kinds, [])
748*b9df5ad1SAndroid Build Coastguard Worker
749*b9df5ad1SAndroid Build Coastguard Worker    for k in new_kinds_lst:
750*b9df5ad1SAndroid Build Coastguard Worker      yield k
751*b9df5ad1SAndroid Build Coastguard Worker
752*b9df5ad1SAndroid Build Coastguard Worker  def combine_kinds_into_single_node(self):
753*b9df5ad1SAndroid Build Coastguard Worker    r"""
754*b9df5ad1SAndroid Build Coastguard Worker    Combines the section's Kinds into a single node.
755*b9df5ad1SAndroid Build Coastguard Worker
756*b9df5ad1SAndroid Build Coastguard Worker    Combines all the children (kinds) of this section into a single
757*b9df5ad1SAndroid Build Coastguard Worker    virtual Kind node.
758*b9df5ad1SAndroid Build Coastguard Worker
759*b9df5ad1SAndroid Build Coastguard Worker    Returns:
760*b9df5ad1SAndroid Build Coastguard Worker      A new Kind node that collapses all Kind siblings into one, combining
761*b9df5ad1SAndroid Build Coastguard Worker      all their children together.
762*b9df5ad1SAndroid Build Coastguard Worker
763*b9df5ad1SAndroid Build Coastguard Worker      For example, given self.kinds == [ x, y ]
764*b9df5ad1SAndroid Build Coastguard Worker
765*b9df5ad1SAndroid Build Coastguard Worker        x  y               z
766*b9df5ad1SAndroid Build Coastguard Worker      / |  | \    -->   / | | \
767*b9df5ad1SAndroid Build Coastguard Worker      a b  c d          a b c d
768*b9df5ad1SAndroid Build Coastguard Worker
769*b9df5ad1SAndroid Build Coastguard Worker      a new instance z is returned in this example.
770*b9df5ad1SAndroid Build Coastguard Worker
771*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
772*b9df5ad1SAndroid Build Coastguard Worker      The children of the kinds are the same references as before, that is
773*b9df5ad1SAndroid Build Coastguard Worker      their parents will point to the old parents and not to the new parent.
774*b9df5ad1SAndroid Build Coastguard Worker    """
775*b9df5ad1SAndroid Build Coastguard Worker    combined = Kind(name="combined", parent=self)
776*b9df5ad1SAndroid Build Coastguard Worker
777*b9df5ad1SAndroid Build Coastguard Worker    for k in self._get_children():
778*b9df5ad1SAndroid Build Coastguard Worker      combined._namespaces.extend(k.namespaces)
779*b9df5ad1SAndroid Build Coastguard Worker      combined._entries.extend(k.entries)
780*b9df5ad1SAndroid Build Coastguard Worker
781*b9df5ad1SAndroid Build Coastguard Worker    return combined
782*b9df5ad1SAndroid Build Coastguard Worker
783*b9df5ad1SAndroid Build Coastguard Workerclass Kind(Node):
784*b9df5ad1SAndroid Build Coastguard Worker  """
785*b9df5ad1SAndroid Build Coastguard Worker  A node corresponding to one of: <static>,<dynamic>,<controls> under a
786*b9df5ad1SAndroid Build Coastguard Worker  <section> element.
787*b9df5ad1SAndroid Build Coastguard Worker
788*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
789*b9df5ad1SAndroid Build Coastguard Worker    name: A string which is one of 'static', 'dynamic, or 'controls'.
790*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, which is always a Section  instance.
791*b9df5ad1SAndroid Build Coastguard Worker    namespaces: A sequence of InnerNamespace children.
792*b9df5ad1SAndroid Build Coastguard Worker    entries: A sequence of Entry/Clone children.
793*b9df5ad1SAndroid Build Coastguard Worker    merged_entries: A sequence of MergedEntry virtual nodes from entries
794*b9df5ad1SAndroid Build Coastguard Worker  """
795*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, name, parent):
796*b9df5ad1SAndroid Build Coastguard Worker    self._name = name
797*b9df5ad1SAndroid Build Coastguard Worker    self._parent = parent
798*b9df5ad1SAndroid Build Coastguard Worker    self._namespaces = []
799*b9df5ad1SAndroid Build Coastguard Worker    self._entries = []
800*b9df5ad1SAndroid Build Coastguard Worker
801*b9df5ad1SAndroid Build Coastguard Worker    self._leafs = []
802*b9df5ad1SAndroid Build Coastguard Worker
803*b9df5ad1SAndroid Build Coastguard Worker  @property
804*b9df5ad1SAndroid Build Coastguard Worker  def namespaces(self):
805*b9df5ad1SAndroid Build Coastguard Worker    return self._namespaces
806*b9df5ad1SAndroid Build Coastguard Worker
807*b9df5ad1SAndroid Build Coastguard Worker  @property
808*b9df5ad1SAndroid Build Coastguard Worker  def entries(self):
809*b9df5ad1SAndroid Build Coastguard Worker    return self._entries
810*b9df5ad1SAndroid Build Coastguard Worker
811*b9df5ad1SAndroid Build Coastguard Worker  @property
812*b9df5ad1SAndroid Build Coastguard Worker  def merged_entries(self):
813*b9df5ad1SAndroid Build Coastguard Worker    for i in self.entries:
814*b9df5ad1SAndroid Build Coastguard Worker      yield i.merge()
815*b9df5ad1SAndroid Build Coastguard Worker
816*b9df5ad1SAndroid Build Coastguard Worker  def sort_children(self):
817*b9df5ad1SAndroid Build Coastguard Worker    self._namespaces.sort(key=self._get_name())
818*b9df5ad1SAndroid Build Coastguard Worker    self._entries.sort(key=self._get_name())
819*b9df5ad1SAndroid Build Coastguard Worker
820*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
821*b9df5ad1SAndroid Build Coastguard Worker    for i in self.namespaces:
822*b9df5ad1SAndroid Build Coastguard Worker      yield i
823*b9df5ad1SAndroid Build Coastguard Worker    for i in self.entries:
824*b9df5ad1SAndroid Build Coastguard Worker      yield i
825*b9df5ad1SAndroid Build Coastguard Worker
826*b9df5ad1SAndroid Build Coastguard Worker  def combine_children_by_name(self):
827*b9df5ad1SAndroid Build Coastguard Worker    r"""
828*b9df5ad1SAndroid Build Coastguard Worker    Combine multiple children with the same name into a single node.
829*b9df5ad1SAndroid Build Coastguard Worker
830*b9df5ad1SAndroid Build Coastguard Worker    Returns:
831*b9df5ad1SAndroid Build Coastguard Worker      A new Kind where all of the children with the same name were combined.
832*b9df5ad1SAndroid Build Coastguard Worker
833*b9df5ad1SAndroid Build Coastguard Worker      For example:
834*b9df5ad1SAndroid Build Coastguard Worker
835*b9df5ad1SAndroid Build Coastguard Worker      Given a Kind k:
836*b9df5ad1SAndroid Build Coastguard Worker
837*b9df5ad1SAndroid Build Coastguard Worker              k
838*b9df5ad1SAndroid Build Coastguard Worker            / | \
839*b9df5ad1SAndroid Build Coastguard Worker            a b c
840*b9df5ad1SAndroid Build Coastguard Worker            | | |
841*b9df5ad1SAndroid Build Coastguard Worker            d e f
842*b9df5ad1SAndroid Build Coastguard Worker
843*b9df5ad1SAndroid Build Coastguard Worker      a.name == "foo"
844*b9df5ad1SAndroid Build Coastguard Worker      b.name == "foo"
845*b9df5ad1SAndroid Build Coastguard Worker      c.name == "bar"
846*b9df5ad1SAndroid Build Coastguard Worker
847*b9df5ad1SAndroid Build Coastguard Worker      The returned Kind will look like this:
848*b9df5ad1SAndroid Build Coastguard Worker
849*b9df5ad1SAndroid Build Coastguard Worker             k'
850*b9df5ad1SAndroid Build Coastguard Worker            /  \
851*b9df5ad1SAndroid Build Coastguard Worker            a' c'
852*b9df5ad1SAndroid Build Coastguard Worker          / |  |
853*b9df5ad1SAndroid Build Coastguard Worker          d e  f
854*b9df5ad1SAndroid Build Coastguard Worker
855*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
856*b9df5ad1SAndroid Build Coastguard Worker      This operation is not recursive. To combine the grandchildren and other
857*b9df5ad1SAndroid Build Coastguard Worker      ancestors, call this method on the ancestor nodes.
858*b9df5ad1SAndroid Build Coastguard Worker    """
859*b9df5ad1SAndroid Build Coastguard Worker    return Kind._combine_children_by_name(self, new_type=type(self))
860*b9df5ad1SAndroid Build Coastguard Worker
861*b9df5ad1SAndroid Build Coastguard Worker  # new_type is either Kind or InnerNamespace
862*b9df5ad1SAndroid Build Coastguard Worker  @staticmethod
863*b9df5ad1SAndroid Build Coastguard Worker  def _combine_children_by_name(self, new_type):
864*b9df5ad1SAndroid Build Coastguard Worker    new_ins_dict = OrderedDict()
865*b9df5ad1SAndroid Build Coastguard Worker    new_ent_dict = OrderedDict()
866*b9df5ad1SAndroid Build Coastguard Worker
867*b9df5ad1SAndroid Build Coastguard Worker    for ins in self.namespaces:
868*b9df5ad1SAndroid Build Coastguard Worker      new_ins = new_ins_dict.setdefault(ins.name,
869*b9df5ad1SAndroid Build Coastguard Worker                                        InnerNamespace(ins.name, parent=self))
870*b9df5ad1SAndroid Build Coastguard Worker      new_ins._namespaces.extend(ins.namespaces)
871*b9df5ad1SAndroid Build Coastguard Worker      new_ins._entries.extend(ins.entries)
872*b9df5ad1SAndroid Build Coastguard Worker
873*b9df5ad1SAndroid Build Coastguard Worker    for ent in self.entries:
874*b9df5ad1SAndroid Build Coastguard Worker      new_ent = new_ent_dict.setdefault(ent.name,
875*b9df5ad1SAndroid Build Coastguard Worker                                        ent.merge())
876*b9df5ad1SAndroid Build Coastguard Worker
877*b9df5ad1SAndroid Build Coastguard Worker    kind = new_type(self.name, self.parent)
878*b9df5ad1SAndroid Build Coastguard Worker    kind._namespaces = new_ins_dict.values()
879*b9df5ad1SAndroid Build Coastguard Worker    kind._entries = new_ent_dict.values()
880*b9df5ad1SAndroid Build Coastguard Worker
881*b9df5ad1SAndroid Build Coastguard Worker    return kind
882*b9df5ad1SAndroid Build Coastguard Worker
883*b9df5ad1SAndroid Build Coastguard Workerclass InnerNamespace(Node):
884*b9df5ad1SAndroid Build Coastguard Worker  """
885*b9df5ad1SAndroid Build Coastguard Worker  A node corresponding to a <namespace> which is an ancestor of a Kind.
886*b9df5ad1SAndroid Build Coastguard Worker  These namespaces may have other namespaces recursively, or entries as leafs.
887*b9df5ad1SAndroid Build Coastguard Worker
888*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
889*b9df5ad1SAndroid Build Coastguard Worker    name: Name attribute from the element, e.g. <namespace name="foo"> -> 'foo'
890*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, which is an InnerNamespace or a Kind.
891*b9df5ad1SAndroid Build Coastguard Worker    namespaces: A sequence of InnerNamespace children.
892*b9df5ad1SAndroid Build Coastguard Worker    entries: A sequence of Entry/Clone children.
893*b9df5ad1SAndroid Build Coastguard Worker    merged_entries: A sequence of MergedEntry virtual nodes from entries
894*b9df5ad1SAndroid Build Coastguard Worker    hal_versions: A set of tuples (major, minor) describing all the HAL versions entries in this section have
895*b9df5ad1SAndroid Build Coastguard Worker  """
896*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, name, parent):
897*b9df5ad1SAndroid Build Coastguard Worker    self._name        = name
898*b9df5ad1SAndroid Build Coastguard Worker    self._parent      = parent
899*b9df5ad1SAndroid Build Coastguard Worker    self._namespaces  = []
900*b9df5ad1SAndroid Build Coastguard Worker    self._entries     = []
901*b9df5ad1SAndroid Build Coastguard Worker    self._leafs       = []
902*b9df5ad1SAndroid Build Coastguard Worker
903*b9df5ad1SAndroid Build Coastguard Worker  @property
904*b9df5ad1SAndroid Build Coastguard Worker  def namespaces(self):
905*b9df5ad1SAndroid Build Coastguard Worker    return self._namespaces
906*b9df5ad1SAndroid Build Coastguard Worker
907*b9df5ad1SAndroid Build Coastguard Worker  @property
908*b9df5ad1SAndroid Build Coastguard Worker  def entries(self):
909*b9df5ad1SAndroid Build Coastguard Worker    return self._entries
910*b9df5ad1SAndroid Build Coastguard Worker
911*b9df5ad1SAndroid Build Coastguard Worker  @property
912*b9df5ad1SAndroid Build Coastguard Worker  def hal_versions(self):
913*b9df5ad1SAndroid Build Coastguard Worker    hal_versions = set()
914*b9df5ad1SAndroid Build Coastguard Worker    for entry in self.entries:
915*b9df5ad1SAndroid Build Coastguard Worker      hal_versions.add( (entry.hal_major_version, entry.hal_minor_version) )
916*b9df5ad1SAndroid Build Coastguard Worker    for namespace in self.namespaces:
917*b9df5ad1SAndroid Build Coastguard Worker      hal_versions.update(namespace.hal_versions)
918*b9df5ad1SAndroid Build Coastguard Worker    return hal_versions
919*b9df5ad1SAndroid Build Coastguard Worker
920*b9df5ad1SAndroid Build Coastguard Worker  @property
921*b9df5ad1SAndroid Build Coastguard Worker  def merged_entries(self):
922*b9df5ad1SAndroid Build Coastguard Worker    for i in self.entries:
923*b9df5ad1SAndroid Build Coastguard Worker      yield i.merge()
924*b9df5ad1SAndroid Build Coastguard Worker
925*b9df5ad1SAndroid Build Coastguard Worker  def sort_children(self):
926*b9df5ad1SAndroid Build Coastguard Worker    self._namespaces.sort(key=self._get_name())
927*b9df5ad1SAndroid Build Coastguard Worker    self._entries.sort(key=self._get_name())
928*b9df5ad1SAndroid Build Coastguard Worker
929*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
930*b9df5ad1SAndroid Build Coastguard Worker    for i in self.namespaces:
931*b9df5ad1SAndroid Build Coastguard Worker      yield i
932*b9df5ad1SAndroid Build Coastguard Worker    for i in self.entries:
933*b9df5ad1SAndroid Build Coastguard Worker      yield i
934*b9df5ad1SAndroid Build Coastguard Worker
935*b9df5ad1SAndroid Build Coastguard Worker  def combine_children_by_name(self):
936*b9df5ad1SAndroid Build Coastguard Worker    r"""
937*b9df5ad1SAndroid Build Coastguard Worker    Combine multiple children with the same name into a single node.
938*b9df5ad1SAndroid Build Coastguard Worker
939*b9df5ad1SAndroid Build Coastguard Worker    Returns:
940*b9df5ad1SAndroid Build Coastguard Worker      A new InnerNamespace where all of the children with the same name were
941*b9df5ad1SAndroid Build Coastguard Worker      combined.
942*b9df5ad1SAndroid Build Coastguard Worker
943*b9df5ad1SAndroid Build Coastguard Worker      For example:
944*b9df5ad1SAndroid Build Coastguard Worker
945*b9df5ad1SAndroid Build Coastguard Worker      Given an InnerNamespace i:
946*b9df5ad1SAndroid Build Coastguard Worker
947*b9df5ad1SAndroid Build Coastguard Worker              i
948*b9df5ad1SAndroid Build Coastguard Worker            / | \
949*b9df5ad1SAndroid Build Coastguard Worker            a b c
950*b9df5ad1SAndroid Build Coastguard Worker            | | |
951*b9df5ad1SAndroid Build Coastguard Worker            d e f
952*b9df5ad1SAndroid Build Coastguard Worker
953*b9df5ad1SAndroid Build Coastguard Worker      a.name == "foo"
954*b9df5ad1SAndroid Build Coastguard Worker      b.name == "foo"
955*b9df5ad1SAndroid Build Coastguard Worker      c.name == "bar"
956*b9df5ad1SAndroid Build Coastguard Worker
957*b9df5ad1SAndroid Build Coastguard Worker      The returned InnerNamespace will look like this:
958*b9df5ad1SAndroid Build Coastguard Worker
959*b9df5ad1SAndroid Build Coastguard Worker             i'
960*b9df5ad1SAndroid Build Coastguard Worker            /  \
961*b9df5ad1SAndroid Build Coastguard Worker            a' c'
962*b9df5ad1SAndroid Build Coastguard Worker          / |  |
963*b9df5ad1SAndroid Build Coastguard Worker          d e  f
964*b9df5ad1SAndroid Build Coastguard Worker
965*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
966*b9df5ad1SAndroid Build Coastguard Worker      This operation is not recursive. To combine the grandchildren and other
967*b9df5ad1SAndroid Build Coastguard Worker      ancestors, call this method on the ancestor nodes.
968*b9df5ad1SAndroid Build Coastguard Worker    """
969*b9df5ad1SAndroid Build Coastguard Worker    return Kind._combine_children_by_name(self, new_type=type(self))
970*b9df5ad1SAndroid Build Coastguard Worker
971*b9df5ad1SAndroid Build Coastguard Workerclass EnumValue(Node):
972*b9df5ad1SAndroid Build Coastguard Worker  """
973*b9df5ad1SAndroid Build Coastguard Worker  A class corresponding to a <value> element within an <enum> within an <entry>.
974*b9df5ad1SAndroid Build Coastguard Worker
975*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
976*b9df5ad1SAndroid Build Coastguard Worker    name: A string,                 e.g. 'ON' or 'OFF'
977*b9df5ad1SAndroid Build Coastguard Worker    id: An optional numeric string, e.g. '0' or '0xFF'
978*b9df5ad1SAndroid Build Coastguard Worker    deprecated: A boolean, True if the enum should be deprecated.
979*b9df5ad1SAndroid Build Coastguard Worker    optional: A boolean
980*b9df5ad1SAndroid Build Coastguard Worker    visibility: A string, one of "system", "java_public", "ndk_public", "hidden", "public",
981*b9df5ad1SAndroid Build Coastguard Worker                "fwk_java_public", "fwk_public", "fwk_ndk_public", "extension", "fwk_system_public"
982*b9df5ad1SAndroid Build Coastguard Worker    notes: A string describing the notes, or None.
983*b9df5ad1SAndroid Build Coastguard Worker    sdk_notes: A string describing extra notes for public SDK only
984*b9df5ad1SAndroid Build Coastguard Worker    ndk_notes: A string describing extra notes for public NDK only
985*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, always an Enum instance.
986*b9df5ad1SAndroid Build Coastguard Worker    hal_major_version: The major HIDL HAL version this value was first added in
987*b9df5ad1SAndroid Build Coastguard Worker    hal_minor_version: The minor HIDL HAL version this value was first added in
988*b9df5ad1SAndroid Build Coastguard Worker    aconfig_flag: The aconfig flag name that determines if this enum value is actually enabled
989*b9df5ad1SAndroid Build Coastguard Worker  """
990*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, name, parent,
991*b9df5ad1SAndroid Build Coastguard Worker               id=None, deprecated=False, optional=False, visibility=None, notes=None,
992*b9df5ad1SAndroid Build Coastguard Worker               sdk_notes=None, ndk_notes=None, hal_version='3.2', aconfig_flag=None):
993*b9df5ad1SAndroid Build Coastguard Worker    self._name = name                    # str, e.g. 'ON' or 'OFF'
994*b9df5ad1SAndroid Build Coastguard Worker    self._id = id                        # int, e.g. '0'
995*b9df5ad1SAndroid Build Coastguard Worker    self._deprecated = deprecated        # bool
996*b9df5ad1SAndroid Build Coastguard Worker    self._optional = optional            # bool
997*b9df5ad1SAndroid Build Coastguard Worker    self._visibility = visibility        # None or str; None is same as public
998*b9df5ad1SAndroid Build Coastguard Worker    self._notes = notes                  # None or str
999*b9df5ad1SAndroid Build Coastguard Worker    self._sdk_notes = sdk_notes          # None or str
1000*b9df5ad1SAndroid Build Coastguard Worker    self._ndk_notes = ndk_notes          # None or str
1001*b9df5ad1SAndroid Build Coastguard Worker    self._parent = parent
1002*b9df5ad1SAndroid Build Coastguard Worker    if hal_version is None:
1003*b9df5ad1SAndroid Build Coastguard Worker      if parent is not None and parent.parent is not None:
1004*b9df5ad1SAndroid Build Coastguard Worker        self._hal_major_version = parent.parent.hal_major_version
1005*b9df5ad1SAndroid Build Coastguard Worker        self._hal_minor_version = parent.parent.hal_minor_version
1006*b9df5ad1SAndroid Build Coastguard Worker      else:
1007*b9df5ad1SAndroid Build Coastguard Worker        self._hal_major_version = 3
1008*b9df5ad1SAndroid Build Coastguard Worker        self._hal_minor_version = 2
1009*b9df5ad1SAndroid Build Coastguard Worker    else:
1010*b9df5ad1SAndroid Build Coastguard Worker      self._hal_major_version = int(hal_version.partition('.')[0])
1011*b9df5ad1SAndroid Build Coastguard Worker      self._hal_minor_version = int(hal_version.partition('.')[2])
1012*b9df5ad1SAndroid Build Coastguard Worker
1013*b9df5ad1SAndroid Build Coastguard Worker    self._aconfig_flag = aconfig_flag
1014*b9df5ad1SAndroid Build Coastguard Worker    if self._aconfig_flag is None:
1015*b9df5ad1SAndroid Build Coastguard Worker      if parent is not None and parent.parent is not None:
1016*b9df5ad1SAndroid Build Coastguard Worker        self._aconfig_flag = parent.parent.aconfig_flag
1017*b9df5ad1SAndroid Build Coastguard Worker
1018*b9df5ad1SAndroid Build Coastguard Worker  @property
1019*b9df5ad1SAndroid Build Coastguard Worker  def id(self):
1020*b9df5ad1SAndroid Build Coastguard Worker    return self._id
1021*b9df5ad1SAndroid Build Coastguard Worker
1022*b9df5ad1SAndroid Build Coastguard Worker  @property
1023*b9df5ad1SAndroid Build Coastguard Worker  def deprecated(self):
1024*b9df5ad1SAndroid Build Coastguard Worker    return self._deprecated
1025*b9df5ad1SAndroid Build Coastguard Worker
1026*b9df5ad1SAndroid Build Coastguard Worker  @property
1027*b9df5ad1SAndroid Build Coastguard Worker  def optional(self):
1028*b9df5ad1SAndroid Build Coastguard Worker    return self._optional
1029*b9df5ad1SAndroid Build Coastguard Worker
1030*b9df5ad1SAndroid Build Coastguard Worker  @property
1031*b9df5ad1SAndroid Build Coastguard Worker  def visibility(self):
1032*b9df5ad1SAndroid Build Coastguard Worker    return self._visibility
1033*b9df5ad1SAndroid Build Coastguard Worker
1034*b9df5ad1SAndroid Build Coastguard Worker  @property
1035*b9df5ad1SAndroid Build Coastguard Worker  def applied_visibility(self):
1036*b9df5ad1SAndroid Build Coastguard Worker    return self._visibility or 'public'
1037*b9df5ad1SAndroid Build Coastguard Worker
1038*b9df5ad1SAndroid Build Coastguard Worker  @property
1039*b9df5ad1SAndroid Build Coastguard Worker  def hidl_comment_string(self):
1040*b9df5ad1SAndroid Build Coastguard Worker    parent_enum = None
1041*b9df5ad1SAndroid Build Coastguard Worker    if (self.parent is not None and self.parent.parent is not None):
1042*b9df5ad1SAndroid Build Coastguard Worker      parent_enum = self.parent.parent
1043*b9df5ad1SAndroid Build Coastguard Worker    if parent_enum is not None and parent_enum.visibility in ('fwk_only', 'fwk_java_public',\
1044*b9df5ad1SAndroid Build Coastguard Worker        'fwk_public', 'fwk_ndk_public') or self._visibility in ('fwk_only', 'fwk_java_public',\
1045*b9df5ad1SAndroid Build Coastguard Worker        'fwk_public', 'fwk_ndk_public'):
1046*b9df5ad1SAndroid Build Coastguard Worker      return ','
1047*b9df5ad1SAndroid Build Coastguard Worker    return ', // HIDL v' + str(self._hal_major_version) + '.' + str(self.hal_minor_version)
1048*b9df5ad1SAndroid Build Coastguard Worker
1049*b9df5ad1SAndroid Build Coastguard Worker  @property
1050*b9df5ad1SAndroid Build Coastguard Worker  def hidden(self):
1051*b9df5ad1SAndroid Build Coastguard Worker    return self.visibility in {'hidden', 'ndk_public', 'test', 'extension', 'fwk_system_public'}
1052*b9df5ad1SAndroid Build Coastguard Worker
1053*b9df5ad1SAndroid Build Coastguard Worker  @property
1054*b9df5ad1SAndroid Build Coastguard Worker  def ndk_hidden(self):
1055*b9df5ad1SAndroid Build Coastguard Worker    return self._visibility in {'hidden', 'java_public', 'test'}
1056*b9df5ad1SAndroid Build Coastguard Worker
1057*b9df5ad1SAndroid Build Coastguard Worker  @property
1058*b9df5ad1SAndroid Build Coastguard Worker  def notes(self):
1059*b9df5ad1SAndroid Build Coastguard Worker    return self._notes
1060*b9df5ad1SAndroid Build Coastguard Worker
1061*b9df5ad1SAndroid Build Coastguard Worker  @property
1062*b9df5ad1SAndroid Build Coastguard Worker  def sdk_notes(self):
1063*b9df5ad1SAndroid Build Coastguard Worker    return self._sdk_notes
1064*b9df5ad1SAndroid Build Coastguard Worker
1065*b9df5ad1SAndroid Build Coastguard Worker  @property
1066*b9df5ad1SAndroid Build Coastguard Worker  def ndk_notes(self):
1067*b9df5ad1SAndroid Build Coastguard Worker    return self._ndk_notes
1068*b9df5ad1SAndroid Build Coastguard Worker
1069*b9df5ad1SAndroid Build Coastguard Worker  @property
1070*b9df5ad1SAndroid Build Coastguard Worker  def hal_major_version(self):
1071*b9df5ad1SAndroid Build Coastguard Worker    return self._hal_major_version
1072*b9df5ad1SAndroid Build Coastguard Worker
1073*b9df5ad1SAndroid Build Coastguard Worker  @property
1074*b9df5ad1SAndroid Build Coastguard Worker  def hal_minor_version(self):
1075*b9df5ad1SAndroid Build Coastguard Worker    return self._hal_minor_version
1076*b9df5ad1SAndroid Build Coastguard Worker
1077*b9df5ad1SAndroid Build Coastguard Worker  @property
1078*b9df5ad1SAndroid Build Coastguard Worker  def aconfig_flag(self):
1079*b9df5ad1SAndroid Build Coastguard Worker    return self._aconfig_flag
1080*b9df5ad1SAndroid Build Coastguard Worker
1081*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
1082*b9df5ad1SAndroid Build Coastguard Worker    return None
1083*b9df5ad1SAndroid Build Coastguard Worker
1084*b9df5ad1SAndroid Build Coastguard Workerclass Enum(Node):
1085*b9df5ad1SAndroid Build Coastguard Worker  """
1086*b9df5ad1SAndroid Build Coastguard Worker  A class corresponding to an <enum> element within an <entry>.
1087*b9df5ad1SAndroid Build Coastguard Worker
1088*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
1089*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent, always an Entry instance.
1090*b9df5ad1SAndroid Build Coastguard Worker    values: A sequence of EnumValue children.
1091*b9df5ad1SAndroid Build Coastguard Worker    has_values_with_id: A boolean representing if any of the children have a
1092*b9df5ad1SAndroid Build Coastguard Worker        non-empty id property.
1093*b9df5ad1SAndroid Build Coastguard Worker  """
1094*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, parent, values, ids={}, deprecateds=[],
1095*b9df5ad1SAndroid Build Coastguard Worker               optionals=[], visibilities={}, notes={}, sdk_notes={}, ndk_notes={},
1096*b9df5ad1SAndroid Build Coastguard Worker               hal_versions={}, aconfig_flags={}):
1097*b9df5ad1SAndroid Build Coastguard Worker    self._parent = parent
1098*b9df5ad1SAndroid Build Coastguard Worker    self._name = None
1099*b9df5ad1SAndroid Build Coastguard Worker    self._values =                                                             \
1100*b9df5ad1SAndroid Build Coastguard Worker      [ EnumValue(val, self, ids.get(val), val in deprecateds, val in optionals, visibilities.get(val), \
1101*b9df5ad1SAndroid Build Coastguard Worker                  notes.get(val), sdk_notes.get(val), ndk_notes.get(val), hal_versions.get(val),        \
1102*b9df5ad1SAndroid Build Coastguard Worker                  aconfig_flags.get(val)) \
1103*b9df5ad1SAndroid Build Coastguard Worker        for val in values ]
1104*b9df5ad1SAndroid Build Coastguard Worker
1105*b9df5ad1SAndroid Build Coastguard Worker  @property
1106*b9df5ad1SAndroid Build Coastguard Worker  def values(self):
1107*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._values)
1108*b9df5ad1SAndroid Build Coastguard Worker
1109*b9df5ad1SAndroid Build Coastguard Worker  @property
1110*b9df5ad1SAndroid Build Coastguard Worker  def has_values_with_id(self):
1111*b9df5ad1SAndroid Build Coastguard Worker    return bool(any(i for i in self.values if i.id))
1112*b9df5ad1SAndroid Build Coastguard Worker
1113*b9df5ad1SAndroid Build Coastguard Worker  def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1114*b9df5ad1SAndroid Build Coastguard Worker    return bool(any(i for i in self.values if i.hal_major_version == hal_major_version and i.hal_minor_version == hal_minor_version))
1115*b9df5ad1SAndroid Build Coastguard Worker
1116*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
1117*b9df5ad1SAndroid Build Coastguard Worker    return (i for i in self._values)
1118*b9df5ad1SAndroid Build Coastguard Worker
1119*b9df5ad1SAndroid Build Coastguard Workerclass Entry(Node):
1120*b9df5ad1SAndroid Build Coastguard Worker  """
1121*b9df5ad1SAndroid Build Coastguard Worker  A node corresponding to an <entry> element.
1122*b9df5ad1SAndroid Build Coastguard Worker
1123*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
1124*b9df5ad1SAndroid Build Coastguard Worker    parent: An edge to the parent node, which is an InnerNamespace or Kind.
1125*b9df5ad1SAndroid Build Coastguard Worker    name: The fully qualified name string, e.g. 'android.shading.mode'
1126*b9df5ad1SAndroid Build Coastguard Worker    name_short: The name attribute from <entry name="mode">, e.g. mode
1127*b9df5ad1SAndroid Build Coastguard Worker    type: The type attribute from <entry type="bar">
1128*b9df5ad1SAndroid Build Coastguard Worker    kind: A string ('static', 'dynamic', 'controls') corresponding to the
1129*b9df5ad1SAndroid Build Coastguard Worker          ancestor Kind#name
1130*b9df5ad1SAndroid Build Coastguard Worker    container: The container attribute from <entry container="array">, or None.
1131*b9df5ad1SAndroid Build Coastguard Worker    container_sizes: A sequence of size strings or None if container is None.
1132*b9df5ad1SAndroid Build Coastguard Worker    enum: An Enum instance if the enum attribute is true, None otherwise.
1133*b9df5ad1SAndroid Build Coastguard Worker    visibility: The visibility of this entry ('system', 'hidden', 'public' etc)
1134*b9df5ad1SAndroid Build Coastguard Worker                across the system. System entries are only visible in native code
1135*b9df5ad1SAndroid Build Coastguard Worker                headers. Hidden entries are marked @hide in managed code, while
1136*b9df5ad1SAndroid Build Coastguard Worker                public entries are visible in the Android SDK.
1137*b9df5ad1SAndroid Build Coastguard Worker    applied_visibility: As visibility, but always valid, defaulting to 'system'
1138*b9df5ad1SAndroid Build Coastguard Worker                        if no visibility is given for an entry.
1139*b9df5ad1SAndroid Build Coastguard Worker    applied_ndk_visible: Always valid. Default is 'false'.
1140*b9df5ad1SAndroid Build Coastguard Worker                         Set to 'true' when the visibility implied entry is visible
1141*b9df5ad1SAndroid Build Coastguard Worker                         in NDK.
1142*b9df5ad1SAndroid Build Coastguard Worker    synthetic: The C-level visibility of this entry ('false', 'true').
1143*b9df5ad1SAndroid Build Coastguard Worker               Synthetic entries will not be generated into the native metadata
1144*b9df5ad1SAndroid Build Coastguard Worker               list of entries (in C code). In general a synthetic entry is
1145*b9df5ad1SAndroid Build Coastguard Worker               glued together at the Java layer from multiple visibiltity=hidden
1146*b9df5ad1SAndroid Build Coastguard Worker               entries.
1147*b9df5ad1SAndroid Build Coastguard Worker    hwlevel: The lowest hardware level at which the entry is guaranteed
1148*b9df5ad1SAndroid Build Coastguard Worker             to be supported by the camera device. All devices with higher
1149*b9df5ad1SAndroid Build Coastguard Worker             hwlevels will also include this entry. None means that the
1150*b9df5ad1SAndroid Build Coastguard Worker             entry is optional on any hardware level.
1151*b9df5ad1SAndroid Build Coastguard Worker    permission_needed: Flags whether the tag needs extra camera permission.
1152*b9df5ad1SAndroid Build Coastguard Worker    aconfig_flag: The aconfig flag name that determines if the entry is actually enabled
1153*b9df5ad1SAndroid Build Coastguard Worker    deprecated: Marks an entry as @Deprecated in the Java layer; if within an
1154*b9df5ad1SAndroid Build Coastguard Worker               unreleased version this needs to be removed altogether. If applied
1155*b9df5ad1SAndroid Build Coastguard Worker               to an entry from an older release, then this means the entry
1156*b9df5ad1SAndroid Build Coastguard Worker               should be ignored by newer code.
1157*b9df5ad1SAndroid Build Coastguard Worker    optional: a bool representing the optional attribute, which denotes the entry
1158*b9df5ad1SAndroid Build Coastguard Worker              is required for hardware level full devices, but optional for other
1159*b9df5ad1SAndroid Build Coastguard Worker              hardware levels.  None if not present.
1160*b9df5ad1SAndroid Build Coastguard Worker    applied_optional: As optional but always valid, defaulting to False if no
1161*b9df5ad1SAndroid Build Coastguard Worker                      optional attribute is present.
1162*b9df5ad1SAndroid Build Coastguard Worker    tuple_values: A sequence of strings describing the tuple values,
1163*b9df5ad1SAndroid Build Coastguard Worker                  None if container is not 'tuple'.
1164*b9df5ad1SAndroid Build Coastguard Worker    description: A string description, or None.
1165*b9df5ad1SAndroid Build Coastguard Worker    deprecation_description: A string describing the reason for deprecation. Must be present
1166*b9df5ad1SAndroid Build Coastguard Worker                 if deprecated is true, otherwise may be None.
1167*b9df5ad1SAndroid Build Coastguard Worker    range: A string range, or None.
1168*b9df5ad1SAndroid Build Coastguard Worker    units: A string units, or None.
1169*b9df5ad1SAndroid Build Coastguard Worker    tags: A sequence of Tag nodes associated with this Entry.
1170*b9df5ad1SAndroid Build Coastguard Worker    type_notes: A string describing notes for the type, or None.
1171*b9df5ad1SAndroid Build Coastguard Worker    typedef: A Typedef associated with this Entry, or None.
1172*b9df5ad1SAndroid Build Coastguard Worker
1173*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
1174*b9df5ad1SAndroid Build Coastguard Worker    Subclass Clone can be used interchangeable with an Entry,
1175*b9df5ad1SAndroid Build Coastguard Worker    for when we don't care about the underlying type.
1176*b9df5ad1SAndroid Build Coastguard Worker
1177*b9df5ad1SAndroid Build Coastguard Worker    parent and tags edges are invalid until after Metadata#construct_graph
1178*b9df5ad1SAndroid Build Coastguard Worker    has been invoked.
1179*b9df5ad1SAndroid Build Coastguard Worker  """
1180*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, **kwargs):
1181*b9df5ad1SAndroid Build Coastguard Worker    """
1182*b9df5ad1SAndroid Build Coastguard Worker    Instantiate a new Entry node.
1183*b9df5ad1SAndroid Build Coastguard Worker
1184*b9df5ad1SAndroid Build Coastguard Worker    Args:
1185*b9df5ad1SAndroid Build Coastguard Worker      name: A string with the fully qualified name, e.g. 'android.shading.mode'
1186*b9df5ad1SAndroid Build Coastguard Worker      type: A string describing the type, e.g. 'int32'
1187*b9df5ad1SAndroid Build Coastguard Worker      kind: A string describing the kind, e.g. 'static'
1188*b9df5ad1SAndroid Build Coastguard Worker      hal_version: A string for the initial HIDL HAL metadata version this entry
1189*b9df5ad1SAndroid Build Coastguard Worker                   was added in
1190*b9df5ad1SAndroid Build Coastguard Worker
1191*b9df5ad1SAndroid Build Coastguard Worker    Args (if container):
1192*b9df5ad1SAndroid Build Coastguard Worker      container: A string describing the container, e.g. 'array' or 'tuple'
1193*b9df5ad1SAndroid Build Coastguard Worker      container_sizes: A list of string sizes if a container, or None otherwise
1194*b9df5ad1SAndroid Build Coastguard Worker
1195*b9df5ad1SAndroid Build Coastguard Worker    Args (if container is 'tuple'):
1196*b9df5ad1SAndroid Build Coastguard Worker      tuple_values: A list of tuple values, e.g. ['width', 'height']
1197*b9df5ad1SAndroid Build Coastguard Worker
1198*b9df5ad1SAndroid Build Coastguard Worker    Args (if the 'enum' attribute is true):
1199*b9df5ad1SAndroid Build Coastguard Worker      enum: A boolean, True if this is an enum, False otherwise
1200*b9df5ad1SAndroid Build Coastguard Worker      enum_values: A list of value strings, e.g. ['ON', 'OFF']
1201*b9df5ad1SAndroid Build Coastguard Worker      enum_optionals: A list of optional enum values, e.g. ['OFF']
1202*b9df5ad1SAndroid Build Coastguard Worker      enum_notes: A dictionary of value->notes strings.
1203*b9df5ad1SAndroid Build Coastguard Worker      enum_ids: A dictionary of value->id strings.
1204*b9df5ad1SAndroid Build Coastguard Worker      enum_hal_versions: A dictionary of value->hal version strings
1205*b9df5ad1SAndroid Build Coastguard Worker      enum_aconfig_flags: A dictionary of value->aconfig flag name strings
1206*b9df5ad1SAndroid Build Coastguard Worker
1207*b9df5ad1SAndroid Build Coastguard Worker    Args (if the 'deprecated' attribute is true):
1208*b9df5ad1SAndroid Build Coastguard Worker      deprecation_description: A string explaining the deprecation, to be added
1209*b9df5ad1SAndroid Build Coastguard Worker                               to the Java-layer @deprecated tag
1210*b9df5ad1SAndroid Build Coastguard Worker
1211*b9df5ad1SAndroid Build Coastguard Worker    Args (optional):
1212*b9df5ad1SAndroid Build Coastguard Worker      description: A string with a description of the entry.
1213*b9df5ad1SAndroid Build Coastguard Worker      range: A string with the range of the values of the entry, e.g. '>= 0'
1214*b9df5ad1SAndroid Build Coastguard Worker      units: A string with the units of the values, e.g. 'inches'
1215*b9df5ad1SAndroid Build Coastguard Worker      details: A string with the detailed documentation for the entry
1216*b9df5ad1SAndroid Build Coastguard Worker      hal_details: A string with the HAL implementation details for the entry
1217*b9df5ad1SAndroid Build Coastguard Worker      ndk_details: A string with the extra NDK API documentation for the entry=
1218*b9df5ad1SAndroid Build Coastguard Worker      tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1219*b9df5ad1SAndroid Build Coastguard Worker      type_notes: A string with the notes for the type
1220*b9df5ad1SAndroid Build Coastguard Worker      visibility: A string describing the visibility, eg 'system', 'hidden',
1221*b9df5ad1SAndroid Build Coastguard Worker                  'public'
1222*b9df5ad1SAndroid Build Coastguard Worker      synthetic: A bool to mark whether this entry is visible only at the Java
1223*b9df5ad1SAndroid Build Coastguard Worker                 layer (True), or at both layers (False = default).
1224*b9df5ad1SAndroid Build Coastguard Worker      hwlevel: A string of the HW level (one of 'legacy', 'limited', 'full')
1225*b9df5ad1SAndroid Build Coastguard Worker      deprecated: A bool to mark whether this is @Deprecated at the Java layer
1226*b9df5ad1SAndroid Build Coastguard Worker                 (default = False).
1227*b9df5ad1SAndroid Build Coastguard Worker      optional: A bool to mark whether optional for non-full hardware devices
1228*b9df5ad1SAndroid Build Coastguard Worker      typedef: A string corresponding to a typedef's name attribute.
1229*b9df5ad1SAndroid Build Coastguard Worker    """
1230*b9df5ad1SAndroid Build Coastguard Worker
1231*b9df5ad1SAndroid Build Coastguard Worker    if kwargs.get('type') is None:
1232*b9df5ad1SAndroid Build Coastguard Worker      print("ERROR: Missing type for entry '%s' kind '%s'"
1233*b9df5ad1SAndroid Build Coastguard Worker            % (kwargs.get('name'), kwargs.get('kind')), file=sys.stderr)
1234*b9df5ad1SAndroid Build Coastguard Worker
1235*b9df5ad1SAndroid Build Coastguard Worker    # Attributes are Read-Only, but edges may be mutated by
1236*b9df5ad1SAndroid Build Coastguard Worker    # Metadata, particularly during construct_graph
1237*b9df5ad1SAndroid Build Coastguard Worker
1238*b9df5ad1SAndroid Build Coastguard Worker    self._name = kwargs['name']
1239*b9df5ad1SAndroid Build Coastguard Worker    self._type = kwargs['type']
1240*b9df5ad1SAndroid Build Coastguard Worker    self._kind = kwargs['kind'] # static, dynamic, or controls
1241*b9df5ad1SAndroid Build Coastguard Worker
1242*b9df5ad1SAndroid Build Coastguard Worker    self._init_common(**kwargs)
1243*b9df5ad1SAndroid Build Coastguard Worker
1244*b9df5ad1SAndroid Build Coastguard Worker  @property
1245*b9df5ad1SAndroid Build Coastguard Worker  def type(self):
1246*b9df5ad1SAndroid Build Coastguard Worker    return self._type
1247*b9df5ad1SAndroid Build Coastguard Worker
1248*b9df5ad1SAndroid Build Coastguard Worker  @property
1249*b9df5ad1SAndroid Build Coastguard Worker  def kind(self):
1250*b9df5ad1SAndroid Build Coastguard Worker    return self._kind
1251*b9df5ad1SAndroid Build Coastguard Worker
1252*b9df5ad1SAndroid Build Coastguard Worker  @property
1253*b9df5ad1SAndroid Build Coastguard Worker  def hal_major_version(self):
1254*b9df5ad1SAndroid Build Coastguard Worker    return self._hal_major_version
1255*b9df5ad1SAndroid Build Coastguard Worker
1256*b9df5ad1SAndroid Build Coastguard Worker  @property
1257*b9df5ad1SAndroid Build Coastguard Worker  def hal_minor_version(self):
1258*b9df5ad1SAndroid Build Coastguard Worker    return self._hal_minor_version
1259*b9df5ad1SAndroid Build Coastguard Worker
1260*b9df5ad1SAndroid Build Coastguard Worker  @property
1261*b9df5ad1SAndroid Build Coastguard Worker  def visibility(self):
1262*b9df5ad1SAndroid Build Coastguard Worker    return self._visibility
1263*b9df5ad1SAndroid Build Coastguard Worker
1264*b9df5ad1SAndroid Build Coastguard Worker  @property
1265*b9df5ad1SAndroid Build Coastguard Worker  def applied_visibility(self):
1266*b9df5ad1SAndroid Build Coastguard Worker    return self._visibility or 'system'
1267*b9df5ad1SAndroid Build Coastguard Worker
1268*b9df5ad1SAndroid Build Coastguard Worker  @property
1269*b9df5ad1SAndroid Build Coastguard Worker  def hidl_comment_string(self):
1270*b9df5ad1SAndroid Build Coastguard Worker    if self._visibility in ('fwk_only', 'fwk_java_public', 'fwk_public', 'fwk_ndk_public'):
1271*b9df5ad1SAndroid Build Coastguard Worker      return self._visibility
1272*b9df5ad1SAndroid Build Coastguard Worker    visibility_lj = str(self.applied_visibility).ljust(12)
1273*b9df5ad1SAndroid Build Coastguard Worker    return visibility_lj + ' | HIDL v' + str(self._hal_major_version) + '.' + str(self._hal_minor_version)
1274*b9df5ad1SAndroid Build Coastguard Worker
1275*b9df5ad1SAndroid Build Coastguard Worker  @property
1276*b9df5ad1SAndroid Build Coastguard Worker  def applied_ndk_visible(self):
1277*b9df5ad1SAndroid Build Coastguard Worker    if self._visibility in ("public", "ndk_public", "fwk_public", "fwk_ndk_public"):
1278*b9df5ad1SAndroid Build Coastguard Worker      return "true"
1279*b9df5ad1SAndroid Build Coastguard Worker    return "false"
1280*b9df5ad1SAndroid Build Coastguard Worker
1281*b9df5ad1SAndroid Build Coastguard Worker  @property
1282*b9df5ad1SAndroid Build Coastguard Worker  def synthetic(self):
1283*b9df5ad1SAndroid Build Coastguard Worker    return self._synthetic
1284*b9df5ad1SAndroid Build Coastguard Worker
1285*b9df5ad1SAndroid Build Coastguard Worker  @property
1286*b9df5ad1SAndroid Build Coastguard Worker  def hwlevel(self):
1287*b9df5ad1SAndroid Build Coastguard Worker    return self._hwlevel
1288*b9df5ad1SAndroid Build Coastguard Worker
1289*b9df5ad1SAndroid Build Coastguard Worker  @property
1290*b9df5ad1SAndroid Build Coastguard Worker  def deprecated(self):
1291*b9df5ad1SAndroid Build Coastguard Worker    return self._deprecated
1292*b9df5ad1SAndroid Build Coastguard Worker
1293*b9df5ad1SAndroid Build Coastguard Worker  @property
1294*b9df5ad1SAndroid Build Coastguard Worker  def deprecation_description(self):
1295*b9df5ad1SAndroid Build Coastguard Worker    return self._deprecation_description
1296*b9df5ad1SAndroid Build Coastguard Worker
1297*b9df5ad1SAndroid Build Coastguard Worker  @property
1298*b9df5ad1SAndroid Build Coastguard Worker  def permission_needed(self):
1299*b9df5ad1SAndroid Build Coastguard Worker    return self._permission_needed or "false"
1300*b9df5ad1SAndroid Build Coastguard Worker
1301*b9df5ad1SAndroid Build Coastguard Worker  @property
1302*b9df5ad1SAndroid Build Coastguard Worker  def aconfig_flag(self):
1303*b9df5ad1SAndroid Build Coastguard Worker    return self._aconfig_flag
1304*b9df5ad1SAndroid Build Coastguard Worker
1305*b9df5ad1SAndroid Build Coastguard Worker  # TODO: optional should just return hwlevel is None
1306*b9df5ad1SAndroid Build Coastguard Worker  @property
1307*b9df5ad1SAndroid Build Coastguard Worker  def optional(self):
1308*b9df5ad1SAndroid Build Coastguard Worker    return self._optional
1309*b9df5ad1SAndroid Build Coastguard Worker
1310*b9df5ad1SAndroid Build Coastguard Worker  @property
1311*b9df5ad1SAndroid Build Coastguard Worker  def applied_optional(self):
1312*b9df5ad1SAndroid Build Coastguard Worker    return self._optional or False
1313*b9df5ad1SAndroid Build Coastguard Worker
1314*b9df5ad1SAndroid Build Coastguard Worker  @property
1315*b9df5ad1SAndroid Build Coastguard Worker  def name_short(self):
1316*b9df5ad1SAndroid Build Coastguard Worker    return self.get_name_minimal()
1317*b9df5ad1SAndroid Build Coastguard Worker
1318*b9df5ad1SAndroid Build Coastguard Worker  @property
1319*b9df5ad1SAndroid Build Coastguard Worker  def container(self):
1320*b9df5ad1SAndroid Build Coastguard Worker    return self._container
1321*b9df5ad1SAndroid Build Coastguard Worker
1322*b9df5ad1SAndroid Build Coastguard Worker  @property
1323*b9df5ad1SAndroid Build Coastguard Worker  def container_sizes(self):
1324*b9df5ad1SAndroid Build Coastguard Worker    if self._container_sizes is None:
1325*b9df5ad1SAndroid Build Coastguard Worker      return None
1326*b9df5ad1SAndroid Build Coastguard Worker    else:
1327*b9df5ad1SAndroid Build Coastguard Worker      return (i for i in self._container_sizes)
1328*b9df5ad1SAndroid Build Coastguard Worker
1329*b9df5ad1SAndroid Build Coastguard Worker  @property
1330*b9df5ad1SAndroid Build Coastguard Worker  def tuple_values(self):
1331*b9df5ad1SAndroid Build Coastguard Worker    if self._tuple_values is None:
1332*b9df5ad1SAndroid Build Coastguard Worker      return None
1333*b9df5ad1SAndroid Build Coastguard Worker    else:
1334*b9df5ad1SAndroid Build Coastguard Worker      return (i for i in self._tuple_values)
1335*b9df5ad1SAndroid Build Coastguard Worker
1336*b9df5ad1SAndroid Build Coastguard Worker  @property
1337*b9df5ad1SAndroid Build Coastguard Worker  def description(self):
1338*b9df5ad1SAndroid Build Coastguard Worker    return self._description
1339*b9df5ad1SAndroid Build Coastguard Worker
1340*b9df5ad1SAndroid Build Coastguard Worker  @property
1341*b9df5ad1SAndroid Build Coastguard Worker  def range(self):
1342*b9df5ad1SAndroid Build Coastguard Worker    return self._range
1343*b9df5ad1SAndroid Build Coastguard Worker
1344*b9df5ad1SAndroid Build Coastguard Worker  @property
1345*b9df5ad1SAndroid Build Coastguard Worker  def units(self):
1346*b9df5ad1SAndroid Build Coastguard Worker    return self._units
1347*b9df5ad1SAndroid Build Coastguard Worker
1348*b9df5ad1SAndroid Build Coastguard Worker  @property
1349*b9df5ad1SAndroid Build Coastguard Worker  def details(self):
1350*b9df5ad1SAndroid Build Coastguard Worker    return self._details
1351*b9df5ad1SAndroid Build Coastguard Worker
1352*b9df5ad1SAndroid Build Coastguard Worker  @property
1353*b9df5ad1SAndroid Build Coastguard Worker  def hal_details(self):
1354*b9df5ad1SAndroid Build Coastguard Worker    return self._hal_details
1355*b9df5ad1SAndroid Build Coastguard Worker
1356*b9df5ad1SAndroid Build Coastguard Worker  @property
1357*b9df5ad1SAndroid Build Coastguard Worker  def ndk_details(self):
1358*b9df5ad1SAndroid Build Coastguard Worker    return self._ndk_details
1359*b9df5ad1SAndroid Build Coastguard Worker
1360*b9df5ad1SAndroid Build Coastguard Worker  @property
1361*b9df5ad1SAndroid Build Coastguard Worker  def applied_ndk_details(self):
1362*b9df5ad1SAndroid Build Coastguard Worker    return (self._details or "") + (self._ndk_details or "")
1363*b9df5ad1SAndroid Build Coastguard Worker
1364*b9df5ad1SAndroid Build Coastguard Worker  @property
1365*b9df5ad1SAndroid Build Coastguard Worker  def tags(self):
1366*b9df5ad1SAndroid Build Coastguard Worker    if self._tags is None:
1367*b9df5ad1SAndroid Build Coastguard Worker      return None
1368*b9df5ad1SAndroid Build Coastguard Worker    else:
1369*b9df5ad1SAndroid Build Coastguard Worker      return (i for i in self._tags)
1370*b9df5ad1SAndroid Build Coastguard Worker
1371*b9df5ad1SAndroid Build Coastguard Worker  @property
1372*b9df5ad1SAndroid Build Coastguard Worker  def type_notes(self):
1373*b9df5ad1SAndroid Build Coastguard Worker    return self._type_notes
1374*b9df5ad1SAndroid Build Coastguard Worker
1375*b9df5ad1SAndroid Build Coastguard Worker  @property
1376*b9df5ad1SAndroid Build Coastguard Worker  def typedef(self):
1377*b9df5ad1SAndroid Build Coastguard Worker    return self._typedef
1378*b9df5ad1SAndroid Build Coastguard Worker
1379*b9df5ad1SAndroid Build Coastguard Worker  @property
1380*b9df5ad1SAndroid Build Coastguard Worker  def enum(self):
1381*b9df5ad1SAndroid Build Coastguard Worker    return self._enum
1382*b9df5ad1SAndroid Build Coastguard Worker
1383*b9df5ad1SAndroid Build Coastguard Worker  @property
1384*b9df5ad1SAndroid Build Coastguard Worker  def session_characteristics_key_since(self):
1385*b9df5ad1SAndroid Build Coastguard Worker    return self._session_characteristics_key_since
1386*b9df5ad1SAndroid Build Coastguard Worker
1387*b9df5ad1SAndroid Build Coastguard Worker  def has_new_values_added_in_hal_version(self, hal_major_version, hal_minor_version):
1388*b9df5ad1SAndroid Build Coastguard Worker    if self._enum is not None:
1389*b9df5ad1SAndroid Build Coastguard Worker      return self._enum.has_new_values_added_in_hal_version(hal_major_version,hal_minor_version)
1390*b9df5ad1SAndroid Build Coastguard Worker    else:
1391*b9df5ad1SAndroid Build Coastguard Worker      return False
1392*b9df5ad1SAndroid Build Coastguard Worker
1393*b9df5ad1SAndroid Build Coastguard Worker  def _get_children(self):
1394*b9df5ad1SAndroid Build Coastguard Worker    if self.enum:
1395*b9df5ad1SAndroid Build Coastguard Worker      yield self.enum
1396*b9df5ad1SAndroid Build Coastguard Worker
1397*b9df5ad1SAndroid Build Coastguard Worker  def sort_children(self):
1398*b9df5ad1SAndroid Build Coastguard Worker    return None
1399*b9df5ad1SAndroid Build Coastguard Worker
1400*b9df5ad1SAndroid Build Coastguard Worker  def is_clone(self):
1401*b9df5ad1SAndroid Build Coastguard Worker    """
1402*b9df5ad1SAndroid Build Coastguard Worker    Whether or not this is a Clone instance.
1403*b9df5ad1SAndroid Build Coastguard Worker
1404*b9df5ad1SAndroid Build Coastguard Worker    Returns:
1405*b9df5ad1SAndroid Build Coastguard Worker      False
1406*b9df5ad1SAndroid Build Coastguard Worker    """
1407*b9df5ad1SAndroid Build Coastguard Worker    return False
1408*b9df5ad1SAndroid Build Coastguard Worker
1409*b9df5ad1SAndroid Build Coastguard Worker  def _init_common(self, **kwargs):
1410*b9df5ad1SAndroid Build Coastguard Worker
1411*b9df5ad1SAndroid Build Coastguard Worker    self._parent = None # filled in by Metadata::_construct_entries
1412*b9df5ad1SAndroid Build Coastguard Worker
1413*b9df5ad1SAndroid Build Coastguard Worker    self._container = kwargs.get('container')
1414*b9df5ad1SAndroid Build Coastguard Worker    self._container_sizes = kwargs.get('container_sizes')
1415*b9df5ad1SAndroid Build Coastguard Worker
1416*b9df5ad1SAndroid Build Coastguard Worker    hal_version = kwargs.get('hal_version')
1417*b9df5ad1SAndroid Build Coastguard Worker    if hal_version is None:
1418*b9df5ad1SAndroid Build Coastguard Worker      if self.is_clone():
1419*b9df5ad1SAndroid Build Coastguard Worker        self._hal_major_version = 0
1420*b9df5ad1SAndroid Build Coastguard Worker        self._hal_minor_version = 0
1421*b9df5ad1SAndroid Build Coastguard Worker      else:
1422*b9df5ad1SAndroid Build Coastguard Worker        self._hal_major_version = 3
1423*b9df5ad1SAndroid Build Coastguard Worker        self._hal_minor_version = 2
1424*b9df5ad1SAndroid Build Coastguard Worker    else:
1425*b9df5ad1SAndroid Build Coastguard Worker      self._hal_major_version = int(hal_version.partition('.')[0])
1426*b9df5ad1SAndroid Build Coastguard Worker      self._hal_minor_version = int(hal_version.partition('.')[2])
1427*b9df5ad1SAndroid Build Coastguard Worker
1428*b9df5ad1SAndroid Build Coastguard Worker    self._aconfig_flag = kwargs.get('aconfig_flag')
1429*b9df5ad1SAndroid Build Coastguard Worker
1430*b9df5ad1SAndroid Build Coastguard Worker    # access these via the 'enum' prop
1431*b9df5ad1SAndroid Build Coastguard Worker    enum_values = kwargs.get('enum_values')
1432*b9df5ad1SAndroid Build Coastguard Worker    enum_deprecateds = kwargs.get('enum_deprecateds')
1433*b9df5ad1SAndroid Build Coastguard Worker    enum_optionals = kwargs.get('enum_optionals')
1434*b9df5ad1SAndroid Build Coastguard Worker    enum_visibilities = kwargs.get('enum_visibilities')
1435*b9df5ad1SAndroid Build Coastguard Worker    enum_notes = kwargs.get('enum_notes')  # { value => notes }
1436*b9df5ad1SAndroid Build Coastguard Worker    enum_sdk_notes = kwargs.get('enum_sdk_notes')  # { value => sdk_notes }
1437*b9df5ad1SAndroid Build Coastguard Worker    enum_ndk_notes = kwargs.get('enum_ndk_notes')  # { value => ndk_notes }
1438*b9df5ad1SAndroid Build Coastguard Worker    enum_ids = kwargs.get('enum_ids')  # { value => notes }
1439*b9df5ad1SAndroid Build Coastguard Worker    enum_hal_versions = kwargs.get('enum_hal_versions') # { value => hal_versions }
1440*b9df5ad1SAndroid Build Coastguard Worker    enum_aconfig_flags = kwargs.get('enum_aconfig_flags') # { value => aconfig flags }
1441*b9df5ad1SAndroid Build Coastguard Worker
1442*b9df5ad1SAndroid Build Coastguard Worker    self._tuple_values = kwargs.get('tuple_values')
1443*b9df5ad1SAndroid Build Coastguard Worker
1444*b9df5ad1SAndroid Build Coastguard Worker    self._description = kwargs.get('description')
1445*b9df5ad1SAndroid Build Coastguard Worker    self._range = kwargs.get('range')
1446*b9df5ad1SAndroid Build Coastguard Worker    self._units = kwargs.get('units')
1447*b9df5ad1SAndroid Build Coastguard Worker    self._details = kwargs.get('details')
1448*b9df5ad1SAndroid Build Coastguard Worker    self._hal_details = kwargs.get('hal_details')
1449*b9df5ad1SAndroid Build Coastguard Worker    self._ndk_details = kwargs.get('ndk_details')
1450*b9df5ad1SAndroid Build Coastguard Worker
1451*b9df5ad1SAndroid Build Coastguard Worker    self._tag_ids = kwargs.get('tag_ids', [])
1452*b9df5ad1SAndroid Build Coastguard Worker    self._tags = None  # Filled in by Metadata::_construct_tags
1453*b9df5ad1SAndroid Build Coastguard Worker
1454*b9df5ad1SAndroid Build Coastguard Worker    self._type_notes = kwargs.get('type_notes')
1455*b9df5ad1SAndroid Build Coastguard Worker    self._type_name = kwargs.get('type_name')
1456*b9df5ad1SAndroid Build Coastguard Worker    self._typedef = None # Filled in by Metadata::_construct_types
1457*b9df5ad1SAndroid Build Coastguard Worker
1458*b9df5ad1SAndroid Build Coastguard Worker    if kwargs.get('enum', False):
1459*b9df5ad1SAndroid Build Coastguard Worker      self._enum = Enum(self, enum_values, enum_ids, enum_deprecateds, enum_optionals,
1460*b9df5ad1SAndroid Build Coastguard Worker                        enum_visibilities, enum_notes, enum_sdk_notes, enum_ndk_notes,
1461*b9df5ad1SAndroid Build Coastguard Worker                        enum_hal_versions, enum_aconfig_flags)
1462*b9df5ad1SAndroid Build Coastguard Worker    else:
1463*b9df5ad1SAndroid Build Coastguard Worker      self._enum = None
1464*b9df5ad1SAndroid Build Coastguard Worker
1465*b9df5ad1SAndroid Build Coastguard Worker    self._visibility = kwargs.get('visibility')
1466*b9df5ad1SAndroid Build Coastguard Worker    self._synthetic = kwargs.get('synthetic', False)
1467*b9df5ad1SAndroid Build Coastguard Worker    self._hwlevel = kwargs.get('hwlevel')
1468*b9df5ad1SAndroid Build Coastguard Worker    self._deprecated = kwargs.get('deprecated', False)
1469*b9df5ad1SAndroid Build Coastguard Worker    self._deprecation_description = kwargs.get('deprecation_description')
1470*b9df5ad1SAndroid Build Coastguard Worker
1471*b9df5ad1SAndroid Build Coastguard Worker    self._permission_needed = kwargs.get('permission_needed')
1472*b9df5ad1SAndroid Build Coastguard Worker    self._optional = kwargs.get('optional')
1473*b9df5ad1SAndroid Build Coastguard Worker    self._ndk_visible = kwargs.get('ndk_visible')
1474*b9df5ad1SAndroid Build Coastguard Worker
1475*b9df5ad1SAndroid Build Coastguard Worker    self._session_characteristics_key_since = None \
1476*b9df5ad1SAndroid Build Coastguard Worker                  if not kwargs.get('session_characteristics_key_since') \
1477*b9df5ad1SAndroid Build Coastguard Worker                    else int(kwargs.get('session_characteristics_key_since'))
1478*b9df5ad1SAndroid Build Coastguard Worker
1479*b9df5ad1SAndroid Build Coastguard Worker    self._property_keys = kwargs
1480*b9df5ad1SAndroid Build Coastguard Worker
1481*b9df5ad1SAndroid Build Coastguard Worker  def merge(self):
1482*b9df5ad1SAndroid Build Coastguard Worker    """
1483*b9df5ad1SAndroid Build Coastguard Worker    Copy the attributes into a new entry, merging it with the target entry
1484*b9df5ad1SAndroid Build Coastguard Worker    if it's a clone.
1485*b9df5ad1SAndroid Build Coastguard Worker    """
1486*b9df5ad1SAndroid Build Coastguard Worker    return MergedEntry(self)
1487*b9df5ad1SAndroid Build Coastguard Worker
1488*b9df5ad1SAndroid Build Coastguard Worker  # Helpers for accessing less than the fully qualified name
1489*b9df5ad1SAndroid Build Coastguard Worker
1490*b9df5ad1SAndroid Build Coastguard Worker  def get_name_as_list(self):
1491*b9df5ad1SAndroid Build Coastguard Worker    """
1492*b9df5ad1SAndroid Build Coastguard Worker    Returns the name as a list split by a period.
1493*b9df5ad1SAndroid Build Coastguard Worker
1494*b9df5ad1SAndroid Build Coastguard Worker    For example:
1495*b9df5ad1SAndroid Build Coastguard Worker      entry.name is 'android.lens.info.shading'
1496*b9df5ad1SAndroid Build Coastguard Worker      entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
1497*b9df5ad1SAndroid Build Coastguard Worker    """
1498*b9df5ad1SAndroid Build Coastguard Worker    return self.name.split(".")
1499*b9df5ad1SAndroid Build Coastguard Worker
1500*b9df5ad1SAndroid Build Coastguard Worker  def get_inner_namespace_list(self):
1501*b9df5ad1SAndroid Build Coastguard Worker    """
1502*b9df5ad1SAndroid Build Coastguard Worker    Returns the inner namespace part of the name as a list
1503*b9df5ad1SAndroid Build Coastguard Worker
1504*b9df5ad1SAndroid Build Coastguard Worker    For example:
1505*b9df5ad1SAndroid Build Coastguard Worker      entry.name is 'android.lens.info.shading'
1506*b9df5ad1SAndroid Build Coastguard Worker      entry.get_inner_namespace_list() == ['info']
1507*b9df5ad1SAndroid Build Coastguard Worker    """
1508*b9df5ad1SAndroid Build Coastguard Worker    return self.get_name_as_list()[2:-1]
1509*b9df5ad1SAndroid Build Coastguard Worker
1510*b9df5ad1SAndroid Build Coastguard Worker  def get_outer_namespace(self):
1511*b9df5ad1SAndroid Build Coastguard Worker    """
1512*b9df5ad1SAndroid Build Coastguard Worker    Returns the outer namespace as a string.
1513*b9df5ad1SAndroid Build Coastguard Worker
1514*b9df5ad1SAndroid Build Coastguard Worker    For example:
1515*b9df5ad1SAndroid Build Coastguard Worker      entry.name is 'android.lens.info.shading'
1516*b9df5ad1SAndroid Build Coastguard Worker      entry.get_outer_namespace() == 'android'
1517*b9df5ad1SAndroid Build Coastguard Worker
1518*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
1519*b9df5ad1SAndroid Build Coastguard Worker      Since outer namespaces are non-recursive,
1520*b9df5ad1SAndroid Build Coastguard Worker      and each entry has one, this does not need to be a list.
1521*b9df5ad1SAndroid Build Coastguard Worker    """
1522*b9df5ad1SAndroid Build Coastguard Worker    return self.get_name_as_list()[0]
1523*b9df5ad1SAndroid Build Coastguard Worker
1524*b9df5ad1SAndroid Build Coastguard Worker  def get_section(self):
1525*b9df5ad1SAndroid Build Coastguard Worker    """
1526*b9df5ad1SAndroid Build Coastguard Worker    Returns the section as a string.
1527*b9df5ad1SAndroid Build Coastguard Worker
1528*b9df5ad1SAndroid Build Coastguard Worker    For example:
1529*b9df5ad1SAndroid Build Coastguard Worker      entry.name is 'android.lens.info.shading'
1530*b9df5ad1SAndroid Build Coastguard Worker      entry.get_section() == ''
1531*b9df5ad1SAndroid Build Coastguard Worker
1532*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
1533*b9df5ad1SAndroid Build Coastguard Worker      Since outer namespaces are non-recursive,
1534*b9df5ad1SAndroid Build Coastguard Worker      and each entry has one, this does not need to be a list.
1535*b9df5ad1SAndroid Build Coastguard Worker    """
1536*b9df5ad1SAndroid Build Coastguard Worker    return self.get_name_as_list()[1]
1537*b9df5ad1SAndroid Build Coastguard Worker
1538*b9df5ad1SAndroid Build Coastguard Worker  def get_name_minimal(self):
1539*b9df5ad1SAndroid Build Coastguard Worker    """
1540*b9df5ad1SAndroid Build Coastguard Worker    Returns only the last component of the fully qualified name as a string.
1541*b9df5ad1SAndroid Build Coastguard Worker
1542*b9df5ad1SAndroid Build Coastguard Worker    For example:
1543*b9df5ad1SAndroid Build Coastguard Worker      entry.name is 'android.lens.info.shading'
1544*b9df5ad1SAndroid Build Coastguard Worker      entry.get_name_minimal() == 'shading'
1545*b9df5ad1SAndroid Build Coastguard Worker
1546*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
1547*b9df5ad1SAndroid Build Coastguard Worker      entry.name_short it an alias for this
1548*b9df5ad1SAndroid Build Coastguard Worker    """
1549*b9df5ad1SAndroid Build Coastguard Worker    return self.get_name_as_list()[-1]
1550*b9df5ad1SAndroid Build Coastguard Worker
1551*b9df5ad1SAndroid Build Coastguard Worker  def get_path_without_name(self):
1552*b9df5ad1SAndroid Build Coastguard Worker    """
1553*b9df5ad1SAndroid Build Coastguard Worker    Returns a string path to the entry, with the name component excluded.
1554*b9df5ad1SAndroid Build Coastguard Worker
1555*b9df5ad1SAndroid Build Coastguard Worker    For example:
1556*b9df5ad1SAndroid Build Coastguard Worker      entry.name is 'android.lens.info.shading'
1557*b9df5ad1SAndroid Build Coastguard Worker      entry.get_path_without_name() == 'android.lens.info'
1558*b9df5ad1SAndroid Build Coastguard Worker    """
1559*b9df5ad1SAndroid Build Coastguard Worker    return ".".join(self.get_name_as_list()[0:-1])
1560*b9df5ad1SAndroid Build Coastguard Worker
1561*b9df5ad1SAndroid Build Coastguard Worker
1562*b9df5ad1SAndroid Build Coastguard Workerclass Clone(Entry):
1563*b9df5ad1SAndroid Build Coastguard Worker  """
1564*b9df5ad1SAndroid Build Coastguard Worker  A Node corresponding to a <clone> element. It has all the attributes of an
1565*b9df5ad1SAndroid Build Coastguard Worker  <entry> element (Entry) plus the additions specified below.
1566*b9df5ad1SAndroid Build Coastguard Worker
1567*b9df5ad1SAndroid Build Coastguard Worker  Attributes (Read-Only):
1568*b9df5ad1SAndroid Build Coastguard Worker    entry: an edge to an Entry object that this targets
1569*b9df5ad1SAndroid Build Coastguard Worker    target_kind: A string describing the kind of the target entry.
1570*b9df5ad1SAndroid Build Coastguard Worker    name: a string of the name, same as entry.name
1571*b9df5ad1SAndroid Build Coastguard Worker    kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
1572*b9df5ad1SAndroid Build Coastguard Worker          for the <clone> element.
1573*b9df5ad1SAndroid Build Coastguard Worker    type: always None, since a clone cannot override the type.
1574*b9df5ad1SAndroid Build Coastguard Worker  """
1575*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, entry=None, **kwargs):
1576*b9df5ad1SAndroid Build Coastguard Worker    """
1577*b9df5ad1SAndroid Build Coastguard Worker    Instantiate a new Clone node.
1578*b9df5ad1SAndroid Build Coastguard Worker
1579*b9df5ad1SAndroid Build Coastguard Worker    Args:
1580*b9df5ad1SAndroid Build Coastguard Worker      name: A string with the fully qualified name, e.g. 'android.shading.mode'
1581*b9df5ad1SAndroid Build Coastguard Worker      type: A string describing the type, e.g. 'int32'
1582*b9df5ad1SAndroid Build Coastguard Worker      kind: A string describing the kind, e.g. 'static'
1583*b9df5ad1SAndroid Build Coastguard Worker      target_kind: A string for the kind of the target entry, e.g. 'dynamic'
1584*b9df5ad1SAndroid Build Coastguard Worker      hal_version: A string for the initial HIDL HAL metadata version this entry
1585*b9df5ad1SAndroid Build Coastguard Worker                   was added in
1586*b9df5ad1SAndroid Build Coastguard Worker
1587*b9df5ad1SAndroid Build Coastguard Worker    Args (if container):
1588*b9df5ad1SAndroid Build Coastguard Worker      container: A string describing the container, e.g. 'array' or 'tuple'
1589*b9df5ad1SAndroid Build Coastguard Worker      container_sizes: A list of string sizes if a container, or None otherwise
1590*b9df5ad1SAndroid Build Coastguard Worker
1591*b9df5ad1SAndroid Build Coastguard Worker    Args (if container is 'tuple'):
1592*b9df5ad1SAndroid Build Coastguard Worker      tuple_values: A list of tuple values, e.g. ['width', 'height']
1593*b9df5ad1SAndroid Build Coastguard Worker
1594*b9df5ad1SAndroid Build Coastguard Worker    Args (if the 'enum' attribute is true):
1595*b9df5ad1SAndroid Build Coastguard Worker      enum: A boolean, True if this is an enum, False otherwise
1596*b9df5ad1SAndroid Build Coastguard Worker      enum_values: A list of value strings, e.g. ['ON', 'OFF']
1597*b9df5ad1SAndroid Build Coastguard Worker      enum_optionals: A list of optional enum values, e.g. ['OFF']
1598*b9df5ad1SAndroid Build Coastguard Worker      enum_notes: A dictionary of value->notes strings.
1599*b9df5ad1SAndroid Build Coastguard Worker      enum_ids: A dictionary of value->id strings.
1600*b9df5ad1SAndroid Build Coastguard Worker
1601*b9df5ad1SAndroid Build Coastguard Worker    Args (optional):
1602*b9df5ad1SAndroid Build Coastguard Worker      entry: An edge to the corresponding target Entry.
1603*b9df5ad1SAndroid Build Coastguard Worker      description: A string with a description of the entry.
1604*b9df5ad1SAndroid Build Coastguard Worker      range: A string with the range of the values of the entry, e.g. '>= 0'
1605*b9df5ad1SAndroid Build Coastguard Worker      units: A string with the units of the values, e.g. 'inches'
1606*b9df5ad1SAndroid Build Coastguard Worker      details: A string with the detailed documentation for the entry
1607*b9df5ad1SAndroid Build Coastguard Worker      hal_details: A string with the HAL implementation details for the entry
1608*b9df5ad1SAndroid Build Coastguard Worker      ndk_details: A string with the extra NDK documentation for the entry
1609*b9df5ad1SAndroid Build Coastguard Worker      tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
1610*b9df5ad1SAndroid Build Coastguard Worker      type_notes: A string with the notes for the type
1611*b9df5ad1SAndroid Build Coastguard Worker
1612*b9df5ad1SAndroid Build Coastguard Worker    Remarks:
1613*b9df5ad1SAndroid Build Coastguard Worker      Note that type is not specified since it has to be the same as the
1614*b9df5ad1SAndroid Build Coastguard Worker      entry.type.
1615*b9df5ad1SAndroid Build Coastguard Worker    """
1616*b9df5ad1SAndroid Build Coastguard Worker    self._entry = entry  # Entry object
1617*b9df5ad1SAndroid Build Coastguard Worker    self._target_kind = kwargs['target_kind']
1618*b9df5ad1SAndroid Build Coastguard Worker    self._name = kwargs['name']  # same as entry.name
1619*b9df5ad1SAndroid Build Coastguard Worker    self._kind = kwargs['kind']
1620*b9df5ad1SAndroid Build Coastguard Worker
1621*b9df5ad1SAndroid Build Coastguard Worker    # illegal to override the type, it should be the same as the entry
1622*b9df5ad1SAndroid Build Coastguard Worker    self._type = None
1623*b9df5ad1SAndroid Build Coastguard Worker    # the rest of the kwargs are optional
1624*b9df5ad1SAndroid Build Coastguard Worker    # can be used to override the regular entry data
1625*b9df5ad1SAndroid Build Coastguard Worker    self._init_common(**kwargs)
1626*b9df5ad1SAndroid Build Coastguard Worker
1627*b9df5ad1SAndroid Build Coastguard Worker  @property
1628*b9df5ad1SAndroid Build Coastguard Worker  def entry(self):
1629*b9df5ad1SAndroid Build Coastguard Worker    return self._entry
1630*b9df5ad1SAndroid Build Coastguard Worker
1631*b9df5ad1SAndroid Build Coastguard Worker  @property
1632*b9df5ad1SAndroid Build Coastguard Worker  def target_kind(self):
1633*b9df5ad1SAndroid Build Coastguard Worker    return self._target_kind
1634*b9df5ad1SAndroid Build Coastguard Worker
1635*b9df5ad1SAndroid Build Coastguard Worker  def is_clone(self):
1636*b9df5ad1SAndroid Build Coastguard Worker    """
1637*b9df5ad1SAndroid Build Coastguard Worker    Whether or not this is a Clone instance.
1638*b9df5ad1SAndroid Build Coastguard Worker
1639*b9df5ad1SAndroid Build Coastguard Worker    Returns:
1640*b9df5ad1SAndroid Build Coastguard Worker      True
1641*b9df5ad1SAndroid Build Coastguard Worker    """
1642*b9df5ad1SAndroid Build Coastguard Worker    return True
1643*b9df5ad1SAndroid Build Coastguard Worker
1644*b9df5ad1SAndroid Build Coastguard Workerclass MergedEntry(Entry):
1645*b9df5ad1SAndroid Build Coastguard Worker  """
1646*b9df5ad1SAndroid Build Coastguard Worker  A MergedEntry has all the attributes of a Clone and its target Entry merged
1647*b9df5ad1SAndroid Build Coastguard Worker  together.
1648*b9df5ad1SAndroid Build Coastguard Worker
1649*b9df5ad1SAndroid Build Coastguard Worker  Remarks:
1650*b9df5ad1SAndroid Build Coastguard Worker    Useful when we want to 'unfold' a clone into a real entry by copying out
1651*b9df5ad1SAndroid Build Coastguard Worker    the target entry data. In this case we don't care about distinguishing
1652*b9df5ad1SAndroid Build Coastguard Worker    a clone vs an entry.
1653*b9df5ad1SAndroid Build Coastguard Worker  """
1654*b9df5ad1SAndroid Build Coastguard Worker  def __init__(self, entry):
1655*b9df5ad1SAndroid Build Coastguard Worker    """
1656*b9df5ad1SAndroid Build Coastguard Worker    Create a new instance of MergedEntry.
1657*b9df5ad1SAndroid Build Coastguard Worker
1658*b9df5ad1SAndroid Build Coastguard Worker    Args:
1659*b9df5ad1SAndroid Build Coastguard Worker      entry: An Entry or Clone instance
1660*b9df5ad1SAndroid Build Coastguard Worker    """
1661*b9df5ad1SAndroid Build Coastguard Worker    props_distinct = ['description', 'units', 'range', 'details',
1662*b9df5ad1SAndroid Build Coastguard Worker                      'hal_details', 'ndk_details', 'tags', 'kind',
1663*b9df5ad1SAndroid Build Coastguard Worker                      'deprecation_description']
1664*b9df5ad1SAndroid Build Coastguard Worker
1665*b9df5ad1SAndroid Build Coastguard Worker    for p in props_distinct:
1666*b9df5ad1SAndroid Build Coastguard Worker      p = '_' + p
1667*b9df5ad1SAndroid Build Coastguard Worker      if entry.is_clone():
1668*b9df5ad1SAndroid Build Coastguard Worker        setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1669*b9df5ad1SAndroid Build Coastguard Worker      else:
1670*b9df5ad1SAndroid Build Coastguard Worker        setattr(self, p, getattr(entry, p))
1671*b9df5ad1SAndroid Build Coastguard Worker
1672*b9df5ad1SAndroid Build Coastguard Worker    props_common = ['parent', 'name', 'container',
1673*b9df5ad1SAndroid Build Coastguard Worker                    'container_sizes', 'enum',
1674*b9df5ad1SAndroid Build Coastguard Worker                    'tuple_values',
1675*b9df5ad1SAndroid Build Coastguard Worker                    'type',
1676*b9df5ad1SAndroid Build Coastguard Worker                    'type_notes',
1677*b9df5ad1SAndroid Build Coastguard Worker                    'visibility',
1678*b9df5ad1SAndroid Build Coastguard Worker                    'ndk_visible',
1679*b9df5ad1SAndroid Build Coastguard Worker                    'synthetic',
1680*b9df5ad1SAndroid Build Coastguard Worker                    'hwlevel',
1681*b9df5ad1SAndroid Build Coastguard Worker                    'deprecated',
1682*b9df5ad1SAndroid Build Coastguard Worker                    'optional',
1683*b9df5ad1SAndroid Build Coastguard Worker                    'typedef',
1684*b9df5ad1SAndroid Build Coastguard Worker                    'hal_major_version',
1685*b9df5ad1SAndroid Build Coastguard Worker                    'hal_minor_version',
1686*b9df5ad1SAndroid Build Coastguard Worker                    'permission_needed',
1687*b9df5ad1SAndroid Build Coastguard Worker                    'aconfig_flag',
1688*b9df5ad1SAndroid Build Coastguard Worker                    'session_characteristics_key_since'
1689*b9df5ad1SAndroid Build Coastguard Worker                   ]
1690*b9df5ad1SAndroid Build Coastguard Worker
1691*b9df5ad1SAndroid Build Coastguard Worker    for p in props_common:
1692*b9df5ad1SAndroid Build Coastguard Worker      p = '_' + p
1693*b9df5ad1SAndroid Build Coastguard Worker      if entry.is_clone():
1694*b9df5ad1SAndroid Build Coastguard Worker        setattr(self, p, getattr(entry.entry, p))
1695*b9df5ad1SAndroid Build Coastguard Worker      else:
1696*b9df5ad1SAndroid Build Coastguard Worker        setattr(self, p, getattr(entry, p))
1697