diff --git a/.agents/docs-and-formatting.md b/.agents/docs-and-formatting.md
index acfa09fede..7d29e77b8f 100644
--- a/.agents/docs-and-formatting.md
+++ b/.agents/docs-and-formatting.md
@@ -13,6 +13,8 @@ Load this file when changing documentation, public APIs, protocol specs, benchma
## Rules
+- Do not format Markdown under `tasks/`, including task design, plan, progress, state, history,
+ and lessons files. These files are agent working state rather than repository documentation.
- Update the relevant docs under `docs/` when important public APIs change.
- Update `docs/specification/**` when protocol behavior changes.
- Keep examples working and aligned with the current API and protocol behavior.
@@ -32,8 +34,6 @@ Load this file when changing documentation, public APIs, protocol specs, benchma
## Formatting Commands
- Markdown: `prettier --write `
-- Do not format Markdown under `tasks/`, including task design, plan, progress, state, history,
- and lessons files. These files are agent working state rather than repository documentation.
- Python code, including `compiler/`, `benchmarks/`, `integration_tests/`, and `python/`:
`python -m ruff format ` and
`python -m ruff check --fix `
diff --git a/README.md b/README.md
index fdef527b63..7d019aa1f4 100644
--- a/README.md
+++ b/README.md
@@ -118,7 +118,7 @@ For more detailed benchmarks and methodology, see [Go Benchmark](benchmarks/go).
-For more detailed benchmarks and methodology, see [Python](benchmarks/python).
+For more detailed benchmarks and methodology, see [Python Benchmarks](benchmarks/python).
### JavaScript/NodeJS Serialization Performance
diff --git a/dart/packages/fory-test/lib/entity/xlang_test_manual.dart b/dart/packages/fory-test/lib/entity/xlang_test_manual.dart
index 821045e973..f1f1f2e5ec 100644
--- a/dart/packages/fory-test/lib/entity/xlang_test_manual.dart
+++ b/dart/packages/fory-test/lib/entity/xlang_test_manual.dart
@@ -22,7 +22,6 @@ library;
// ignore_for_file: implementation_imports, invalid_use_of_internal_member
import 'package:fory/fory.dart';
-import 'package:fory/src/serializer/serializer_support.dart';
import 'xlang_test_models.dart';
@@ -166,43 +165,17 @@ const List _refOverrideContainerForyFieldInfo =
final GeneratedStructRegistration
_refOverrideContainerForyRegistration =
GeneratedStructRegistration(
- fieldWritersBySlot: >[
- _writeRefOverrideContainerField0,
- _writeRefOverrideContainerField1,
- _writeRefOverrideContainerField2,
- ],
type: RefOverrideContainer,
serializerFactory: _RefOverrideContainerForySerializer.new,
evolving: true,
+ needsRootRef: true,
+ usesNestedTypeDefinitions: true,
fields: _refOverrideContainerForyFieldInfo,
);
-void _writeRefOverrideContainerField0(
- WriteContext context,
- GeneratedStructFieldInfo field,
- RefOverrideContainer value,
-) {
- writeGeneratedStructFieldInfoValue(context, field, value.listField);
-}
-
-void _writeRefOverrideContainerField1(
- WriteContext context,
- GeneratedStructFieldInfo field,
- RefOverrideContainer value,
-) {
- writeGeneratedStructFieldInfoValue(context, field, value.setField);
-}
-
-void _writeRefOverrideContainerField2(
- WriteContext context,
- GeneratedStructFieldInfo field,
- RefOverrideContainer value,
-) {
- writeGeneratedStructFieldInfoValue(context, field, value.mapField);
-}
-
final class _RefOverrideContainerForySerializer
- extends Serializer {
+ extends Serializer
+ implements GeneratedStructSerializer {
List? _generatedFields;
_RefOverrideContainerForySerializer();
@@ -223,67 +196,67 @@ final class _RefOverrideContainerForySerializer
@override
void write(WriteContext context, RefOverrideContainer value) {
- final slots = generatedStructWriteSlots(context);
- if (slots == null) {
- final fields = _writeFields(context);
- writeGeneratedStructFieldInfoValue(context, fields[0], value.listField);
- writeGeneratedStructFieldInfoValue(context, fields[1], value.setField);
- writeGeneratedStructFieldInfoValue(context, fields[2], value.mapField);
- return;
- }
- final writers = _refOverrideContainerForyRegistration.fieldWritersBySlot;
- for (final field in slots.orderedFields) {
- writers[field.slot](context, field, value);
- }
+ final fields = _writeFields(context);
+ writeGeneratedStructFieldInfoValue(context, fields[0], value.listField);
+ writeGeneratedStructFieldInfoValue(context, fields[1], value.setField);
+ writeGeneratedStructFieldInfoValue(context, fields[2], value.mapField);
}
@override
RefOverrideContainer read(ReadContext context) {
- final slots = generatedStructReadSlots(context);
final value = RefOverrideContainer();
- context.reference(value);
- if (slots == null) {
- final fields = _readFields(context);
- value.listField = _readRefOverrideContainerListField(
- readGeneratedStructFieldInfoValue(context, fields[0], value.listField),
- value.listField,
- );
- value.setField = _readRefOverrideContainerSetField(
- readGeneratedStructFieldInfoValue(context, fields[1], value.setField),
- value.setField,
- );
- value.mapField = _readRefOverrideContainerMapField(
- readGeneratedStructFieldInfoValue(context, fields[2], value.mapField),
- value.mapField,
- );
- return value;
- }
- if (slots.containsSlot(0)) {
- final rawRefOverrideContainer0 = slots.valueForSlot(0);
- value.listField = _readRefOverrideContainerListField(
- rawRefOverrideContainer0 is DeferredReadRef
- ? context.getReadRef(rawRefOverrideContainer0.id)
- : rawRefOverrideContainer0,
- value.listField,
- );
- }
- if (slots.containsSlot(1)) {
- final rawRefOverrideContainer1 = slots.valueForSlot(1);
- value.setField = _readRefOverrideContainerSetField(
- rawRefOverrideContainer1 is DeferredReadRef
- ? context.getReadRef(rawRefOverrideContainer1.id)
- : rawRefOverrideContainer1,
- value.setField,
- );
- }
- if (slots.containsSlot(2)) {
- final rawRefOverrideContainer2 = slots.valueForSlot(2);
- value.mapField = _readRefOverrideContainerMapField(
- rawRefOverrideContainer2 is DeferredReadRef
- ? context.getReadRef(rawRefOverrideContainer2.id)
- : rawRefOverrideContainer2,
- value.mapField,
- );
+ final fields = _readFields(context);
+ value.listField = _readRefOverrideContainerListField(
+ readGeneratedStructFieldInfoValue(context, fields[0], value.listField),
+ value.listField,
+ );
+ value.setField = _readRefOverrideContainerSetField(
+ readGeneratedStructFieldInfoValue(context, fields[1], value.setField),
+ value.setField,
+ );
+ value.mapField = _readRefOverrideContainerMapField(
+ readGeneratedStructFieldInfoValue(context, fields[2], value.mapField),
+ value.mapField,
+ );
+ return value;
+ }
+
+ @override
+ RefOverrideContainer readCompatibleStruct(
+ ReadContext context,
+ CompatibleStructReadLayout layout,
+ ) {
+ final value = RefOverrideContainer();
+ for (var index = 0; index < layout.fieldCount; index += 1) {
+ final field = layout.localFieldAt(index);
+ if (field == null) {
+ skipGeneratedCompatibleStructField(context, layout, index);
+ continue;
+ }
+ switch (field.index) {
+ case 0:
+ value.listField = _readRefOverrideContainerListField(
+ readGeneratedCompatibleStructField(context, layout, index),
+ value.listField,
+ );
+ break;
+ case 1:
+ value.setField = _readRefOverrideContainerSetField(
+ readGeneratedCompatibleStructField(context, layout, index),
+ value.setField,
+ );
+ break;
+ case 2:
+ value.mapField = _readRefOverrideContainerMapField(
+ readGeneratedCompatibleStructField(context, layout, index),
+ value.mapField,
+ );
+ break;
+ default:
+ throw StateError(
+ 'Compatible field index is out of range for RefOverrideContainer.',
+ );
+ }
}
return value;
}
diff --git a/dart/packages/fory-test/test/compatible_struct_slots_test.dart b/dart/packages/fory-test/test/compatible_struct_read_test.dart
similarity index 96%
rename from dart/packages/fory-test/test/compatible_struct_slots_test.dart
rename to dart/packages/fory-test/test/compatible_struct_read_test.dart
index bf2f3a216a..478bf21540 100644
--- a/dart/packages/fory-test/test/compatible_struct_slots_test.dart
+++ b/dart/packages/fory-test/test/compatible_struct_read_test.dart
@@ -22,7 +22,7 @@ import 'package:fory_test/entity/xlang_test_models.dart';
import 'package:test/test.dart';
void main() {
- test('compatible named struct round trip scopes nested struct slots', () {
+ test('compatible named struct round trip preserves nested struct fields', () {
final fory = Fory(compatible: true);
registerXlangType(
fory,
diff --git a/dart/packages/fory/lib/src/codegen/fory_generator.dart b/dart/packages/fory/lib/src/codegen/fory_generator.dart
index 02483ea7d7..8ca52f903e 100644
--- a/dart/packages/fory/lib/src/codegen/fory_generator.dart
+++ b/dart/packages/fory/lib/src/codegen/fory_generator.dart
@@ -460,17 +460,23 @@ final class ForyGenerator extends Generator {
final hasRuntimeFastPath = structSpec.fields.any(
(field) => !_usesDirectGeneratedBasicFastPath(field),
);
- final directCursorRuns = _directGeneratedWriteReservationRuns(
+ final writeUsesBuffer = structSpec.fields.any(
+ _directGeneratedBasicWriteNeedsBuffer,
+ );
+ final readUsesBuffer = structSpec.fields.any(
+ _directGeneratedBasicReadNeedsBuffer,
+ );
+ final directPrimitiveRuns = _directGeneratedPrimitiveRuns(
structSpec.fields,
);
- final directCursorRunByStart = {
- for (final run in directCursorRuns) run.start: run,
+ final directPrimitiveRunByStart = {
+ for (final run in directPrimitiveRuns) run.start: run,
};
- final directCursorRunByEnd = {
- for (final run in directCursorRuns) run.end: run,
+ final directPrimitiveRunByEnd = {
+ for (final run in directPrimitiveRuns) run.end: run,
};
- final directCursorStartByIndex = {
- for (final run in directCursorRuns)
+ final directPrimitiveRunStartByIndex = {
+ for (final run in directPrimitiveRuns)
for (var index = run.start; index <= run.end; index += 1)
index: run.start,
};
@@ -484,79 +490,24 @@ final class ForyGenerator extends Generator {
output
..writeln('];')
..writeln()
- ..writeln(
- 'typedef _${structSpec.name}FieldWriter = GeneratedStructFieldInfoWriter<${structSpec.name}>;',
- );
- if (structSpec.constructorPlan.mode == _ConstructorMode.mutable) {
- output.writeln(
- 'typedef _${structSpec.name}FieldReader = GeneratedStructFieldInfoReader<${structSpec.name}>;',
- );
- }
- output.writeln();
- for (var index = 0; index < structSpec.fields.length; index += 1) {
- final field = structSpec.fields[index];
- final fieldValue =
- _generatedFieldInfoWriteValueExpression(field, 'value.${field.name}');
- output
- ..writeln(
- 'void _write${structSpec.name}Field$index(WriteContext context, GeneratedStructFieldInfo field, ${structSpec.name} value) {',
- )
- ..writeln(
- ' writeGeneratedStructFieldInfoValue(context, field, $fieldValue);',
- )
- ..writeln('}')
- ..writeln();
- }
- if (structSpec.constructorPlan.mode == _ConstructorMode.mutable) {
- for (var index = 0; index < structSpec.fields.length; index += 1) {
- final field = structSpec.fields[index];
- final readerFunctionName = field.readerFunctionName(structSpec.name);
- output
- ..writeln(
- 'void _read${structSpec.name}Field$index(ReadContext context, ${structSpec.name} value, Object? rawValue) {',
- )
- ..writeln(
- ' value.${field.name} = $readerFunctionName(${_slotResolvedRawExpression('rawValue')}, value.${field.name});',
- )
- ..writeln('}')
- ..writeln();
- }
- }
- output
..writeln(
'final GeneratedStructRegistration<${structSpec.name}> $registrationName = GeneratedStructRegistration<${structSpec.name}>(',
- )
- ..writeln(' fieldWritersBySlot: <_${structSpec.name}FieldWriter>[');
- for (var index = 0; index < structSpec.fields.length; index += 1) {
- output.writeln(' _write${structSpec.name}Field$index,');
- }
- output
- ..writeln(' ],')
- ..writeln(
- structSpec.constructorPlan.mode == _ConstructorMode.mutable
- ? ' compatibleFactory: ${structSpec.name}.new,'
- : ' compatibleFactory: null,',
- );
- if (structSpec.constructorPlan.mode == _ConstructorMode.mutable) {
- output.writeln(
- ' compatibleReadersBySlot: <_${structSpec.name}FieldReader>[',
);
- for (var index = 0; index < structSpec.fields.length; index += 1) {
- output.writeln(' _read${structSpec.name}Field$index,');
- }
- output.writeln(' ],');
- } else {
- output.writeln(' compatibleReadersBySlot: null,');
- }
output
..writeln(' type: ${structSpec.name},')
..writeln(' serializerFactory: _${structSpec.name}ForySerializer.new,')
..writeln(' evolving: ${structSpec.evolving},')
+ ..writeln(
+ ' needsRootRef: ${_structNeedsEarlyReadReference(structSpec)},',
+ )
+ ..writeln(
+ ' usesNestedTypeDefinitions: ${_structUsesNestedTypeDefinitions(structSpec)},',
+ )
..writeln(' fields: $metadataListName,')
..writeln(');')
..writeln()
..writeln(
- 'final class $serializerClassName extends Serializer<${structSpec.name}> {',
+ 'final class $serializerClassName extends Serializer<${structSpec.name}> implements GeneratedStructSerializer<${structSpec.name}> {',
)
..writeln(' List? _generatedFields;')
..writeln()
@@ -586,10 +537,8 @@ final class ForyGenerator extends Generator {
..writeln(' @override')
..writeln(
' void write(WriteContext context, ${structSpec.name} value) {',
- )
- ..writeln(' final slots = generatedStructWriteSlots(context);')
- ..writeln(' if (slots == null) {');
- if (directCursorRuns.isNotEmpty) {
+ );
+ if (writeUsesBuffer) {
output.writeln(' final buffer = context.buffer;');
}
if (hasRuntimeFastPath) {
@@ -597,15 +546,23 @@ final class ForyGenerator extends Generator {
}
for (var index = 0; index < structSpec.fields.length; index += 1) {
final field = structSpec.fields[index];
- final directCursorRun = directCursorRunByStart[index];
- if (directCursorRun != null) {
- output.writeln(
- ' final cursor$index = GeneratedWriteCursor.reserve(buffer, ${directCursorRun.bytes});',
+ final directPrimitiveRun = directPrimitiveRunByStart[index];
+ if (directPrimitiveRun != null) {
+ _writeDirectGeneratedWriteRunStart(
+ output,
+ structSpec.fields,
+ directPrimitiveRun,
+ ' ',
);
}
if (_usesReservedGeneratedFastPath(field)) {
- output.writeln(
- ' ${_directGeneratedCursorWriteStatement(field, 'cursor${directCursorStartByIndex[index]}', 'value.${field.name}')};',
+ _writeDirectGeneratedBufferWriteStatement(
+ output,
+ field,
+ directPrimitiveRunStartByIndex[index]!,
+ index,
+ 'value.${field.name}',
+ ' ',
);
} else if (_usesDirectGeneratedBasicFastPath(field)) {
output.writeln(
@@ -624,18 +581,16 @@ final class ForyGenerator extends Generator {
' writeGeneratedStructFieldInfoValue(context, fields[$index], $fieldValue);',
);
}
- final directCursorEndRun = directCursorRunByEnd[index];
- if (directCursorEndRun != null) {
- output.writeln(' cursor${directCursorEndRun.start}.finish();');
+ final directPrimitiveEndRun = directPrimitiveRunByEnd[index];
+ if (directPrimitiveEndRun != null) {
+ _writeDirectGeneratedWriteRunEnd(
+ output,
+ directPrimitiveEndRun,
+ ' ',
+ );
}
}
output
- ..writeln(' return;')
- ..writeln(' }')
- ..writeln(' final writers = $registrationName.fieldWritersBySlot;')
- ..writeln(' for (final field in slots.orderedFields) {')
- ..writeln(' writers[field.slot](context, field, value);')
- ..writeln(' }')
..writeln(' }')
..writeln()
..writeln(' @override')
@@ -643,12 +598,14 @@ final class ForyGenerator extends Generator {
switch (structSpec.constructorPlan.mode) {
case _ConstructorMode.mutable:
- output
- ..writeln(' final slots = generatedStructReadSlots(context);')
- ..writeln(' final value = ${structSpec.name}();')
- ..writeln(' context.reference(value);')
- ..writeln(' if (slots == null) {');
- if (directCursorRuns.isNotEmpty) {
+ output.writeln(' final value = ${structSpec.name}();');
+ if (_structNeedsEarlyReadReference(structSpec)) {
+ output
+ ..writeln(' if (context.hasPreservedRefId) {')
+ ..writeln(' context.reference(value);')
+ ..writeln(' }');
+ }
+ if (readUsesBuffer) {
output.writeln(' final buffer = context.buffer;');
}
if (hasRuntimeFastPath) {
@@ -657,15 +614,23 @@ final class ForyGenerator extends Generator {
for (var index = 0; index < structSpec.fields.length; index += 1) {
final field = structSpec.fields[index];
final readerFunctionName = field.readerFunctionName(structSpec.name);
- final directCursorRun = directCursorRunByStart[index];
- if (directCursorRun != null) {
- output.writeln(
- ' final cursor$index = GeneratedReadCursor.start(buffer);',
+ final directPrimitiveRun = directPrimitiveRunByStart[index];
+ if (directPrimitiveRun != null) {
+ _writeDirectGeneratedReadRunStart(
+ output,
+ structSpec.fields,
+ directPrimitiveRun,
+ ' ',
);
}
if (_usesReservedGeneratedFastPath(field)) {
- output.writeln(
- ' value.${field.name} = ${_directGeneratedCursorReadExpression(field, 'cursor${directCursorStartByIndex[index]}')};',
+ _writeDirectGeneratedBufferReadStatement(
+ output,
+ field,
+ directPrimitiveRunStartByIndex[index]!,
+ index,
+ 'value.${field.name}',
+ ' ',
);
} else if (_usesDirectGeneratedBasicFastPath(field)) {
output.writeln(
@@ -688,31 +653,18 @@ final class ForyGenerator extends Generator {
' value.${field.name} = $readerFunctionName(readGeneratedStructFieldInfoValue(context, fields[$index], value.${field.name}), value.${field.name});',
);
}
- final directCursorEndRun = directCursorRunByEnd[index];
- if (directCursorEndRun != null) {
- output.writeln(' cursor${directCursorEndRun.start}.finish();');
+ final directPrimitiveEndRun = directPrimitiveRunByEnd[index];
+ if (directPrimitiveEndRun != null) {
+ _writeDirectGeneratedReadRunEnd(
+ output,
+ directPrimitiveEndRun,
+ ' ',
+ );
}
}
- output.writeln(' return value;');
- output.writeln(' }');
- for (var index = 0; index < structSpec.fields.length; index += 1) {
- final field = structSpec.fields[index];
- final readerFunctionName = field.readerFunctionName(structSpec.name);
- final rawValueName = 'raw${structSpec.name}$index';
- output.writeln(' if (slots.containsSlot($index)) {');
- output.writeln(
- ' final $rawValueName = slots.valueForSlot($index);',
- );
- output.writeln(
- ' value.${field.name} = $readerFunctionName(${_slotResolvedRawExpression(rawValueName)}, value.${field.name});',
- );
- output.writeln(' }');
- }
output.writeln(' return value;');
case _ConstructorMode.constructor:
- output.writeln(' final slots = generatedStructReadSlots(context);');
- output.writeln(' if (slots == null) {');
- if (directCursorRuns.isNotEmpty) {
+ if (readUsesBuffer) {
output.writeln(' final buffer = context.buffer;');
}
if (hasRuntimeFastPath) {
@@ -721,15 +673,23 @@ final class ForyGenerator extends Generator {
for (var index = 0; index < structSpec.fields.length; index += 1) {
final field = structSpec.fields[index];
final readerFunctionName = field.readerFunctionName(structSpec.name);
- final directCursorRun = directCursorRunByStart[index];
- if (directCursorRun != null) {
- output.writeln(
- ' final cursor$index = GeneratedReadCursor.start(buffer);',
+ final directPrimitiveRun = directPrimitiveRunByStart[index];
+ if (directPrimitiveRun != null) {
+ _writeDirectGeneratedReadRunStart(
+ output,
+ structSpec.fields,
+ directPrimitiveRun,
+ ' ',
);
}
if (_usesReservedGeneratedFastPath(field)) {
- output.writeln(
- ' final ${field.displayType} ${field.localName} = ${_directGeneratedCursorReadExpression(field, 'cursor${directCursorStartByIndex[index]}')};',
+ _writeDirectGeneratedBufferReadStatement(
+ output,
+ field,
+ directPrimitiveRunStartByIndex[index]!,
+ index,
+ 'final ${field.displayType} ${field.localName}',
+ ' ',
);
} else if (_usesDirectGeneratedBasicFastPath(field)) {
output.writeln(
@@ -752,15 +712,17 @@ final class ForyGenerator extends Generator {
' final ${field.displayType} ${field.localName} = $readerFunctionName(readGeneratedStructFieldInfoValue(context, fields[$index]));',
);
}
- final directCursorEndRun = directCursorRunByEnd[index];
- if (directCursorEndRun != null) {
- output.writeln(' cursor${directCursorEndRun.start}.finish();');
+ final directPrimitiveEndRun = directPrimitiveRunByEnd[index];
+ if (directPrimitiveEndRun != null) {
+ _writeDirectGeneratedReadRunEnd(
+ output,
+ directPrimitiveEndRun,
+ ' ',
+ );
}
}
final constructorInvocation = _constructorInvocation(structSpec);
- output
- ..writeln(' final value = $constructorInvocation;')
- ..writeln(' context.reference(value);');
+ output.writeln(' final value = $constructorInvocation;');
for (final fieldName
in structSpec.constructorPlan.postConstructionFieldNames) {
final field = structSpec.fields.firstWhere(
@@ -768,48 +730,12 @@ final class ForyGenerator extends Generator {
);
output.writeln(' value.${field.name} = ${field.localName};');
}
- output.writeln(' return value;');
- // Slow path: schema-evolution slots present. Use `late final` so each
- // field can be conditionally assigned from its slot or read fresh.
- output.writeln(' }');
- for (var index = 0; index < structSpec.fields.length; index += 1) {
- final field = structSpec.fields[index];
- output.writeln(
- ' late final ${field.displayType} ${field.localName};',
- );
- }
- for (var index = 0; index < structSpec.fields.length; index += 1) {
- final field = structSpec.fields[index];
- final readerFunctionName = field.readerFunctionName(structSpec.name);
- final rawValueName = 'raw${structSpec.name}$index';
- output.writeln(' if (slots.containsSlot($index)) {');
- output.writeln(
- ' final $rawValueName = slots.valueForSlot($index);',
- );
- output.writeln(
- ' ${field.localName} = $readerFunctionName(${_slotResolvedRawExpression(rawValueName)});',
- );
- output.writeln(' } else {');
- output.writeln(
- ' ${field.localName} = $readerFunctionName(null);',
- );
- output.writeln(' }');
- }
- output
- ..writeln(' final value = $constructorInvocation;')
- ..writeln(' context.reference(value);');
- for (final fieldName
- in structSpec.constructorPlan.postConstructionFieldNames) {
- final field = structSpec.fields.firstWhere(
- (item) => item.name == fieldName,
- );
- output.writeln(' value.${field.name} = ${field.localName};');
- }
output.writeln(' return value;');
}
+ output.writeln(' }');
+ _writeCompatibleStructReadMethod(output, structSpec);
output
- ..writeln(' }')
..writeln('}')
..writeln();
@@ -830,6 +756,114 @@ final class ForyGenerator extends Generator {
}
}
+ void _writeCompatibleStructReadMethod(
+ StringBuffer output,
+ _GeneratedStructSpec structSpec,
+ ) {
+ output
+ ..writeln()
+ ..writeln(' @override')
+ ..writeln(
+ ' ${structSpec.name} readCompatibleStruct(ReadContext context, CompatibleStructReadLayout layout) {',
+ );
+ switch (structSpec.constructorPlan.mode) {
+ case _ConstructorMode.mutable:
+ output.writeln(' final value = ${structSpec.name}();');
+ if (_structNeedsEarlyReadReference(structSpec)) {
+ output
+ ..writeln(' if (context.hasPreservedRefId) {')
+ ..writeln(' context.reference(value);')
+ ..writeln(' }');
+ }
+ output
+ ..writeln(
+ ' for (var index = 0; index < layout.fieldCount; index += 1) {',
+ )
+ ..writeln(' final field = layout.localFieldAt(index);')
+ ..writeln(' if (field == null) {')
+ ..writeln(
+ ' skipGeneratedCompatibleStructField(context, layout, index);',
+ )
+ ..writeln(' continue;')
+ ..writeln(' }')
+ ..writeln(' switch (field.index) {');
+ for (var index = 0; index < structSpec.fields.length; index += 1) {
+ final field = structSpec.fields[index];
+ final readerFunctionName = field.readerFunctionName(structSpec.name);
+ output
+ ..writeln(' case $index:')
+ ..writeln(
+ ' value.${field.name} = $readerFunctionName(readGeneratedCompatibleStructField(context, layout, index), value.${field.name});',
+ )
+ ..writeln(' break;');
+ }
+ output
+ ..writeln(' default:')
+ ..writeln(
+ " throw StateError('Compatible field index is out of range for ${structSpec.name}.');",
+ )
+ ..writeln(' }')
+ ..writeln(' }')
+ ..writeln(' return value;');
+ case _ConstructorMode.constructor:
+ for (var index = 0; index < structSpec.fields.length; index += 1) {
+ final field = structSpec.fields[index];
+ output
+ ..writeln(' late final ${field.displayType} ${field.localName};')
+ ..writeln(' var hasField$index = false;');
+ }
+ output
+ ..writeln(
+ ' for (var index = 0; index < layout.fieldCount; index += 1) {',
+ )
+ ..writeln(' final field = layout.localFieldAt(index);')
+ ..writeln(' if (field == null) {')
+ ..writeln(
+ ' skipGeneratedCompatibleStructField(context, layout, index);',
+ )
+ ..writeln(' continue;')
+ ..writeln(' }')
+ ..writeln(' switch (field.index) {');
+ for (var index = 0; index < structSpec.fields.length; index += 1) {
+ final field = structSpec.fields[index];
+ final readerFunctionName = field.readerFunctionName(structSpec.name);
+ output
+ ..writeln(' case $index:')
+ ..writeln(
+ ' ${field.localName} = $readerFunctionName(readGeneratedCompatibleStructField(context, layout, index));',
+ )
+ ..writeln(' hasField$index = true;')
+ ..writeln(' break;');
+ }
+ output
+ ..writeln(' default:')
+ ..writeln(
+ " throw StateError('Compatible field index is out of range for ${structSpec.name}.');",
+ )
+ ..writeln(' }')
+ ..writeln(' }');
+ for (var index = 0; index < structSpec.fields.length; index += 1) {
+ final field = structSpec.fields[index];
+ final readerFunctionName = field.readerFunctionName(structSpec.name);
+ output
+ ..writeln(' if (!hasField$index) {')
+ ..writeln(' ${field.localName} = $readerFunctionName(null);')
+ ..writeln(' }');
+ }
+ final constructorInvocation = _constructorInvocation(structSpec);
+ output.writeln(' final value = $constructorInvocation;');
+ for (final fieldName
+ in structSpec.constructorPlan.postConstructionFieldNames) {
+ final field = structSpec.fields.firstWhere(
+ (item) => item.name == fieldName,
+ );
+ output.writeln(' value.${field.name} = ${field.localName};');
+ }
+ output.writeln(' return value;');
+ }
+ output.writeln(' }');
+ }
+
void _writeRegistrationHelpers(
StringBuffer output, {
required List<_GeneratedEnumSpec> enumSpecs,
@@ -934,10 +968,6 @@ final class ForyGenerator extends Generator {
return '${structSpec.name}($arguments)';
}
- String _slotResolvedRawExpression(String rawValueExpression) {
- return 'resolveGeneratedSlotRawValue(context, $rawValueExpression)';
- }
-
bool _isSkipped(FieldElement field) {
final annotation = _fieldAnnotationOf(field);
if (annotation == null) {
@@ -1184,6 +1214,66 @@ GeneratedFieldType(
field.fieldType.typeId == TypeIds.enumById;
}
+ bool _directGeneratedBasicWriteNeedsBuffer(_GeneratedFieldSpec field) {
+ if (!_usesDirectGeneratedBasicFastPath(field)) {
+ return false;
+ }
+ switch (field.fieldType.typeId) {
+ case TypeIds.string:
+ case TypeIds.binary:
+ case TypeIds.decimal:
+ case TypeIds.date:
+ case TypeIds.duration:
+ case TypeIds.timestamp:
+ case TypeIds.boolArray:
+ case TypeIds.int8Array:
+ case TypeIds.int16Array:
+ case TypeIds.int32Array:
+ case TypeIds.int64Array:
+ case TypeIds.uint8Array:
+ case TypeIds.uint16Array:
+ case TypeIds.uint32Array:
+ case TypeIds.uint64Array:
+ case TypeIds.float16Array:
+ case TypeIds.bfloat16Array:
+ case TypeIds.float32Array:
+ case TypeIds.float64Array:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ bool _directGeneratedBasicReadNeedsBuffer(_GeneratedFieldSpec field) {
+ if (!_usesDirectGeneratedBasicFastPath(field)) {
+ return false;
+ }
+ switch (field.fieldType.typeId) {
+ case TypeIds.string:
+ case TypeIds.binary:
+ case TypeIds.decimal:
+ case TypeIds.date:
+ case TypeIds.duration:
+ case TypeIds.timestamp:
+ case TypeIds.boolArray:
+ case TypeIds.int8Array:
+ case TypeIds.int16Array:
+ case TypeIds.int32Array:
+ case TypeIds.int64Array:
+ case TypeIds.uint8Array:
+ case TypeIds.uint16Array:
+ case TypeIds.uint32Array:
+ case TypeIds.uint64Array:
+ case TypeIds.float16Array:
+ case TypeIds.bfloat16Array:
+ case TypeIds.float32Array:
+ case TypeIds.float64Array:
+ return false;
+ default:
+ return true;
+ }
+ }
+
bool _usesDirectGeneratedDeclaredReadFastPath(_GeneratedFieldSpec field) {
if (field.fieldType.nullable ||
field.fieldType.ref ||
@@ -1264,17 +1354,20 @@ GeneratedFieldType(
);
}
- List<_DirectGeneratedWriteReservationRun>
- _directGeneratedWriteReservationRuns(List<_GeneratedFieldSpec> fields) {
- final runs = <_DirectGeneratedWriteReservationRun>[];
+ List<_DirectGeneratedPrimitiveRun> _directGeneratedPrimitiveRuns(
+ List<_GeneratedFieldSpec> fields,
+ ) {
+ final runs = <_DirectGeneratedPrimitiveRun>[];
int? start;
var bytes = 0;
for (var index = 0; index < fields.length; index += 1) {
- final fieldBytes = _directGeneratedWriteReservationBytes(fields[index]);
+ final fieldBytes = _directGeneratedPrimitiveReservationBytes(
+ fields[index],
+ );
if (fieldBytes == null) {
if (start != null) {
runs.add(
- _DirectGeneratedWriteReservationRun(start, index - 1, bytes),
+ _DirectGeneratedPrimitiveRun(start, index - 1, bytes),
);
start = null;
bytes = 0;
@@ -1286,17 +1379,17 @@ GeneratedFieldType(
}
if (start != null) {
runs.add(
- _DirectGeneratedWriteReservationRun(start, fields.length - 1, bytes),
+ _DirectGeneratedPrimitiveRun(start, fields.length - 1, bytes),
);
}
return runs;
}
bool _usesReservedGeneratedFastPath(_GeneratedFieldSpec field) {
- return _directGeneratedWriteReservationBytes(field) != null;
+ return _directGeneratedPrimitiveReservationBytes(field) != null;
}
- int? _directGeneratedWriteReservationBytes(_GeneratedFieldSpec field) {
+ int? _directGeneratedPrimitiveReservationBytes(_GeneratedFieldSpec field) {
if (!_usesDirectGeneratedBasicFastPath(field)) {
return null;
}
@@ -1314,30 +1407,327 @@ GeneratedFieldType(
case TypeIds.uint32:
case TypeIds.float32:
return 4;
- case TypeIds.date:
- return 10;
- case TypeIds.int64:
- case TypeIds.uint64:
case TypeIds.float64:
return 8;
- case TypeIds.duration:
- return 14;
- case TypeIds.timestamp:
- return 12;
case TypeIds.varInt32:
case TypeIds.varUint32:
- case TypeIds.enumById:
return 5;
- case TypeIds.varInt64:
- case TypeIds.taggedInt64:
- case TypeIds.varUint64:
- case TypeIds.taggedUint64:
- return 10;
default:
return null;
}
}
+ bool _directGeneratedRunUsesBytes(
+ List<_GeneratedFieldSpec> fields,
+ _DirectGeneratedPrimitiveRun run,
+ ) {
+ for (var index = run.start; index <= run.end; index += 1) {
+ switch (fields[index].fieldType.typeId) {
+ case TypeIds.boolType:
+ case TypeIds.varInt32:
+ case TypeIds.varUint32:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _directGeneratedRunUsesView(
+ List<_GeneratedFieldSpec> fields,
+ _DirectGeneratedPrimitiveRun run,
+ ) {
+ for (var index = run.start; index <= run.end; index += 1) {
+ switch (fields[index].fieldType.typeId) {
+ case TypeIds.boolType:
+ case TypeIds.varInt32:
+ case TypeIds.varUint32:
+ break;
+ default:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void _writeDirectGeneratedWriteRunStart(
+ StringBuffer output,
+ List<_GeneratedFieldSpec> fields,
+ _DirectGeneratedPrimitiveRun run,
+ String indent,
+ ) {
+ output.writeln(
+ '${indent}var offset${run.start} = bufferReserveBytes(buffer, ${run.bytes});',
+ );
+ if (_directGeneratedRunUsesBytes(fields, run)) {
+ output.writeln('${indent}final bytes${run.start} = bufferBytes(buffer);');
+ }
+ if (_directGeneratedRunUsesView(fields, run)) {
+ output
+ .writeln('${indent}final view${run.start} = bufferByteData(buffer);');
+ }
+ }
+
+ void _writeDirectGeneratedReadRunStart(
+ StringBuffer output,
+ List<_GeneratedFieldSpec> fields,
+ _DirectGeneratedPrimitiveRun run,
+ String indent,
+ ) {
+ output.writeln(
+ '${indent}var offset${run.start} = bufferReaderIndex(buffer);',
+ );
+ if (_directGeneratedRunUsesBytes(fields, run)) {
+ output.writeln('${indent}final bytes${run.start} = bufferBytes(buffer);');
+ }
+ if (_directGeneratedRunUsesView(fields, run)) {
+ output
+ .writeln('${indent}final view${run.start} = bufferByteData(buffer);');
+ }
+ }
+
+ void _writeDirectGeneratedWriteRunEnd(
+ StringBuffer output,
+ _DirectGeneratedPrimitiveRun run,
+ String indent,
+ ) {
+ output.writeln(
+ '${indent}bufferSetWriterIndex(buffer, offset${run.start});',
+ );
+ }
+
+ void _writeDirectGeneratedReadRunEnd(
+ StringBuffer output,
+ _DirectGeneratedPrimitiveRun run,
+ String indent,
+ ) {
+ output.writeln(
+ '${indent}bufferSetReaderIndex(buffer, offset${run.start});',
+ );
+ }
+
+ void _writeDirectGeneratedBufferWriteStatement(
+ StringBuffer output,
+ _GeneratedFieldSpec field,
+ int runStart,
+ int fieldIndex,
+ String valueExpression,
+ String indent,
+ ) {
+ final offset = 'offset$runStart';
+ final bytes = 'bytes$runStart';
+ final view = 'view$runStart';
+ final scalar = _directGeneratedScalarExpression(field, valueExpression);
+ switch (field.fieldType.typeId) {
+ case TypeIds.boolType:
+ output
+ ..writeln('$indent$bytes[$offset] = $valueExpression ? 1 : 0;')
+ ..writeln('$indent$offset += 1;');
+ case TypeIds.int8:
+ output
+ ..writeln('$indent$view.setInt8($offset, $scalar);')
+ ..writeln('$indent$offset += 1;');
+ case TypeIds.uint8:
+ output
+ ..writeln('$indent$view.setUint8($offset, $scalar);')
+ ..writeln('$indent$offset += 1;');
+ case TypeIds.int16:
+ output
+ ..writeln(
+ '$indent$view.setInt16($offset, $scalar, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.uint16:
+ output
+ ..writeln(
+ '$indent$view.setUint16($offset, $scalar, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.int32:
+ output
+ ..writeln(
+ '$indent$view.setInt32($offset, $scalar, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 4;');
+ case TypeIds.uint32:
+ output
+ ..writeln(
+ '$indent$view.setUint32($offset, $scalar, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 4;');
+ case TypeIds.float16:
+ output
+ ..writeln(
+ '$indent$view.setUint16($offset, $valueExpression.toBits(), generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.bfloat16:
+ output
+ ..writeln(
+ '$indent$view.setUint16($offset, $valueExpression.toBits(), generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.float32:
+ output
+ ..writeln(
+ '$indent$view.setFloat32($offset, $scalar, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 4;');
+ case TypeIds.float64:
+ output
+ ..writeln(
+ '$indent$view.setFloat64($offset, $scalar, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 8;');
+ case TypeIds.varInt32:
+ final checked = 'value$fieldIndex';
+ final remaining = 'remaining$fieldIndex';
+ output
+ ..writeln('$indent final $checked = $scalar;')
+ ..writeln(
+ '$indent var $remaining = (($checked << 1) ^ ($checked >> 31)).toUnsigned(32);',
+ )
+ ..writeln('$indent while ($remaining >= 0x80) {')
+ ..writeln('$indent $bytes[$offset] = ($remaining & 0x7f) | 0x80;')
+ ..writeln('$indent $offset += 1;')
+ ..writeln('$indent $remaining >>>= 7;')
+ ..writeln('$indent }')
+ ..writeln('$indent $bytes[$offset] = $remaining;')
+ ..writeln('$indent $offset += 1;');
+ case TypeIds.varUint32:
+ final remaining = 'remaining$fieldIndex';
+ output
+ ..writeln('$indent var $remaining = $scalar;')
+ ..writeln('$indent while ($remaining >= 0x80) {')
+ ..writeln('$indent $bytes[$offset] = ($remaining & 0x7f) | 0x80;')
+ ..writeln('$indent $offset += 1;')
+ ..writeln('$indent $remaining >>>= 7;')
+ ..writeln('$indent }')
+ ..writeln('$indent $bytes[$offset] = $remaining;')
+ ..writeln('$indent $offset += 1;');
+ default:
+ throw StateError(
+ 'Unsupported generated direct buffer write fast path for ${field.name}.',
+ );
+ }
+ }
+
+ void _writeDirectGeneratedBufferReadStatement(
+ StringBuffer output,
+ _GeneratedFieldSpec field,
+ int runStart,
+ int fieldIndex,
+ String target,
+ String indent,
+ ) {
+ final offset = 'offset$runStart';
+ final bytes = 'bytes$runStart';
+ final view = 'view$runStart';
+ switch (field.fieldType.typeId) {
+ case TypeIds.boolType:
+ output
+ ..writeln('$indent$target = $bytes[$offset] != 0;')
+ ..writeln('$indent$offset += 1;');
+ case TypeIds.int8:
+ output
+ ..writeln('$indent$target = $view.getInt8($offset);')
+ ..writeln('$indent$offset += 1;');
+ case TypeIds.uint8:
+ output
+ ..writeln('$indent$target = $view.getUint8($offset);')
+ ..writeln('$indent$offset += 1;');
+ case TypeIds.int16:
+ output
+ ..writeln(
+ '$indent$target = $view.getInt16($offset, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.uint16:
+ output
+ ..writeln(
+ '$indent$target = $view.getUint16($offset, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.int32:
+ output
+ ..writeln(
+ '$indent$target = $view.getInt32($offset, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 4;');
+ case TypeIds.uint32:
+ output
+ ..writeln(
+ '$indent$target = $view.getUint32($offset, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 4;');
+ case TypeIds.float16:
+ output
+ ..writeln(
+ '$indent$target = Float16.fromBits($view.getUint16($offset, generatedLittleEndian));',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.bfloat16:
+ output
+ ..writeln(
+ '$indent$target = Bfloat16.fromBits($view.getUint16($offset, generatedLittleEndian));',
+ )
+ ..writeln('$indent$offset += 2;');
+ case TypeIds.float32:
+ final value = '$view.getFloat32($offset, generatedLittleEndian)';
+ output
+ ..writeln(
+ field.type.isDartCoreDouble
+ ? '$indent$target = $value;'
+ : '$indent$target = Float32($value);',
+ )
+ ..writeln('$indent$offset += 4;');
+ case TypeIds.float64:
+ output
+ ..writeln(
+ '$indent$target = $view.getFloat64($offset, generatedLittleEndian);',
+ )
+ ..writeln('$indent$offset += 8;');
+ case TypeIds.varInt32:
+ final result = 'result$fieldIndex';
+ _writeDirectGeneratedVarUint32Read(
+ output, result, bytes, offset, indent);
+ output.writeln(
+ '$indent$target = (($result >>> 1) ^ -($result & 1)).toSigned(32);',
+ );
+ case TypeIds.varUint32:
+ final result = 'result$fieldIndex';
+ _writeDirectGeneratedVarUint32Read(
+ output, result, bytes, offset, indent);
+ output.writeln('$indent$target = $result;');
+ default:
+ throw StateError(
+ 'Unsupported generated direct buffer read fast path for ${field.name}.',
+ );
+ }
+ }
+
+ void _writeDirectGeneratedVarUint32Read(
+ StringBuffer output,
+ String result,
+ String bytes,
+ String offset,
+ String indent,
+ ) {
+ final shift = '${result}Shift';
+ final byte = '${result}Byte';
+ output
+ ..writeln('$indent var $shift = 0;')
+ ..writeln('$indent var $result = 0;')
+ ..writeln('$indent while (true) {')
+ ..writeln('$indent final $byte = $bytes[$offset];')
+ ..writeln('$indent $offset += 1;')
+ ..writeln('$indent $result |= ($byte & 0x7f) << $shift;')
+ ..writeln('$indent if (($byte & 0x80) == 0) {')
+ ..writeln('$indent break;')
+ ..writeln('$indent }')
+ ..writeln('$indent $shift += 7;')
+ ..writeln('$indent }');
+ }
+
String _directGeneratedWriteStatement(
_GeneratedFieldSpec field,
String valueExpression,
@@ -1428,89 +1818,6 @@ GeneratedFieldType(
}
}
- String _directGeneratedCursorWriteStatement(
- _GeneratedFieldSpec field,
- String cursorExpression,
- String valueExpression,
- ) {
- switch (field.fieldType.typeId) {
- case TypeIds.boolType:
- return '$cursorExpression.writeBool($valueExpression)';
- case TypeIds.int8:
- return '$cursorExpression.writeByte(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.int16:
- return '$cursorExpression.writeInt16(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.int32:
- return '$cursorExpression.writeInt32(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.varInt32:
- return '$cursorExpression.writeVarInt32(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.int64:
- if (field.type.isDartCoreInt) {
- return '$cursorExpression.writeInt64FromInt($valueExpression)';
- }
- return '$cursorExpression.writeInt64(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.varInt64:
- if (field.type.isDartCoreInt) {
- return '$cursorExpression.writeVarInt64FromInt($valueExpression)';
- }
- return '$cursorExpression.writeVarInt64(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.taggedInt64:
- if (field.type.isDartCoreInt) {
- return '$cursorExpression.writeTaggedInt64FromInt($valueExpression)';
- }
- return '$cursorExpression.writeTaggedInt64(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.uint8:
- return '$cursorExpression.writeUint8(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.uint16:
- return '$cursorExpression.writeUint16(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.uint32:
- return '$cursorExpression.writeUint32(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.varUint32:
- return '$cursorExpression.writeVarUint32(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.uint64:
- if (field.type.isDartCoreInt) {
- return '$cursorExpression.writeUint64FromInt($valueExpression)';
- }
- return '$cursorExpression.writeUint64(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.varUint64:
- if (field.type.isDartCoreInt) {
- return '$cursorExpression.writeVarUint64FromInt($valueExpression)';
- }
- return '$cursorExpression.writeVarUint64(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.taggedUint64:
- if (field.type.isDartCoreInt) {
- return '$cursorExpression.writeTaggedUint64FromInt($valueExpression)';
- }
- return '$cursorExpression.writeTaggedUint64(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.float16:
- return '$cursorExpression.writeFloat16($valueExpression)';
- case TypeIds.bfloat16:
- return '$cursorExpression.writeBfloat16($valueExpression)';
- case TypeIds.float32:
- return '$cursorExpression.writeFloat32(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.float64:
- return '$cursorExpression.writeFloat64(${_directGeneratedScalarExpression(field, valueExpression)})';
- case TypeIds.date:
- return '$cursorExpression.writeVarInt64($valueExpression.toEpochDay())';
- case TypeIds.duration:
- return '$cursorExpression.writeVarInt64(generatedDurationWireSeconds($valueExpression)); $cursorExpression.writeInt32(generatedDurationWireNanoseconds($valueExpression))';
- case TypeIds.timestamp:
- return _isDateTimeType(field.type)
- ? '$cursorExpression.writeInt64(generatedDateTimeWireSeconds($valueExpression)); $cursorExpression.writeUint32(generatedDateTimeWireNanoseconds($valueExpression))'
- : '$cursorExpression.writeInt64($valueExpression.seconds); $cursorExpression.writeUint32(generatedTimestampWireNanoseconds($valueExpression))';
- case TypeIds.enumById:
- return _enumCursorWriteExpression(
- field.type,
- cursorExpression,
- valueExpression,
- );
- default:
- throw StateError(
- 'Unsupported generated direct cursor write fast path for ${field.name}.',
- );
- }
- }
-
String _directGeneratedReadExpression(_GeneratedFieldSpec field) {
switch (field.fieldType.typeId) {
case TypeIds.boolType:
@@ -1606,7 +1913,7 @@ GeneratedFieldType(
case TypeIds.float64Array:
return 'readGeneratedTypedArrayValue(context, 8, (bytes) => bytes.buffer.asFloat64List(bytes.offsetInBytes, bytes.lengthInBytes ~/ 8))';
case TypeIds.enumById:
- return _enumReadExpression(field.type, 'context');
+ return _enumReadExpression(field.type, 'buffer');
default:
throw StateError(
'Unsupported generated direct read fast path for ${field.name}.',
@@ -1614,80 +1921,6 @@ GeneratedFieldType(
}
}
- String _directGeneratedCursorReadExpression(
- _GeneratedFieldSpec field,
- String cursorExpression,
- ) {
- switch (field.fieldType.typeId) {
- case TypeIds.boolType:
- return '$cursorExpression.readBool()';
- case TypeIds.int8:
- return '$cursorExpression.readByte()';
- case TypeIds.int16:
- return '$cursorExpression.readInt16()';
- case TypeIds.int32:
- return '$cursorExpression.readInt32()';
- case TypeIds.varInt32:
- return '$cursorExpression.readVarInt32()';
- case TypeIds.int64:
- return field.type.isDartCoreInt
- ? '$cursorExpression.readInt64AsInt()'
- : '$cursorExpression.readInt64()';
- case TypeIds.varInt64:
- return field.type.isDartCoreInt
- ? '$cursorExpression.readVarInt64AsInt()'
- : '$cursorExpression.readVarInt64()';
- case TypeIds.taggedInt64:
- return field.type.isDartCoreInt
- ? '$cursorExpression.readTaggedInt64AsInt()'
- : '$cursorExpression.readTaggedInt64()';
- case TypeIds.uint8:
- return '$cursorExpression.readUint8()';
- case TypeIds.uint16:
- return '$cursorExpression.readUint16()';
- case TypeIds.uint32:
- return '$cursorExpression.readUint32()';
- case TypeIds.varUint32:
- return '$cursorExpression.readVarUint32()';
- case TypeIds.uint64:
- return field.type.isDartCoreInt
- ? '$cursorExpression.readUint64AsInt()'
- : '$cursorExpression.readUint64()';
- case TypeIds.varUint64:
- return field.type.isDartCoreInt
- ? '$cursorExpression.readVarUint64AsInt()'
- : '$cursorExpression.readVarUint64()';
- case TypeIds.taggedUint64:
- return field.type.isDartCoreInt
- ? '$cursorExpression.readTaggedUint64AsInt()'
- : '$cursorExpression.readTaggedUint64()';
- case TypeIds.float16:
- return '$cursorExpression.readFloat16()';
- case TypeIds.bfloat16:
- return '$cursorExpression.readBfloat16()';
- case TypeIds.float32:
- return field.type.isDartCoreDouble
- ? '$cursorExpression.readFloat32()'
- : 'Float32($cursorExpression.readFloat32())';
- case TypeIds.float64:
- return '$cursorExpression.readFloat64()';
- case TypeIds.date:
- return 'LocalDate.fromEpochDay($cursorExpression.readVarInt64())';
- case TypeIds.duration:
- return 'readGeneratedDurationFromWire($cursorExpression.readVarInt64(), $cursorExpression.readInt32())';
- case TypeIds.timestamp:
- return _isDateTimeType(field.type)
- ? 'readGeneratedDateTimeFromWire($cursorExpression.readInt64(), $cursorExpression.readUint32())'
- : 'readGeneratedTimestampFromWire($cursorExpression.readInt64(), $cursorExpression.readUint32())';
- case TypeIds.enumById:
- return _enumCursorReadExpression(field.type, cursorExpression);
- default:
- throw StateError(
- 'Unsupported generated direct cursor read fast path for ${field.name}.',
- );
- }
- }
-
String _directGeneratedTypedContainerReadExpression(
String structName,
_GeneratedFieldSpec field,
@@ -1723,7 +1956,7 @@ GeneratedFieldType(
case TypeIds.uint64:
case TypeIds.varUint64:
case TypeIds.taggedUint64:
- return 'Uint64($valueExpression)';
+ return 'generatedCheckedUint64Int($valueExpression)';
default:
return _checkedGeneratedScalarExpression(
field.fieldType.typeId, valueExpression);
@@ -2823,17 +3056,6 @@ GeneratedFieldType(
return 'buffer.writeVarUint32($valueExpression.index)';
}
- String _enumCursorWriteExpression(
- DartType type,
- String cursorExpression,
- String valueExpression,
- ) {
- if (_enumUsesRawValue(type)) {
- return '$cursorExpression.writeVarUint32($valueExpression.rawValue)';
- }
- return '$cursorExpression.writeVarUint32($valueExpression.index)';
- }
-
String _enumReadExpression(DartType type, String contextExpression) {
final typeDisplay = _typeReferenceLiteral(type);
if (_enumUsesRawValue(type)) {
@@ -2842,14 +3064,6 @@ GeneratedFieldType(
return '$typeDisplay.values[$contextExpression.readVarUint32()]';
}
- String _enumCursorReadExpression(DartType type, String cursorExpression) {
- final typeDisplay = _typeReferenceLiteral(type);
- if (_enumUsesRawValue(type)) {
- return '$typeDisplay.fromRawValue($cursorExpression.readVarUint32())';
- }
- return '$typeDisplay.values[$cursorExpression.readVarUint32()]';
- }
-
bool _sameType(DartType left, DartType right) =>
_typeLiteral(_withoutNullability(left)) ==
_typeLiteral(_withoutNullability(right));
@@ -2978,6 +3192,50 @@ GeneratedFieldType(
}
return buffer.toString();
}
+
+ bool _structNeedsEarlyReadReference(_GeneratedStructSpec structSpec) {
+ for (final field in structSpec.fields) {
+ if (_fieldTypeNeedsEarlyReadReference(field.fieldType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _fieldTypeNeedsEarlyReadReference(_GeneratedFieldTypeSpec fieldType) {
+ if (fieldType.ref) {
+ return true;
+ }
+ for (final argument in fieldType.arguments) {
+ if (_fieldTypeNeedsEarlyReadReference(argument)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _structUsesNestedTypeDefinitions(_GeneratedStructSpec structSpec) {
+ for (final field in structSpec.fields) {
+ if (_fieldTypeUsesNestedTypeDefinitions(field.fieldType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _fieldTypeUsesNestedTypeDefinitions(
+ _GeneratedFieldTypeSpec fieldType,
+ ) {
+ if (fieldType.dynamic == true || TypeIds.isUserType(fieldType.typeId)) {
+ return true;
+ }
+ for (final argument in fieldType.arguments) {
+ if (_fieldTypeUsesNestedTypeDefinitions(argument)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
final class _GeneratedEnumSpec {
@@ -3033,12 +3291,12 @@ final class _GeneratedFieldSpec {
String get localName => '_${name}Value';
}
-final class _DirectGeneratedWriteReservationRun {
+final class _DirectGeneratedPrimitiveRun {
final int start;
final int end;
final int bytes;
- const _DirectGeneratedWriteReservationRun(this.start, this.end, this.bytes);
+ const _DirectGeneratedPrimitiveRun(this.start, this.end, this.bytes);
}
final class _GeneratedFieldTypeSpec {
diff --git a/dart/packages/fory/lib/src/codegen/generated_cursor.dart b/dart/packages/fory/lib/src/codegen/generated_cursor.dart
deleted file mode 100644
index 44816f1189..0000000000
--- a/dart/packages/fory/lib/src/codegen/generated_cursor.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-export 'generated_cursor_native.dart'
- if (dart.library.js_interop) 'generated_cursor_web.dart';
diff --git a/dart/packages/fory/lib/src/codegen/generated_cursor_mixin.dart b/dart/packages/fory/lib/src/codegen/generated_cursor_mixin.dart
deleted file mode 100644
index d8aa225336..0000000000
--- a/dart/packages/fory/lib/src/codegen/generated_cursor_mixin.dart
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// ignore_for_file: use_string_in_part_of_directives
-
-part of fory.src.codegen.generated_cursor;
-
-mixin _GeneratedWriteCursorMixin {
- late final Buffer _buffer;
- late final Uint8List _bytes;
- late final ByteData _view;
- int _offset = 0;
-
- void _initWriteCursor(Buffer buffer, int maxBytes) {
- final start = bufferReserveBytes(buffer, maxBytes);
- _buffer = buffer;
- _bytes = bufferBytes(buffer);
- _view = bufferByteData(buffer);
- _offset = start;
- }
-
- void finish() {
- bufferSetWriterIndex(_buffer, _offset);
- }
-
- @pragma('vm:prefer-inline')
- void writeBool(bool value) {
- _bytes[_offset] = value ? 1 : 0;
- _offset += 1;
- }
-
- @pragma('vm:prefer-inline')
- void writeByte(int value) {
- _view.setInt8(_offset, value);
- _offset += 1;
- }
-
- @pragma('vm:prefer-inline')
- void writeUint8(int value) {
- _view.setUint8(_offset, value);
- _offset += 1;
- }
-
- @pragma('vm:prefer-inline')
- void writeInt16(int value) {
- _view.setInt16(_offset, value, Endian.little);
- _offset += 2;
- }
-
- @pragma('vm:prefer-inline')
- void writeUint16(int value) {
- _view.setUint16(_offset, value, Endian.little);
- _offset += 2;
- }
-
- @pragma('vm:prefer-inline')
- void writeInt32(int value) {
- _view.setInt32(_offset, value, Endian.little);
- _offset += 4;
- }
-
- @pragma('vm:prefer-inline')
- void writeUint32(int value) {
- _view.setUint32(_offset, value, Endian.little);
- _offset += 4;
- }
-
- @pragma('vm:prefer-inline')
- void writeFloat16(Float16 value) {
- writeUint16(value.toBits());
- }
-
- @pragma('vm:prefer-inline')
- void writeBfloat16(Bfloat16 value) {
- writeUint16(value.toBits());
- }
-
- @pragma('vm:prefer-inline')
- void writeFloat32(double value) {
- _view.setFloat32(_offset, value, Endian.little);
- _offset += 4;
- }
-
- @pragma('vm:prefer-inline')
- void writeFloat64(double value) {
- _view.setFloat64(_offset, value, Endian.little);
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- void writeVarUint32(int value) {
- var remaining = value;
- while (remaining >= 0x80) {
- _bytes[_offset] = (remaining & 0x7f) | 0x80;
- _offset += 1;
- remaining >>>= 7;
- }
- _bytes[_offset] = remaining;
- _offset += 1;
- }
-
- @pragma('vm:prefer-inline')
- void writeVarInt32(int value) {
- writeVarUint32(((value << 1) ^ (value >> 31)).toUnsigned(32));
- }
-
- void writeVarUint64(Uint64 value);
-}
-
-mixin _GeneratedReadCursorMixin {
- late final Buffer _buffer;
- late final ByteData _view;
- int _offset = 0;
-
- void _initReadCursor(Buffer buffer) {
- _buffer = buffer;
- _view = bufferByteData(buffer);
- _offset = bufferReaderIndex(buffer);
- }
-
- void finish() {
- bufferSetReaderIndex(_buffer, _offset);
- }
-
- @pragma('vm:prefer-inline')
- bool readBool() => readUint8() != 0;
-
- @pragma('vm:prefer-inline')
- int readByte() {
- final value = _view.getInt8(_offset);
- _offset += 1;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readUint8() {
- final value = _view.getUint8(_offset);
- _offset += 1;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readInt16() {
- final value = _view.getInt16(_offset, Endian.little);
- _offset += 2;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readUint16() {
- final value = _view.getUint16(_offset, Endian.little);
- _offset += 2;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readInt32() {
- final value = _view.getInt32(_offset, Endian.little);
- _offset += 4;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readUint32() {
- final value = _view.getUint32(_offset, Endian.little);
- _offset += 4;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- Float16 readFloat16() => Float16.fromBits(readUint16());
-
- @pragma('vm:prefer-inline')
- Bfloat16 readBfloat16() => Bfloat16.fromBits(readUint16());
-
- @pragma('vm:prefer-inline')
- double readFloat32() {
- final value = _view.getFloat32(_offset, Endian.little);
- _offset += 4;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- double readFloat64() {
- final value = _view.getFloat64(_offset, Endian.little);
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readVarUint32() {
- var shift = 0;
- var result = 0;
- while (true) {
- final byte = readUint8();
- result |= (byte & 0x7f) << shift;
- if ((byte & 0x80) == 0) {
- return result;
- }
- shift += 7;
- }
- }
-
- @pragma('vm:prefer-inline')
- int readVarInt32() {
- final value = readVarUint32();
- return ((value >>> 1) ^ -(value & 1)).toSigned(32);
- }
-
- Uint64 readVarUint64();
-}
diff --git a/dart/packages/fory/lib/src/codegen/generated_cursor_native.dart b/dart/packages/fory/lib/src/codegen/generated_cursor_native.dart
deleted file mode 100644
index 482d31d15c..0000000000
--- a/dart/packages/fory/lib/src/codegen/generated_cursor_native.dart
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// ignore_for_file: unnecessary_library_name
-
-library fory.src.codegen.generated_cursor;
-
-import 'dart:typed_data';
-
-import 'package:meta/meta.dart';
-
-import 'package:fory/src/memory/buffer.dart';
-import 'package:fory/src/types/bfloat16.dart';
-import 'package:fory/src/types/float16.dart';
-import 'package:fory/src/types/int64.dart';
-import 'package:fory/src/types/uint64.dart';
-
-part 'generated_cursor_mixin.dart';
-
-@internal
-final class GeneratedWriteCursor with _GeneratedWriteCursorMixin {
- GeneratedWriteCursor._();
-
- factory GeneratedWriteCursor.reserve(Buffer buffer, int maxBytes) {
- return GeneratedWriteCursor._().._initWriteCursor(buffer, maxBytes);
- }
-
- @pragma('vm:prefer-inline')
- void writeInt64(Int64 value) {
- _view.setInt64(_offset, value.toInt(), Endian.little);
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- void writeInt64FromInt(int value) {
- _view.setInt64(_offset, value, Endian.little);
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- void writeUint64(Uint64 value) {
- _view.setInt64(_offset, value.value, Endian.little);
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- void writeUint64FromInt(int value) {
- _view.setInt64(_offset, value.toSigned(64), Endian.little);
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- @override
- void writeVarUint64(Uint64 value) {
- _writeVarUint64Int(value.value);
- }
-
- @pragma('vm:prefer-inline')
- void writeVarUint64FromInt(int value) {
- _writeVarUint64Int(value.toSigned(64));
- }
-
- @pragma('vm:prefer-inline')
- void writeVarInt64(Int64 value) {
- _writeVarUint64Int((value << 1) ^ (value >> 63));
- }
-
- @pragma('vm:prefer-inline')
- void writeVarInt64FromInt(int value) {
- _writeVarUint64Int((value << 1) ^ (value >> 63));
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedInt64(Int64 value) {
- if (value >= -0x40000000 && value <= 0x3fffffff) {
- writeInt32((value.toInt() << 1).toSigned(32));
- return;
- }
- writeUint8(0x01);
- writeInt64(value);
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedInt64FromInt(int value) {
- if (value >= -0x40000000 && value <= 0x3fffffff) {
- writeInt32((value << 1).toSigned(32));
- return;
- }
- writeUint8(0x01);
- writeInt64FromInt(value);
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedUint64(Uint64 value) {
- if (value >= 0 && value <= 0x7fffffff) {
- writeInt32(value.toInt() << 1);
- return;
- }
- writeUint8(0x01);
- writeUint64(value);
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedUint64FromInt(int value) {
- if (value >= 0 && value <= 0x7fffffff) {
- writeInt32(value << 1);
- return;
- }
- writeUint8(0x01);
- writeUint64FromInt(value);
- }
-
- @pragma('vm:prefer-inline')
- void _writeVarUint64Int(int value) {
- var remaining = value;
- for (var index = 0; index < 8; index += 1) {
- final chunk = remaining & 0x7f;
- remaining >>>= 7;
- if (remaining == 0) {
- _bytes[_offset] = chunk;
- _offset += 1;
- return;
- }
- _bytes[_offset] = chunk | 0x80;
- _offset += 1;
- }
- _bytes[_offset] = remaining & 0xff;
- _offset += 1;
- }
-}
-
-@internal
-final class GeneratedReadCursor with _GeneratedReadCursorMixin {
- GeneratedReadCursor._();
-
- factory GeneratedReadCursor.start(Buffer buffer) {
- return GeneratedReadCursor._().._initReadCursor(buffer);
- }
-
- @pragma('vm:prefer-inline')
- Int64 readInt64() {
- final value = Int64(_view.getInt64(_offset, Endian.little));
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readInt64AsInt() {
- final value = _view.getInt64(_offset, Endian.little);
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- Uint64 readUint64() {
- final value = Uint64(_view.getInt64(_offset, Endian.little));
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readUint64AsInt() {
- final value = _view.getUint64(_offset, Endian.little);
- if ((_view.getUint32(_offset + 4, Endian.little) & 0x80000000) != 0) {
- throw StateError(
- 'Uint64 value $value is not representable as a native int.',
- );
- }
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- @override
- Uint64 readVarUint64() {
- var shift = 0;
- var result = Uint64(0);
- while (shift < 56) {
- final byte = readUint8();
- result = result | (Uint64(byte & 0x7f) << shift);
- if ((byte & 0x80) == 0) {
- return result;
- }
- shift += 7;
- }
- return result | (Uint64(readUint8()) << 56);
- }
-
- @pragma('vm:prefer-inline')
- int readVarUint64AsInt() {
- var shift = 0;
- var result = 0;
- while (shift < 56) {
- final byte = readUint8();
- result |= (byte & 0x7f) << shift;
- if ((byte & 0x80) == 0) {
- return result;
- }
- shift += 7;
- }
- final byte = readUint8();
- final value = result | (byte << 56);
- if ((byte & 0x80) != 0) {
- throw StateError(
- 'Uint64 value $value is not representable as a native int.',
- );
- }
- return value;
- }
-
- @pragma('vm:prefer-inline')
- Int64 readVarInt64() {
- final encoded = readVarUint64();
- return Int64((encoded >>> 1) ^ -(encoded & 1));
- }
-
- @pragma('vm:prefer-inline')
- int readVarInt64AsInt() {
- var shift = 0;
- var encoded = 0;
- while (shift < 56) {
- final byte = readUint8();
- encoded |= (byte & 0x7f) << shift;
- if ((byte & 0x80) == 0) {
- return (encoded >>> 1) ^ -(encoded & 1);
- }
- shift += 7;
- }
- encoded |= readUint8() << 56;
- return (encoded >>> 1) ^ -(encoded & 1);
- }
-
- @pragma('vm:prefer-inline')
- Int64 readTaggedInt64() {
- final readIndex = _offset;
- final first = _view.getInt32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return Int64(first.toSigned(32) ~/ 2);
- }
- final value = Int64(_view.getInt64(readIndex + 1, Endian.little));
- _offset = readIndex + 9;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readTaggedInt64AsInt() {
- final readIndex = _offset;
- final first = _view.getInt32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return first.toSigned(32) ~/ 2;
- }
- final value = _view.getInt64(readIndex + 1, Endian.little);
- _offset = readIndex + 9;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- Uint64 readTaggedUint64() {
- final readIndex = _offset;
- final first = _view.getUint32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return Uint64(first >>> 1);
- }
- final value = Uint64(_view.getInt64(readIndex + 1, Endian.little));
- _offset = readIndex + 9;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readTaggedUint64AsInt() {
- final readIndex = _offset;
- final first = _view.getUint32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return first >>> 1;
- }
- final value = _view.getUint64(readIndex + 1, Endian.little);
- if ((_view.getUint32(readIndex + 5, Endian.little) & 0x80000000) != 0) {
- throw StateError(
- 'Uint64 value $value is not representable as a native int.',
- );
- }
- _offset = readIndex + 9;
- return value;
- }
-}
diff --git a/dart/packages/fory/lib/src/codegen/generated_cursor_web.dart b/dart/packages/fory/lib/src/codegen/generated_cursor_web.dart
deleted file mode 100644
index d58a518769..0000000000
--- a/dart/packages/fory/lib/src/codegen/generated_cursor_web.dart
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// ignore_for_file: unnecessary_library_name
-
-library fory.src.codegen.generated_cursor;
-
-import 'dart:typed_data';
-
-import 'package:meta/meta.dart';
-
-import 'package:fory/src/memory/buffer.dart';
-import 'package:fory/src/types/bfloat16.dart';
-import 'package:fory/src/types/float16.dart';
-import 'package:fory/src/types/int64.dart';
-import 'package:fory/src/types/uint64.dart';
-
-part 'generated_cursor_mixin.dart';
-
-const int _jsSafeIntMax = 9007199254740991;
-const int _jsSafeIntMin = -9007199254740991;
-
-@internal
-final class GeneratedWriteCursor with _GeneratedWriteCursorMixin {
- GeneratedWriteCursor._();
-
- factory GeneratedWriteCursor.reserve(Buffer buffer, int maxBytes) {
- return GeneratedWriteCursor._().._initWriteCursor(buffer, maxBytes);
- }
-
- @pragma('vm:prefer-inline')
- void writeInt64(Int64 value) {
- _writeInt64Words(_offset, value);
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- void writeInt64FromInt(int value) {
- _writeInt64Words(_offset, _int64FromInt(value));
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- void writeUint64(Uint64 value) {
- _writeUint64Words(_offset, value);
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- void writeUint64FromInt(int value) {
- _checkUint64IntRange(value);
- _writeUint64Words(_offset, Uint64(value));
- _offset += 8;
- }
-
- @pragma('vm:prefer-inline')
- @override
- void writeVarUint64(Uint64 value) {
- var remaining = value;
- for (var shift = 0; shift < 56 && remaining > 0x7f; shift += 7) {
- _bytes[_offset] = (remaining.low32 & 0x7f) | 0x80;
- _offset += 1;
- remaining = remaining >> 7;
- }
- _bytes[_offset] = remaining.toInt();
- _offset += 1;
- }
-
- @pragma('vm:prefer-inline')
- void writeVarUint64FromInt(int value) {
- _checkUint64IntRange(value);
- writeVarUint64(Uint64(value));
- }
-
- @pragma('vm:prefer-inline')
- void writeVarInt64(Int64 value) {
- writeVarUint64(_zigZagEncodeInt64(value));
- }
-
- @pragma('vm:prefer-inline')
- void writeVarInt64FromInt(int value) {
- writeVarInt64(_int64FromInt(value));
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedInt64(Int64 value) {
- if (value >= -0x40000000 && value <= 0x3fffffff) {
- writeInt32((value.toInt() << 1).toSigned(32));
- return;
- }
- writeUint8(0x01);
- writeInt64(value);
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedInt64FromInt(int value) {
- if (value >= -0x40000000 && value <= 0x3fffffff) {
- writeInt32((value << 1).toSigned(32));
- return;
- }
- _checkInt64IntRange(value);
- writeUint8(0x01);
- writeInt64FromInt(value);
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedUint64(Uint64 value) {
- if (value >= 0 && value <= 0x7fffffff) {
- writeInt32(value.toInt() << 1);
- return;
- }
- writeUint8(0x01);
- writeUint64(value);
- }
-
- @pragma('vm:prefer-inline')
- void writeTaggedUint64FromInt(int value) {
- if (value >= 0 && value <= 0x7fffffff) {
- writeInt32(value << 1);
- return;
- }
- _checkUint64IntRange(value);
- writeUint8(0x01);
- writeUint64FromInt(value);
- }
-
- @pragma('vm:prefer-inline')
- void _writeInt64Words(int offset, Int64 value) {
- _view.setUint32(offset, value.low32, Endian.little);
- _view.setUint32(offset + 4, value.high32Unsigned, Endian.little);
- }
-
- @pragma('vm:prefer-inline')
- void _writeUint64Words(int offset, Uint64 value) {
- _view.setUint32(offset, value.low32, Endian.little);
- _view.setUint32(offset + 4, value.high32Unsigned, Endian.little);
- }
-}
-
-@internal
-final class GeneratedReadCursor with _GeneratedReadCursorMixin {
- GeneratedReadCursor._();
-
- factory GeneratedReadCursor.start(Buffer buffer) {
- return GeneratedReadCursor._().._initReadCursor(buffer);
- }
-
- @pragma('vm:prefer-inline')
- Int64 readInt64() {
- final value = _readInt64Words(_offset);
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readInt64AsInt() {
- final value = _int64ToInt(_readInt64Words(_offset));
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- Uint64 readUint64() {
- final value = _readUint64Words(_offset);
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readUint64AsInt() {
- final value = _readUint64Words(_offset).toInt();
- _offset += 8;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- @override
- Uint64 readVarUint64() {
- var shift = 0;
- var result = Uint64(0);
- while (shift < 56) {
- final byte = readUint8();
- result = result | (Uint64(byte & 0x7f) << shift);
- if ((byte & 0x80) == 0) {
- return result;
- }
- shift += 7;
- }
- return result | (Uint64(readUint8()) << 56);
- }
-
- @pragma('vm:prefer-inline')
- int readVarUint64AsInt() {
- return readVarUint64().toInt();
- }
-
- @pragma('vm:prefer-inline')
- Int64 readVarInt64() {
- return _zigZagDecodeInt64(readVarUint64());
- }
-
- @pragma('vm:prefer-inline')
- int readVarInt64AsInt() {
- return _int64ToInt(readVarInt64());
- }
-
- @pragma('vm:prefer-inline')
- Int64 readTaggedInt64() {
- final readIndex = _offset;
- final first = _view.getInt32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return Int64(first.toSigned(32) ~/ 2);
- }
- final value = _readInt64Words(readIndex + 1);
- _offset = readIndex + 9;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readTaggedInt64AsInt() {
- final readIndex = _offset;
- final first = _view.getInt32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return first.toSigned(32) ~/ 2;
- }
- final value = _int64ToInt(_readInt64Words(readIndex + 1));
- _offset = readIndex + 9;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- Uint64 readTaggedUint64() {
- final readIndex = _offset;
- final first = _view.getUint32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return Uint64(first >>> 1);
- }
- final value = _readUint64Words(readIndex + 1);
- _offset = readIndex + 9;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- int readTaggedUint64AsInt() {
- final readIndex = _offset;
- final first = _view.getUint32(readIndex, Endian.little);
- if ((first & 1) == 0) {
- _offset = readIndex + 4;
- return first >>> 1;
- }
- final value = _readUint64Words(readIndex + 1).toInt();
- _offset = readIndex + 9;
- return value;
- }
-
- @pragma('vm:prefer-inline')
- Int64 _readInt64Words(int offset) {
- return Int64.fromWords(
- _view.getUint32(offset, Endian.little),
- _view.getInt32(offset + 4, Endian.little),
- );
- }
-
- @pragma('vm:prefer-inline')
- Uint64 _readUint64Words(int offset) {
- return Uint64.fromWords(
- _view.getUint32(offset, Endian.little),
- _view.getUint32(offset + 4, Endian.little),
- );
- }
-}
-
-@pragma('vm:prefer-inline')
-void _checkInt64IntRange(int value) {
- if (value < _jsSafeIntMin || value > _jsSafeIntMax) {
- throw StateError(
- 'Dart int value $value is outside the JS-safe signed int64 range '
- '[$_jsSafeIntMin, $_jsSafeIntMax]. Use Int64 for full 64-bit values '
- 'on web.',
- );
- }
-}
-
-@pragma('vm:prefer-inline')
-Int64 _int64FromInt(int value) {
- _checkInt64IntRange(value);
- return Int64(value);
-}
-
-@pragma('vm:prefer-inline')
-void _checkUint64IntRange(int value) {
- if (value < 0 || value > _jsSafeIntMax) {
- throw StateError(
- 'Dart int value $value is outside the JS-safe unsigned uint64 int '
- 'field range [0, $_jsSafeIntMax]. Use Uint64 for full unsigned '
- '64-bit values on web.',
- );
- }
-}
-
-@pragma('vm:prefer-inline')
-int _int64ToInt(Int64 value) => value.toInt();
-
-@pragma('vm:prefer-inline')
-Uint64 _zigZagEncodeInt64(Int64 value) {
- final encoded = (value << 1) ^ (value >> 63);
- return Uint64.fromWords(encoded.low32, encoded.high32Unsigned);
-}
-
-@pragma('vm:prefer-inline')
-Int64 _zigZagDecodeInt64(Uint64 encoded) {
- final magnitude = encoded >> 1;
- final decoded = Int64.fromWords(magnitude.low32, magnitude.high32Unsigned);
- if ((encoded.low32 & 1) == 0) {
- return decoded;
- }
- return -(decoded + 1);
-}
diff --git a/dart/packages/fory/lib/src/codegen/generated_registry.dart b/dart/packages/fory/lib/src/codegen/generated_registry.dart
index 61368b7d4a..0b432e14c1 100644
--- a/dart/packages/fory/lib/src/codegen/generated_registry.dart
+++ b/dart/packages/fory/lib/src/codegen/generated_registry.dart
@@ -21,7 +21,6 @@ import 'package:meta/meta.dart';
import 'package:fory/src/meta/field_info.dart';
import 'package:fory/src/serializer/serializer.dart';
-import 'package:fory/src/serializer/struct_serializer.dart';
enum GeneratedRegistrationKind {
enumType,
@@ -33,18 +32,17 @@ final class GeneratedRegistration {
final GeneratedRegistrationKind kind;
final Serializer