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

[pigeon]: added generation of empty classes in dart #8337

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f9a3a92
added generation of empty classes in dart
feduke-nukem Dec 24, 2024
42b5e81
Merge branch 'main' into fix-160501
feduke-nukem Dec 24, 2024
72d9718
fix(160501): readme fix
feduke-nukem Dec 24, 2024
ffd14fe
Merge branch 'fix-160501' of https://github.com/feduke-nukem/packages…
feduke-nukem Dec 24, 2024
50464ea
Merge branch 'main' into fix-160501
feduke-nukem Dec 27, 2024
51fada4
fix(160501): bump version
feduke-nukem Dec 27, 2024
d8a2edb
Merge branch 'fix-160501' of https://github.com/feduke-nukem/packages…
feduke-nukem Dec 27, 2024
36b5dcd
fix(160501): run tool/generate.dart
feduke-nukem Dec 27, 2024
15e9ef5
Merge branch 'main' into fix-160501
feduke-nukem Dec 28, 2024
5585cac
Merge branch 'main' into fix-160501
feduke-nukem Jan 1, 2025
a2a4882
Merge branch 'main' into fix-160501
feduke-nukem Jan 5, 2025
bbeb7de
Merge branch 'main' into fix-160501
feduke-nukem Jan 13, 2025
598992c
Merge branch 'main' into fix-160501
feduke-nukem Jan 14, 2025
ff13737
Merge branch 'main' into fix-160501
feduke-nukem Jan 15, 2025
f364686
fix(160501): review changes
feduke-nukem Jan 15, 2025
9746ec3
fix(160501): fixes for kotlin fromList method
feduke-nukem Jan 15, 2025
3803c6a
fix(160501): added EmptyEvent into macos integration TestPlugin
feduke-nukem Jan 15, 2025
f81fc7e
Merge branch 'main' into fix-160501
feduke-nukem Jan 15, 2025
bd589c2
Merge branch 'main' into fix-160501
feduke-nukem Jan 16, 2025
6d4298a
fix(160501): added new line for @Suppress("UNUSED_PARAMETER")
feduke-nukem Jan 16, 2025
51205f6
Merge branch 'main' into fix-160501
feduke-nukem Jan 17, 2025
d65b57b
Merge branch 'main' into fix-160501
feduke-nukem Jan 19, 2025
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
1 change: 1 addition & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## NEXT
tarrinneal marked this conversation as resolved.
Show resolved Hide resolved

* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
* [dart] fixes [160501](https://github.com/flutter/flutter/issues/160501).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be it's own version update 22.7.3

I think it should read Adds support for empty data classes
This shouldn't be added to dart if it isn't supported on all platforms also, so no [dart] needed

Copy link
Author

@feduke-nukem feduke-nukem Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Also added generating @Suppress("UNUSED_PARAMETER") for fromList() method of empty classes (Kotlin) as tests were failing due to linter

However I am facing issues at some CI steps:

Infra Failure: Step('Run package tests.reset XCode') (canceled) (retcode: None)
Task timed out.

UPD: It worked


## 22.7.0

Expand Down
12 changes: 12 additions & 0 deletions packages/pigeon/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ Stream<String> getEventStream() async* {
case StringEvent():
final String stringData = event.data;
yield '$stringData, ';
case EmptyEvent():
yield 'EmptyEvent, ';
}
}
}
Expand Down Expand Up @@ -420,6 +422,12 @@ class EventListener: StreamEventsStreamHandler {
}
}

func onEmptyEvent() {
if let eventSink = eventSink {
eventSink.success(EmptyEvent())
}
}

