Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle mapping struct fields with subtypes to Objective-C #319

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion stone/backends/swift_rsrc/ObjcTypes.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,37 @@ public class DBX{{ namespace_class_name }}{{ data_type_class_name }}: {{ 'NSObje
{% for field in data_type.fields %}
{{ struct_field_doc(field, ' ') }}
@objc
public var {{ fmt_var(field.name) }}: {{ fmt_objc_type(field.data_type) }} { {{ objc_return_field_value(data_type, field) }} }
{% if objc_return_field_value_specified_in_jinja(field) %}
public var {{ fmt_var(field.name) }}: {{ fmt_objc_type(field.data_type) }} {
{% if (field_is_user_defined(field)) or (field_is_user_defined_optional(field)) %}
switch {{ swift_var_name }}.{{ fmt_var(field.name) }} {
{% for tuple in objc_return_field_value_type_tuples(field) %}
case let {{ tuple[0] }} as {{ tuple[1] }}:
return {{ tuple[2] }}(swift: {{ tuple[0] }})
{% endfor %}
default:
{% if field_is_user_defined_optional(field) %}
return {{ swift_var_name }}.{{ fmt_var(field.name) }}.flatMap { {{ fmt_objc_type(field.data_type, False) }}(swift: $0) }
{% else %}
return {{ fmt_objc_type(field.data_type) }}(swift: {{ swift_var_name }}.{{ fmt_var(field.name) }})
{% endif %}
}
{% elif (field_is_user_defined_map(field)) or (field_is_user_defined_list(field)) %}
{{ swift_var_name }}.{{ fmt_var(field.name) }}.{{ 'mapValues' if field_is_user_defined_map(field) else 'map' }} {
switch $0 {
{% for tuple in objc_return_field_value_type_tuples(field) %} {#extract this snippet?#}
case let {{ tuple[0] }} as {{ tuple[1] }}:
return {{ tuple[2] }}(swift: {{ tuple[0] }})
{% endfor %}
default:
return {{ fmt_objc_type(field.data_type.data_type) }}(swift: $0)
}
}
{% endif %}
}
{% else %}
public var {{ fmt_var(field.name) }}: {{ fmt_objc_type(field.data_type) }} { {{ objc_return_field_value_oneliner(data_type, field) }} }
{% endif %}
{% endfor %}
{% if data_type.fields %}

Expand Down
73 changes: 71 additions & 2 deletions stone/backends/swift_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,16 @@ def generate(self, api):
template_globals['data_objc_type_doc'] = self._data_objc_type_doc
template_globals['objc_init_args'] = self._objc_init_args
template_globals['fmt_objc_type'] = fmt_objc_type
template_globals['objc_return_field_value'] = self._objc_return_field_value
oneliner_func_key = 'objc_return_field_value_oneliner'
template_globals[oneliner_func_key] = self._objc_return_field_value_oneliner
template_globals['field_is_user_defined'] = self._field_is_user_defined
template_globals['field_is_user_defined_optional'] = self._field_is_user_defined_optional
template_globals['field_is_user_defined_list'] = self._field_is_user_defined_list
template_globals['field_is_user_defined_map'] = self._field_is_user_defined_map
in_jinja_key = 'objc_return_field_value_specified_in_jinja'
template_globals[in_jinja_key] = self._objc_return_field_value_specified_in_jinja
field_value_tuples_key = 'objc_return_field_value_type_tuples'
template_globals[field_value_tuples_key] = self._objc_return_field_value_type_tuples
template_globals['objc_init_args_to_swift'] = self._objc_init_args_to_swift
template_globals['objc_union_arg'] = self._objc_union_arg
template_globals['objc_swift_var_name'] = self._objc_swift_var_name
Expand Down Expand Up @@ -334,7 +343,67 @@ def _route_schema_attrs(self, route_schema, route):
result = ',\n '.join(attrs)
return result

def _objc_return_field_value(self, parent_type, field):
# List[typing.Tuple[let_name: str, swift_type: str, objc_type: str]]
def _objc_return_field_value_type_tuples(self, field):
data_type = field.data_type
ret = []

# if list type get the data type of the item
if is_list_type(data_type):
data_type = data_type.data_type

# if map type get the data type of the value
if is_map_type(data_type):
data_type = data_type.value_data_type

# if data_type is a struct type and has subtypes, process them into labels and types
if is_struct_type(data_type) and data_type.has_enumerated_subtypes():
all_subtypes = data_type.get_all_subtypes_with_tags()

for subtype in all_subtypes:
# subtype[0] is the tag name and subtype[1] is the subtype struct itself
struct = subtype[1]
case_let_name = fmt_var(struct.name)
swift_type = fmt_type(struct)
objc_type = fmt_objc_type(struct)
ret.append((case_let_name, swift_type, objc_type))

return ret

def _field_is_user_defined(self, field):
data_type, nullable = unwrap_nullable(field.data_type)
return is_user_defined_type(data_type) and not nullable

def _field_is_user_defined_optional(self, field):
data_type, nullable = unwrap_nullable(field.data_type)
return is_user_defined_type(data_type) and nullable

def _field_is_user_defined_map(self, field):
data_type, _ = unwrap_nullable(field.data_type)
return is_map_type(data_type) and is_user_defined_type(data_type.value_data_type)

def _field_is_user_defined_list(self, field):
data_type, _ = unwrap_nullable(field.data_type)
if is_list_type(data_type):
list_data_type, _ = unwrap_nullable(data_type.data_type)
return is_user_defined_type(list_data_type)
else:
return False

def _objc_return_field_value_specified_in_jinja(self, field) -> bool:
eligible_kind = self._field_is_user_defined(field) or \
self._field_is_user_defined_optional(field) or \
self._field_is_user_defined_map(field) or \
self._field_is_user_defined_list(field)

if not eligible_kind:
return False

requires_iterating_over_subtypes = len(self._objc_return_field_value_type_tuples(field)) > 0

return requires_iterating_over_subtypes

def _objc_return_field_value_oneliner(self, parent_type, field):
data_type, nullable = unwrap_nullable(field.data_type)
swift_var_name = self._objc_swift_var_name(parent_type)

Expand Down
Loading