blob: bcfa29ef34b82f2653db54ad495e35da02e90d2f [file] [log] [blame]
Igor Murashkinda1c3142012-11-21 17:11:37 -08001#
2# Copyright (C) 2012 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17"""
18A set of helpers for rendering Mako templates with a Metadata model.
19"""
20
21import metadata_model
22
23_context_buf = None
24
25def _is_sec_or_ins(x):
26 return isinstance(x, metadata_model.Section) or \
27 isinstance(x, metadata_model.InnerNamespace)
28
29##
30## Metadata Helpers
31##
32
33def find_all_sections(root):
34 """
35 Find all descendants that are Section or InnerNamespace instances.
36
37 Args:
38 root: a Metadata instance
39
40 Returns:
41 A list of Section/InnerNamespace instances
42
43 Remarks:
44 These are known as "sections" in the generated C code.
45 """
46 return root.find_all(_is_sec_or_ins)
47
48def find_parent_section(entry):
49 """
50 Find the closest ancestor that is either a Section or InnerNamespace.
51
52 Args:
53 entry: an Entry or Clone node
54
55 Returns:
56 An instance of Section or InnerNamespace
57 """
58 return entry.find_parent_first(_is_sec_or_ins)
59
60# find uniquely named entries (w/o recursing through inner namespaces)
61def find_unique_entries(node):
62 """
63 Find all uniquely named entries, without recursing through inner namespaces.
64
65 Args:
66 node: a Section or InnerNamespace instance
67
68 Yields:
69 A sequence of MergedEntry nodes representing an entry
70
71 Remarks:
72 This collapses multiple entries with the same fully qualified name into
73 one entry (e.g. if there are multiple entries in different kinds).
74 """
75 if not isinstance(node, metadata_model.Section) and \
76 not isinstance(node, metadata_model.InnerNamespace):
77 raise TypeError("expected node to be a Section or InnerNamespace")
78
79 d = {}
80 # remove the 'kinds' from the path between sec and the closest entries
81 # then search the immediate children of the search path
82 search_path = isinstance(node, metadata_model.Section) and node.kinds \
83 or [node]
84 for i in search_path:
85 for entry in i.entries:
86 d[entry.name] = entry
87
88 for k,v in d.iteritems():
89 yield v.merge()
90
91def path_name(node):
92 """
93 Calculate a period-separated string path from the root to this element,
94 by joining the names of each node and excluding the Metadata/Kind nodes
95 from the path.
96
97 Args:
98 node: a Node instance
99
100 Returns:
101 A string path
102 """
103
104 isa = lambda x,y: isinstance(x, y)
105 fltr = lambda x: not isa(x, metadata_model.Metadata) and \
106 not isa(x, metadata_model.Kind)
107
108 path = node.find_parents(fltr)
109 path = list(path)
110 path.reverse()
111 path.append(node)
112
113 return ".".join((i.name for i in path))
114
115##
116## Filters
117##
118
119# abcDef.xyz -> ABC_DEF_XYZ
120def csym(name):
121 """
122 Convert an entry name string into an uppercase C symbol.
123
124 Returns:
125 A string
126
127 Example:
128 csym('abcDef.xyz') == 'ABC_DEF_XYZ'
129 """
130 newstr = name
131 newstr = "".join([i.isupper() and ("_" + i) or i for i in newstr]).upper()
132 newstr = newstr.replace(".", "_")
133 return newstr
134
135# abcDef.xyz -> abc_def_xyz
136def csyml(name):
137 """
138 Convert an entry name string into a lowercase C symbol.
139
140 Returns:
141 A string
142
143 Example:
144 csyml('abcDef.xyz') == 'abc_def_xyz'
145 """
146 return csym(name).lower()
147
148# pad with spaces to make string len == size. add new line if too big
149def ljust(size, indent=4):
150 """
151 Creates a function that given a string will pad it with spaces to make
152 the string length == size. Adds a new line if the string was too big.
153
154 Args:
155 size: an integer representing how much spacing should be added
156 indent: an integer representing the initial indendation level
157
158 Returns:
159 A function that takes a string and returns a string.
160
161 Example:
162 ljust(8)("hello") == 'hello '
163
164 Remarks:
165 Deprecated. Use pad instead since it works for non-first items in a
166 Mako template.
167 """
168 def inner(what):
169 newstr = what.ljust(size)
170 if len(newstr) > size:
171 return what + "\n" + "".ljust(indent + size)
172 else:
173 return newstr
174 return inner
175
176def _find_new_line():
177
178 if _context_buf is None:
179 raise ValueError("Context buffer was not set")
180
181 buf = _context_buf
182 x = -1 # since the first read is always ''
183 cur_pos = buf.tell()
184 while buf.tell() > 0 and buf.read(1) != '\n':
185 buf.seek(cur_pos - x)
186 x = x + 1
187
188 buf.seek(cur_pos)
189
190 return int(x)
191
192# Pad the string until the buffer reaches the desired column.
193# If string is too long, insert a new line with 'col' spaces instead
194def pad(col):
195 """
196 Create a function that given a string will pad it to the specified column col.
197 If the string overflows the column, put the string on a new line and pad it.
198
199 Args:
200 col: an integer specifying the column number
201
202 Returns:
203 A function that given a string will produce a padded string.
204
205 Example:
206 pad(8)("hello") == 'hello '
207
208 Remarks:
209 This keeps track of the line written by Mako so far, so it will always
210 align to the column number correctly.
211 """
212 def inner(what):
213 wut = int(col)
214 current_col = _find_new_line()
215
216 if len(what) > wut - current_col:
217 return what + "\n".ljust(col)
218 else:
219 return what.ljust(wut - current_col)
220 return inner
221
222# int32 -> TYPE_INT32, byte -> TYPE_BYTE, etc. note that enum -> TYPE_INT32
223def ctype_enum(what):
224 """
225 Generate a camera_metadata_type_t symbol from a type string.
226
227 Args:
228 what: a type string
229
230 Returns:
231 A string representing the camera_metadata_type_t
232
233 Example:
234 ctype_enum('int32') == 'TYPE_INT32'
235 ctype_enum('int64') == 'TYPE_INT64'
236 ctype_enum('float') == 'TYPE_FLOAT'
237 ctype_enum('enum') == 'TYPE_INT32'
238
239 Remarks:
240 An enum is coerced to an int32 since the rest of the camera_metadata
241 code doesn't support enums directly yet.
242 """
243 if what == 'enum':
244 return 'TYPE_INT32'
245 return 'TYPE_%s' %(what.upper())