void generateObjcSource()

in packages/pigeon/lib/objc_generator.dart [789:927]


void generateObjcSource(ObjcOptions options, Root root, StringSink sink) {
  final Indent indent = Indent(sink);
  final List<String> classNames =
      root.classes.map((Class x) => x.name).toList();
  final List<String> enumNames = root.enums.map((Enum x) => x.name).toList();

  void writeHeader() {
    if (options.copyrightHeader != null) {
      addLines(indent, options.copyrightHeader!, linePrefix: '// ');
    }
    indent.writeln('// $generatedCodeWarning');
    indent.writeln('// $seeAlsoWarning');
  }

  void writeImports() {
    indent.writeln('#import "${options.header}"');
    indent.writeln('#import <Flutter/Flutter.h>');
  }

  void writeArcEnforcer() {
    indent.writeln('#if !__has_feature(objc_arc)');
    indent.writeln('#error File requires ARC to be enabled.');
    indent.writeln('#endif');
  }

  void writeWrapResultFunction() {
    indent.format('''
static NSDictionary<NSString *, id> *wrapResult(id result, FlutterError *error) {
\tNSDictionary *errorDict = (NSDictionary *)[NSNull null];
\tif (error) {
\t\terrorDict = @{
\t\t\t\t@"${Keys.errorCode}": (error.code ? error.code : [NSNull null]),
\t\t\t\t@"${Keys.errorMessage}": (error.message ? error.message : [NSNull null]),
\t\t\t\t@"${Keys.errorDetails}": (error.details ? error.details : [NSNull null]),
\t\t\t\t};
\t}
\treturn @{
\t\t\t@"${Keys.result}": (result ? result : [NSNull null]),
\t\t\t@"${Keys.error}": errorDict,
\t\t\t};
}''');
  }

  void writeDataClassExtension(Class klass) {
    final String className = _className(options.prefix, klass.name);
    indent.writeln('@interface $className ()');
    indent.writeln('+ ($className *)fromMap:(NSDictionary *)dict;');
    indent.writeln('- (NSDictionary *)toMap;');
    indent.writeln('@end');
  }

  void writeDataClassImplementation(Class klass) {
    final String className = _className(options.prefix, klass.name);
    void writeInitializer() {
      _writeInitializerDeclaration(
          indent, klass, root.classes, root.enums, options.prefix);
      indent.writeScoped(' {', '}', () {
        const String result = 'pigeonResult';
        indent.writeln('$className* $result = [[$className alloc] init];');
        for (final NamedType field in klass.fields) {
          indent.writeln('$result.${field.name} = ${field.name};');
        }
        indent.writeln('return $result;');
      });
    }

    void writeFromMap() {
      indent.write('+ ($className *)fromMap:(NSDictionary *)dict ');
      indent.scoped('{', '}', () {
        const String resultName = 'pigeonResult';
        indent.writeln('$className *$resultName = [[$className alloc] init];');
        for (final NamedType field in klass.fields) {
          if (enumNames.contains(field.type.baseName)) {
            indent.writeln(
                '$resultName.${field.name} = [${_dictGetter(classNames, 'dict', field, options.prefix)} integerValue];');
          } else {
            indent.writeln(
                '$resultName.${field.name} = ${_dictGetter(classNames, 'dict', field, options.prefix)};');
            if (field.type.isNullable) {
              indent.write(
                  'if ((NSNull *)$resultName.${field.name} == [NSNull null]) ');
              indent.scoped('{', '}', () {
                indent.writeln('$resultName.${field.name} = nil;');
              });
            } else {
              indent.writeln(
                  'NSAssert((NSNull *)$resultName.${field.name} != [NSNull null], @"");');
            }
          }
        }
        indent.writeln('return $resultName;');
      });
    }

    void writeToMap() {
      indent.write('- (NSDictionary *)toMap ');
      indent.scoped('{', '}', () {
        indent.write('return [NSDictionary dictionaryWithObjectsAndKeys:');
        for (final NamedType field in klass.fields) {
          indent.add(_dictValue(classNames, enumNames, field) +
              ', @"${field.name}", ');
        }
        indent.addln('nil];');
      });
    }

    indent.writeln('@implementation $className');
    writeInitializer();
    writeFromMap();
    writeToMap();
    indent.writeln('@end');
  }

  void writeApi(Api api) {
    final String codecName = _getCodecName(options.prefix, api.name);
    _writeCodec(indent, codecName, options, api, root);
    indent.addln('');
    if (api.location == ApiLocation.host) {
      _writeHostApiSource(indent, options, api);
    } else if (api.location == ApiLocation.flutter) {
      _writeFlutterApiSource(indent, options, api);
    }
  }

  writeHeader();
  writeImports();
  indent.writeln('');
  writeArcEnforcer();
  indent.addln('');
  writeWrapResultFunction();
  indent.addln('');
  root.classes.forEach(writeDataClassExtension);
  indent.writeln('');
  for (final Class klass in root.classes) {
    writeDataClassImplementation(klass);
    indent.writeln('');
  }
  root.apis.forEach(writeApi);
}