writeFlutterApi method

  1. @override
void writeFlutterApi(
  1. GObjectOptions generatorOptions,
  2. Root root,
  3. Indent indent,
  4. Api api, {
  5. required String dartPackageName,
})
override

Writes a single Flutter Api to indent.

Implementation

@override
void writeFlutterApi(
  GObjectOptions generatorOptions,
  Root root,
  Indent indent,
  Api api, {
  required String dartPackageName,
}) {
  final String module = _getModule(generatorOptions, dartPackageName);
  final String className = _getClassName(module, api.name);
  final String methodPrefix = _getMethodPrefix(module, api.name);
  final String codecClassName = _getClassName(module, _codecBaseName);
  final String codecMethodPrefix = _getMethodPrefix(module, _codecBaseName);

  indent.newln();
  _writeObjectStruct(indent, module, api.name, () {
    indent.writeln('FlBinaryMessenger* messenger;');
    indent.writeln('gchar *suffix;');
  });

  indent.newln();
  _writeDefineType(indent, module, api.name);

  indent.newln();
  _writeDispose(indent, module, api.name, () {
    _writeCastSelf(indent, module, api.name, 'object');
    indent.writeln('g_clear_object(&self->messenger);');
    indent.writeln('g_clear_pointer(&self->suffix, g_free);');
  });

  indent.newln();
  _writeInit(indent, module, api.name, () {});

  indent.newln();
  _writeClassInit(indent, module, api.name, () {});

  indent.newln();
  indent.writeScoped(
      '$className* ${methodPrefix}_new(FlBinaryMessenger* messenger, const gchar* suffix) {',
      '}', () {
    _writeObjectNew(indent, module, api.name);
    indent.writeln(
        'self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));');
    indent.writeln(
        'self->suffix = suffix != nullptr ? g_strdup_printf(".%s", suffix) : g_strdup("");');
    indent.writeln('return self;');
  });

  for (final Method method in api.methods) {
    final String methodName = _getMethodName(method.name);
    final String responseName = _getResponseName(api.name, method.name);
    final String responseClassName = _getClassName(module, responseName);
    final String responseMethodPrefix =
        _getMethodPrefix(module, responseName);
    final String testResponseMacro =
        '${_snakeCaseFromCamelCase(module)}_IS_${_snakeCaseFromCamelCase(responseName)}'
            .toUpperCase();

    indent.newln();
    _writeObjectStruct(indent, module, responseName, () {
      indent.writeln('FlValue* error;');
      if (!method.returnType.isVoid) {
        indent.writeln('FlValue* return_value;');
        if (_isNullablePrimitiveType(method.returnType)) {
          final String primitiveType =
              _getType(module, method.returnType, primitive: true);
          indent.writeln('$primitiveType return_value_;');
        }
      }
    });

    indent.newln();
    _writeDefineType(indent, module, responseName);

    indent.newln();
    _writeDispose(indent, module, responseName, () {
      _writeCastSelf(indent, module, responseName, 'object');
      indent.writeln('g_clear_pointer(&self->error, fl_value_unref);');
      if (!method.returnType.isVoid) {
        indent
            .writeln('g_clear_pointer(&self->return_value, fl_value_unref);');
      }
    });

    indent.newln();
    _writeInit(indent, module, responseName, () {});

    indent.newln();
    _writeClassInit(indent, module, responseName, () {});

    indent.newln();
    indent.writeScoped(
        'static $responseClassName* ${responseMethodPrefix}_new(FlValue* response) {',
        '}', () {
      _writeObjectNew(indent, module, responseName);
      indent.writeScoped('if (fl_value_get_length(response) > 1) {', '}', () {
        indent.writeln('self->error = fl_value_ref(response);');
      });
      if (!method.returnType.isVoid) {
        indent.writeScoped('else {', '}', () {
          indent.writeln(
              'FlValue* value = fl_value_get_list_value(response, 0);');
          indent.writeln('self->return_value = fl_value_ref(value);');
        });
      }
      indent.writeln('return self;');
    });

    indent.newln();
    indent.writeScoped(
        'gboolean ${responseMethodPrefix}_is_error($responseClassName* self) {',
        '}', () {
      indent
          .writeln('g_return_val_if_fail($testResponseMacro(self), FALSE);');
      indent.writeln('return self->error != nullptr;');
    });

    indent.newln();
    indent.writeScoped(
        'const gchar* ${responseMethodPrefix}_get_error_code($responseClassName* self) {',
        '}', () {
      indent.writeln(
          'g_return_val_if_fail($testResponseMacro(self), nullptr);');
      indent.writeln('g_assert(${responseMethodPrefix}_is_error(self));');
      indent.writeln(
          'return fl_value_get_string(fl_value_get_list_value(self->error, 0));');
    });

    indent.newln();
    indent.writeScoped(
        'const gchar* ${responseMethodPrefix}_get_error_message($responseClassName* self) {',
        '}', () {
      indent.writeln(
          'g_return_val_if_fail($testResponseMacro(self), nullptr);');
      indent.writeln('g_assert(${responseMethodPrefix}_is_error(self));');
      indent.writeln(
          'return fl_value_get_string(fl_value_get_list_value(self->error, 1));');
    });

    indent.newln();
    indent.writeScoped(
        'FlValue* ${responseMethodPrefix}_get_error_details($responseClassName* self) {',
        '}', () {
      indent.writeln(
          'g_return_val_if_fail($testResponseMacro(self), nullptr);');
      indent.writeln('g_assert(${responseMethodPrefix}_is_error(self));');
      indent.writeln('return fl_value_get_list_value(self->error, 2);');
    });

    if (!method.returnType.isVoid) {
      final String primitiveType =
          _getType(module, method.returnType, primitive: true);

      indent.newln();
      final String returnType = _isNullablePrimitiveType(method.returnType)
          ? '$primitiveType*'
          : primitiveType;
      indent.writeScoped(
          '$returnType ${responseMethodPrefix}_get_return_value($responseClassName* self${_isNumericListType(method.returnType) ? ', size_t* return_value_length' : ''}) {',
          '}', () {
        indent.writeln(
            'g_return_val_if_fail($testResponseMacro(self), ${_getDefaultValue(module, method.returnType)});');
        indent.writeln('g_assert(!${responseMethodPrefix}_is_error(self));');
        if (method.returnType.isNullable) {
          indent.writeScoped(
              'if (fl_value_get_type(self->return_value) == FL_VALUE_TYPE_NULL) {',
              '}', () {
            indent.writeln('return nullptr;');
          });
        }
        if (_isNumericListType(method.returnType)) {
          indent.writeScoped('if (return_value_length != nullptr) {', '}',
              () {
            indent.writeln(
                '*return_value_length = fl_value_get_length(self->return_value);');
          });
        }
        if (_isNullablePrimitiveType(method.returnType)) {
          indent.writeln(
              'self->return_value_ = ${_fromFlValue(module, method.returnType, 'self->return_value')};');
          indent.writeln('return &self->return_value_;');
        } else {
          indent.writeln(
              'return ${_fromFlValue(module, method.returnType, 'self->return_value')};');
        }
      });
    }

    indent.newln();
    indent.writeScoped(
        'static void ${methodPrefix}_${methodName}_cb(GObject* object, GAsyncResult* result, gpointer user_data) {',
        '}', () {
      indent.writeln('GTask* task = G_TASK(user_data);');
      indent.writeln('g_task_return_pointer(task, result, g_object_unref);');
    });

    final List<String> asyncArgs = <String>['$className* self'];
    for (final Parameter param in method.parameters) {
      final String name = _snakeCaseFromCamelCase(param.name);
      asyncArgs.add('${_getType(module, param.type)} $name');
      if (_isNumericListType(param.type)) {
        asyncArgs.add('size_t ${name}_length');
      }
    }
    asyncArgs.addAll(<String>[
      'GCancellable* cancellable',
      'GAsyncReadyCallback callback',
      'gpointer user_data',
    ]);
    indent.newln();
    indent.writeScoped(
        "void ${methodPrefix}_$methodName(${asyncArgs.join(', ')}) {", '}',
        () {
      indent.writeln('g_autoptr(FlValue) args = fl_value_new_list();');
      for (final Parameter param in method.parameters) {
        final String name = _snakeCaseFromCamelCase(param.name);
        final String value = _makeFlValue(root, module, param.type, name,
            lengthVariableName: '${name}_length');
        indent.writeln('fl_value_append_take(args, $value);');
      }
      final String channelName =
          makeChannelName(api, method, dartPackageName);
      indent.writeln(
          'g_autofree gchar* channel_name = g_strdup_printf("$channelName%s", self->suffix);');
      indent.writeln(
          'g_autoptr($codecClassName) codec = ${codecMethodPrefix}_new();');
      indent.writeln(
          'FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec));');
      indent.writeln(
          'GTask* task = g_task_new(self, cancellable, callback, user_data);');
      indent.writeln('g_task_set_task_data(task, channel, g_object_unref);');
      indent.writeln(
          'fl_basic_message_channel_send(channel, args, cancellable, ${methodPrefix}_${methodName}_cb, task);');
    });

    final List<String> finishArgs = <String>[
      '$className* self',
      'GAsyncResult* result',
      'GError** error',
    ];
    indent.newln();
    indent.writeScoped(
        "$responseClassName* ${methodPrefix}_${methodName}_finish(${finishArgs.join(', ')}) {",
        '}', () {
      indent.writeln('g_autoptr(GTask) task = G_TASK(result);');
      indent.writeln(
          'GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr));');
      indent.writeln(
          'FlBasicMessageChannel* channel = FL_BASIC_MESSAGE_CHANNEL(g_task_get_task_data(task));');
      indent.writeln(
          'g_autoptr(FlValue) response = fl_basic_message_channel_send_finish(channel, r, error);');
      indent.writeScoped('if (response == nullptr) { ', '}', () {
        indent.writeln('return nullptr;');
      });
      indent.writeln('return ${responseMethodPrefix}_new(response);');
    });
  }
}