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