def _generate_struct(self, struct):
     with self.block('type %s struct' % struct.name):
         if struct.parent_type:
             self.emit(
                 fmt_type(struct.parent_type, struct.namespace).lstrip('*'))
         for field in struct.fields:
             self._generate_field(field, namespace=struct.namespace)
         if struct.name in ('DownloadArg', ):
             self.emit(
                 '// ExtraHeaders can be used to pass Range, If-None-Match headers'
             )
             self.emit('ExtraHeaders map[string]string `json:"-"`')
     self._generate_struct_builder(struct)
     self.emit()
     if needs_base_type(struct):
         self.emit('// UnmarshalJSON deserializes into a %s instance' %
                   struct.name)
         with self.block('func (u *%s) UnmarshalJSON(b []byte) error' %
                         struct.name):
             with self.block('type wrap struct'):
                 for field in struct.all_fields:
                     self._generate_field(field,
                                          namespace=struct.namespace,
                                          raw=_needs_base_type(
                                              field.data_type))
             self.emit('var w wrap')
             with self.block('if err := json.Unmarshal(b, &w); err != nil'):
                 self.emit('return err')
             for field in struct.all_fields:
                 dt = field.data_type
                 fn = fmt_var(field.name)
                 tn = fmt_type(dt,
                               namespace=struct.namespace,
                               use_interface=True)
                 if _needs_base_type(dt):
                     if is_list_type(dt):
                         self.emit("u.{0} = make({1}, len(w.{0}))".format(
                             fn, tn))
                         # Grab the underlying type to get the correct Is...FromJSON method
                         tn = fmt_type(dt.data_type,
                                       namespace=struct.namespace,
                                       use_interface=True)
                         with self.block(
                                 "for i, e := range w.{0}".format(fn)):
                             self.emit("v, err := {1}FromJSON(e)".format(
                                 fn, tn))
                             with self.block('if err != nil'):
                                 self.emit('return err')
                             self.emit("u.{0}[i] = v".format(fn))
                     else:
                         self.emit("{0}, err := {1}FromJSON(w.{0})".format(
                             fn, tn))
                         with self.block('if err != nil'):
                             self.emit('return err')
                         self.emit("u.{0} = {0}".format(fn))
                 else:
                     self.emit("u.{0} = w.{0}".format(fn))
             self.emit('return nil')
예제 #2
0
    def _generate_union_helper(self, u):
        name = u.name
        namespace = u.namespace
        # Unions can be inherited, but don't need to be polymorphic.
        # So let's flatten out all the inherited fields.
        fields = u.all_fields
        if is_struct_type(u) and u.has_enumerated_subtypes():
            name = fmt_var(name, export=False) + 'Union'
            fields = u.get_enumerated_subtypes()

        with self.block('type %s struct' % name):
            self.emit('dropbox.Tagged')
            for field in fields:
                if is_void_type(field.data_type):
                    continue
                self._generate_field(field, union_field=True,
                                     namespace=namespace)
        self.emit()
        self.emit('// Valid tag values for %s' % fmt_var(u.name))
        with self.block('const', delim=('(', ')')):
            for field in fields:
                self.emit('%s%s = "%s"' %
                          (fmt_var(u.name), fmt_var(field.name), field.name))
        self.emit()

        num_void_fields = sum([is_void_type(f.data_type) for f in fields])
        # Simple structure, no need in UnmarshalJSON
        if len(fields) == num_void_fields:
            return

        self.emit('// UnmarshalJSON deserializes into a %s instance' % name)
        with self.block('func (u *%s) UnmarshalJSON(body []byte) error' % name):
            with self.block('type wrap struct'):
                self.emit('dropbox.Tagged')
                for field in fields:
                    if is_void_type(field.data_type) or (
                            is_struct_type(field.data_type) and not _needs_base_type(field.data_type)):
                        # pure structures are flattened in the containing union json blob and thus are loaded from body
                        continue
                    # sub-unions must be handled as RawMessage, which will be loaded into correct implementation later
                    self._generate_field(field, union_field=True,
                                         namespace=namespace, raw=_needs_base_type(field.data_type))
            self.emit('var w wrap')
            self.emit('var err error')
            with self.block('if err = json.Unmarshal(body, &w); err != nil'):
                self.emit('return err')
            self.emit('u.Tag = w.Tag')
            with self.block('switch u.Tag'):
                for field in fields:
                    if is_void_type(field.data_type):
                        continue
                    field_name = fmt_var(field.name)
                    with self.block('case "%s":' % field.name, delim=(None, None)):
                        if _needs_base_type(field.data_type):
                            self.emit("u.{0}, err = Is{1}FromJSON(w.{0})"
                                      .format(field_name, field.data_type.name))
                        elif is_struct_type(field.data_type):
                            self.emit('err = json.Unmarshal(body, &u.{0})'
                                      .format(field_name))
                        else:
                            self.emit('u.{0} = w.{0}'.format(field_name))
                    with self.block("if err != nil"):
                        self.emit("return err")
            self.emit('return nil')
        self.emit()