func onEventsDone() {
eventSink?.endOfStream()
eventSink = nil
Expand Down Expand Up @@ -457,6 +465,10 @@ class EventListener : StreamEventsStreamHandler() {
eventSink?.success(StringEvent(data = event))
}

fun onEmptyEvent() {
eventSink?.success(EmptyEvent())
}

fun onEventsDone() {
eventSink?.endOfStream()
eventSink = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ data class StringEvent(val data: String) : PlatformEvent() {
}
}

/** Generated class from Pigeon that represents data sent in messages. */
class EmptyEvent() : PlatformEvent() {
companion object {
fun fromList(pigeonVar_list: List<Any?>): EmptyEvent {
return EmptyEvent()
}
}

fun toList(): List<Any?> {
return listOf()
}
}

private open class EventChannelMessagesPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return when (type) {
Expand All @@ -58,6 +71,9 @@ private open class EventChannelMessagesPigeonCodec : StandardMessageCodec() {
130.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { StringEvent.fromList(it) }
}
131.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let { EmptyEvent.fromList(it) }
}
else -> super.readValueOfType(type, buffer)
}
}
Expand All @@ -72,6 +88,10 @@ private open class EventChannelMessagesPigeonCodec : StandardMessageCodec() {
stream.write(130)
writeValue(stream, value.toList())
}
is EmptyEvent -> {
stream.write(131)
writeValue(stream, value.toList())
}
else -> super.writeValue(stream, value)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package dev.flutter.pigeon_example_app

import EmptyEvent
import ExampleHostApi
import FlutterError
import IntEvent
Expand Down Expand Up @@ -72,6 +73,10 @@ class EventListener : StreamEventsStreamHandler() {
eventSink?.success(StringEvent(data = event))
}

fun onEmptyEvent() {
eventSink?.success(EmptyEvent())
}

