Skip to content

Commit 614539a

Browse files
committed
fix(type-clashes): protect from nested-type-clash
It was possible for a nested type to be generated with a name that in fact CLASHED with an existing schema type. What are the odds ! The clash-check added will just verify against clashes with schema types, which seems to be doing it for now.
1 parent 32145e6 commit 614539a

7 files changed

Lines changed: 74 additions & 67 deletions

File tree

gen/youtube3/src/lib.rs

Lines changed: 45 additions & 45 deletions
Large diffs are not rendered by default.

src/mako/README.md.mako

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<%
22
from util import (markdown_comment, new_context)
3-
c = new_context(resources)
3+
c = new_context(schemas, resources)
44
%>\
55
<%namespace name="lib" file="lib/lib.mako"/>\
66
<%namespace name="util" file="lib/util.mako"/>\

src/mako/lib.rs.mako

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
nested_schemas = list()
1212
if schemas:
1313
nested_schemas = list(iter_nested_types(schemas))
14-
c = new_context(resources)
14+
c = new_context(schemas, resources)
1515
hub_type = hub_type(schemas, util.canonical_name())
1616
ht_params = hub_type_params_s()
1717
%>\

src/mako/lib/mbuild.mako

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ pub struct ${ThisType}
9090
% for p in params:
9191
${property(p.name)}:\
9292
% if is_required_property(p):
93-
${activity_rust_type(p, allow_optionals=False)},
93+
${activity_rust_type(schemas, p, allow_optionals=False)},
9494
% else:
95-
${activity_rust_type(p)},
95+
${activity_rust_type(schemas, p)},
9696
% endif
9797
% endfor
9898
## A generic map for additinal parameters. Sometimes you can set some that are documented online only
@@ -161,7 +161,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
161161
###############################################################################################
162162
<%def name="_setter_fn(resource, method, m, p, part_prop, ThisType, c)">\
163163
<%
164-
InType = activity_input_type(p)
164+
InType = activity_input_type(schemas, p)
165165
166166
def show_part_info(m, p):
167167
if p.name != 'part':
@@ -217,7 +217,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
217217
is_string_value = lambda v: v.endswith('"')
218218
219219
# to rust value
220-
trv = lambda spn, sp, sn=None: to_rust_type(sn, spn, sp, allow_optionals=False)
220+
trv = lambda spn, sp, sn=None: to_rust_type(schemas, sn, spn, sp, allow_optionals=False)
221221
# rvfrt = random value for rust type
222222
rvfrt = lambda spn, sp, sn=None: rnd_arg_val_for_type(trv(spn, sp, sn))
223223

