writeClassDecode method

  1. @override
void writeClassDecode(
  1. CppOptions generatorOptions,
  2. Root root,
  3. Indent indent,
  4. Class klass,
  5. Set<String> customClassNames,
  6. Set<String> customEnumNames, {
  7. required String dartPackageName,
})
override

Writes a single class decode method to indent.

Implementation

@override
void writeClassDecode(
  CppOptions generatorOptions,
  Root root,
  Indent indent,
  Class klass,
  Set<String> customClassNames,
  Set<String> customEnumNames, {
  required String dartPackageName,
}) {
  // Returns the expression to convert the given EncodableValue to a field
  // value.
  String getValueExpression(NamedType field, String encodable) {
    if (customEnumNames.contains(field.type.baseName)) {
      return '(${field.type.baseName})(std::get<int32_t>($encodable))';
    } else if (field.type.baseName == 'int') {
      return '$encodable.LongValue()';
    } else if (field.type.baseName == 'Object') {
      return encodable;
    } else {
      final HostDatatype hostDatatype = getFieldHostDatatype(field,
          root.classes, root.enums, _shortBaseCppTypeForBuiltinDartType);
      if (!hostDatatype.isBuiltin &&
          root.classes
              .map((Class x) => x.name)
              .contains(field.type.baseName)) {
        return '${hostDatatype.datatype}::FromEncodableList(std::get<EncodableList>($encodable))';
      } else {
        return 'std::get<${hostDatatype.datatype}>($encodable)';
      }
    }
  }

  _writeFunctionDefinition(indent, 'FromEncodableList',
      scope: klass.name,
      returnType: klass.name,
      parameters: <String>['const EncodableList& list'], body: () {
    const String instanceVariable = 'decoded';
    final Iterable<_IndexedField> indexedFields = indexMap(
        getFieldsInSerializationOrder(klass),
        (int index, NamedType field) => _IndexedField(index, field));
    final Iterable<_IndexedField> nullableFields = indexedFields
        .where((_IndexedField field) => field.field.type.isNullable);
    final Iterable<_IndexedField> nonNullableFields = indexedFields
        .where((_IndexedField field) => !field.field.type.isNullable);

    // Non-nullable fields must be set via the constructor.
    String constructorArgs = nonNullableFields
        .map((_IndexedField param) =>
            getValueExpression(param.field, 'list[${param.index}]'))
        .join(',\n\t');
    if (constructorArgs.isNotEmpty) {
      constructorArgs = '(\n\t$constructorArgs)';
    }
    indent.format('${klass.name} $instanceVariable$constructorArgs;');

    // Add the nullable fields via setters, since converting the encodable
    // values to the pointer types that the convenience constructor uses for
    // nullable fields is non-trivial.
    for (final _IndexedField entry in nullableFields) {
      final NamedType field = entry.field;
      final String setterName = _makeSetterName(field);
      final String encodableFieldName =
          '${_encodablePrefix}_${_makeVariableName(field)}';
      indent.writeln('auto& $encodableFieldName = list[${entry.index}];');

      final String valueExpression =
          getValueExpression(field, encodableFieldName);
      indent.writeScoped('if (!$encodableFieldName.IsNull()) {', '}', () {
        indent.writeln('$instanceVariable.$setterName($valueExpression);');
      });
    }

    // This returns by value, relying on copy elision, since it makes the
    // usage more convenient during deserialization than it would be with
    // explicit transfer via unique_ptr.
    indent.writeln('return $instanceVariable;');
  });
}