fun onEventsDone() {
eventSink?.endOfStream()
eventSink = null
Expand All @@ -93,6 +98,11 @@ fun sendEvents(eventListener: EventListener) {
eventListener.onIntEvent(count.toLong())
count++
}
} else if (count % 5 == 0) {
handler.post {
eventListener.onEmptyEvent()
count++
}
} else {
handler.post {
eventListener.onStringEvent(count.toString())
Expand Down
8 changes: 8 additions & 0 deletions packages/pigeon/example/app/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ class EventListener: StreamEventsStreamHandler {
}
}

func onEmptyEvent() {
if let eventSink = eventSink {
eventSink.success(EmptyEvent())
}
}

func onEventsDone() {
eventSink?.endOfStream()
eventSink = nil
Expand All @@ -84,6 +90,8 @@ func sendEvents(_ eventListener: EventListener) {
} else {
if (count % 2) == 0 {
eventListener.onIntEvent(event: Int64(count))
} else if (count % 5) == 0 {
eventListener.onEmptyEvent()
} else {
eventListener.onStringEvent(event: String(count))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,28 @@ struct StringEvent: PlatformEvent {
}
}

/// Generated class from Pigeon that represents data sent in messages.
struct EmptyEvent: PlatformEvent {

// swift-format-ignore: AlwaysUseLowerCamelCase
static func fromList(_ pigeonVar_list: [Any?]) -> EmptyEvent? {

return EmptyEvent()
}
func toList() -> [Any?] {
return []
}
}

private class EventChannelMessagesPigeonCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? {
switch type {
case 129:
return IntEvent.fromList(self.readValue() as! [Any?])
case 130:
return StringEvent.fromList(self.readValue() as! [Any?])
case 131:
return EmptyEvent.fromList(self.readValue() as! [Any?])
default:
return super.readValue(ofType: type)
}
Expand All @@ -88,6 +103,9 @@ private class EventChannelMessagesPigeonCodecWriter: FlutterStandardWriter {
} else if let value = value as? StringEvent {
super.writeByte(130)
super.writeValue(value.toList())
} else if let value = value as? EmptyEvent {
super.writeByte(131)
super.writeValue(value.toList())
} else {
super.writeValue(value)
}
Expand Down
2 changes: 2 additions & 0 deletions packages/pigeon/example/app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class _MyHomePageState extends State<MyHomePage> {
case StringEvent():
final String stringData = event.data;
yield '$stringData, ';
case EmptyEvent():
yield 'EmptyEvent, ';
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ class StringEvent extends PlatformEvent {
}
}

class EmptyEvent extends PlatformEvent {
Object encode() {
return <Object?>[];
}

static EmptyEvent decode(Object result) {
result as List<Object?>;
return EmptyEvent();
}
}

class _PigeonCodec extends StandardMessageCodec {
const _PigeonCodec();
@override
Expand All @@ -68,6 +79,9 @@ class _PigeonCodec extends StandardMessageCodec {
} else if (value is StringEvent) {
buffer.putUint8(130);
writeValue(buffer, value.encode());
} else if (value is EmptyEvent) {
buffer.putUint8(131);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
Expand All @@ -80,6 +94,8 @@ class _PigeonCodec extends StandardMessageCodec {
return IntEvent.decode(readValue(buffer)!);
case 130:
return StringEvent.decode(readValue(buffer)!);
case 131:
return EmptyEvent.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class StringEvent extends PlatformEvent {
StringEvent(this.data);
String data;
}

class EmptyEvent extends PlatformEvent {}

// #enddocregion sealed-definitions

// #docregion event-definitions
Expand Down
22 changes: 13 additions & 9 deletions packages/pigeon/lib/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,24 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
: '';

indent.write('${sealed}class ${classDefinition.name} $implements');

indent.addScoped('{', '}', () {
if (classDefinition.fields.isEmpty) {
if (classDefinition.isSealed) {
return;
}
_writeConstructor(indent, classDefinition);
indent.newln();
for (final NamedType field
in getFieldsInSerializationOrder(classDefinition)) {
addDocumentationComments(
indent, field.documentationComments, _docCommentSpec);

final String datatype = _addGenericTypesNullable(field.type);
indent.writeln('$datatype ${field.name};');
if (classDefinition.fields.isNotEmpty) {
_writeConstructor(indent, classDefinition);
indent.newln();
for (final NamedType field
in getFieldsInSerializationOrder(classDefinition)) {
addDocumentationComments(
indent, field.documentationComments, _docCommentSpec);

final String datatype = _addGenericTypesNullable(field.type);
indent.writeln('$datatype ${field.name};');
indent.newln();
}
}
writeClassEncode(
generatorOptions,
Expand Down
6 changes: 5 additions & 1 deletion packages/pigeon/lib/kotlin_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,11 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
bool private = false,
}) {
final String privateString = private ? 'private ' : '';
final String classType = classDefinition.isSealed ? 'sealed' : 'data';
final String classType = classDefinition.isSealed
? 'sealed'
: classDefinition.fields.isNotEmpty
? 'data'
: '';
tarrinneal marked this conversation as resolved.
Show resolved Hide resolved
final String inheritance = classDefinition.superClass != null
? ' : ${classDefinition.superClassName}()'
: '';
Expand Down
24 changes: 24 additions & 0 deletions packages/pigeon/test/dart_generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1807,4 +1807,28 @@ name: foobar
expect(code, contains('buffer.putUint8(4);'));
expect(code, contains('buffer.putInt64(value);'));
});

// https://github.com/flutter/flutter/issues/160501
test('gen one empty class', () {
final Class classDefinition = Class(
name: 'Foobar',
fields: <NamedType>[],
);
final Root root = Root(
apis: <Api>[],
classes: <Class>[classDefinition],
enums: <Enum>[],
);
final StringBuffer sink = StringBuffer();
const DartGenerator generator = DartGenerator();
generator.generate(
const DartOptions(),
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final String code = sink.toString();
expect(code, contains('Object encode()'));
expect(code, contains('static Foobar decode(Object result)'));
});
}
26 changes: 26 additions & 0 deletions packages/pigeon/test/kotlin_generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1856,4 +1856,30 @@ void main() {
// There should be only one occurrence of 'is Foo' in the block
expect(count, 1);
});

// https://github.com/flutter/flutter/issues/160501
test('gen one empty class', () {
final Class classDefinition = Class(
name: 'Foobar',
fields: <NamedType>[],
);
final Root root = Root(
apis: <Api>[],
classes: <Class>[classDefinition],
enums: <Enum>[],
);
final StringBuffer sink = StringBuffer();
const KotlinOptions kotlinOptions = KotlinOptions();
const KotlinGenerator generator = KotlinGenerator();
generator.generate(
kotlinOptions,
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final String code = sink.toString();

/// The generated class should not be data class
expect(code, isNot(contains('data class')));
});
}
Loading