src/mako/lib/rbuild.mako

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ impl${rb_params} ${ThisType} {
6161
6262
method_args = ''
6363
if required_props:
64-
method_args = ', ' + ', '.join('%s: %s' % (mangle_ident(p.name), activity_input_type(p)) for p in required_props)
64+
method_args = ', ' + ', '.join('%s: %s' % (mangle_ident(p.name), activity_input_type(schemas, p)) for p in required_props)
6565
6666
mb_tparams = mb_type_params_s(m)
6767
# we would could have information about data requirements for each property in it's dict.
6868
# for now, we just hardcode it, and treat the entries as way to easily change param names
6969
assert len(api.properties) == 2, "Hardcoded for now, thanks to scope requirements"
70-
70+
7171
type_params = ''
7272
if mb_additional_type_params(m):
7373
type_params = '<%s>' % ', '.join(mb_additional_type_params(m))
@@ -82,7 +82,7 @@ impl${rb_params} ${ThisType} {
8282
${RType} {
8383
hub: self.hub,
8484
% for p in required_props:
85-
${property(p.name)}: ${rust_copy_value_s(mangle_ident(p.name), activity_input_type(p), p)},
85+
${property(p.name)}: ${rust_copy_value_s(mangle_ident(p.name), activity_input_type(schemas, p), p)},
8686
% endfor
8787
## auto-generate parts from request resources
8888
% if part_prop and request_value:

src/mako/lib/schema.mako

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub struct ${s.id}\
1111
{
1212
% for pn, p in properties.iteritems():
1313
${p.get('description', 'no description provided') | rust_doc_comment, indent_all_but_first_by(1)}
14-
pub ${mangle_ident(pn)}: ${to_rust_type(s.id, pn, p)},
14+
pub ${mangle_ident(pn)}: ${to_rust_type(schemas, s.id, pn, p)},
1515
% endfor
1616
}
1717
% else: ## it's an empty struct, i.e. struct Foo;
@@ -35,7 +35,7 @@ ${doc(s, c)}\
3535
${_new_object(s, s.get('properties'), c)}\
3636
% elif s.type == 'array':
3737
% if s.items.get('type') != 'object':
38-
pub struct ${s.id}(${to_rust_type(s.id, NESTED_TYPE_SUFFIX, s)});
38+
pub struct ${s.id}(${to_rust_type(schemas, s.id, NESTED_TYPE_SUFFIX, s)});
3939
% else:
4040
${_new_object(s, s.items.get('properties'), c)}\
4141
% endif ## array item != 'object'
@@ -57,7 +57,7 @@ impl ${s.id} {
5757
% for pn, p in s.properties.iteritems():
5858
<%
5959
mn = 'self.' + mangle_ident(pn)
60-
rt = to_rust_type(s.id, pn, p)
60+
rt = to_rust_type(schemas, s.id, pn, p)
6161
check = 'is_some()'
6262
if rt.startswith('Vec') or rt.startswith('HashMap'):
6363
check = 'len() > 0'
@@ -92,6 +92,6 @@ This type is not used in any activity, and only used as *part* of another schema
9292
% if s.type != 'object':
9393
9494
## for some reason, it's not shown in rustdoc ...
95-
The contained type is `${to_rust_type(s.id, s.id, s)}`.
95+
The contained type is `${to_rust_type(schemas, s.id, s.id, s)}`.
9696
%endif
9797
</%def>

src/mako/lib/util.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,18 @@ def mangle_ident(n):
263263
def _is_map_prop(p):
264264
return 'additionalProperties' in p
265265

266+
def _assure_unique_type_name(schemas, tn):
267+
if tn in schemas:
268+
tn += 'Internal'
269+
assert tn not in schemas
270+
return tn
271+
266272
# map a json type to an rust type
267273
# sn = schema name
268274
# pn = property name
269275
# t = type dict
270276
# NOTE: In case you don't understand how this algorithm really works ... me neither - THE AUTHOR
271-
def to_rust_type(sn, pn, t, allow_optionals=True):
277+
def to_rust_type(schemas, sn, pn, t, allow_optionals=True):
272278
def nested_type(nt):
273279
if 'items' in nt:
274280
nt = nt.items
@@ -277,8 +283,8 @@ def nested_type(nt):
277283
else:
278284
assert(is_nested_type_property(nt))
279285
# It's a nested type - we take it literally like $ref, but generate a name for the type ourselves
280-
return nested_type_name(sn, pn)
281-
return to_rust_type(sn, pn, nt, allow_optionals=False)
286+
return _assure_unique_type_name(schemas, nested_type_name(sn, pn))
287+
return to_rust_type(schemas, sn, pn, nt, allow_optionals=False)
282288

283289
def wrap_type(tn):
284290
if allow_optionals:
@@ -323,10 +329,10 @@ def is_nested_type(s):
323329

324330
# convert a rust-type to something that would be taken as input of a function
325331
# even though our storage type is different
326-
def activity_input_type(p):
332+
def activity_input_type(schemas, p):
327333
if 'input_type' in p:
328334
return p.input_type
329-
n = activity_rust_type(p, allow_optionals=False)
335+
n = activity_rust_type(schemas, p, allow_optionals=False)
330336
if n == 'String':
331337
n = 'str'
332338
# pods are copied anyway
@@ -370,6 +376,7 @@ def iter_nested_properties(prefix, properties):
370376
if 'properties' not in s:
371377
continue
372378
for np in iter_nested_properties(s.id, s.properties):
379+
np.id = _assure_unique_type_name(schemas, np.id)
373380
yield np
374381
# end for aech schma
375382

@@ -409,8 +416,8 @@ def activity_split(fqan):
409416
return t[0], t[1], '.'.join(t[2:])
410417

411418
# Shorthand to get a type from parameters of activities
412-
def activity_rust_type(p, allow_optionals=True):
413-
return to_rust_type(None, p.name, p, allow_optionals=allow_optionals)
419+
def activity_rust_type(schemas, p, allow_optionals=True):
420+
return to_rust_type(schemas, None, p.name, p, allow_optionals=allow_optionals)
414421

415422
# the inverse of activity-split, but needs to know the 'name' of the API
416423
def to_fqan(name, resource, method):
@@ -563,7 +570,7 @@ def build_all_params(schemas, c, m, n, npn):
563570
Context = collections.namedtuple('Context', ['sta_map', 'fqan_map', 'rta_map', 'rtc_map'])
564571

565572
# return a newly build context from the given data
566-
def new_context(resources):
573+
def new_context(schemas, resources):
567574
if not resources:
568575
return Context(dict(), dict(), dict(), dict())
569576
# Returns (A, B) where
@@ -587,7 +594,7 @@ def build_activity_mappings(activities, res = None, fqan = None):
587594
t = m.get(in_out_type_name, None)
588595
if t is None:
589596
continue
590-
tn = to_rust_type(None, None, t, allow_optionals=False)
597+
tn = to_rust_type(schemas, None, None, t, allow_optionals=False)
591598
info = res.setdefault(tn, dict())
592599
io_info = info.setdefault(m.id, [])
593600
io_info.append(in_out_type_name)

0 commit comments

Comments
 (0)