Skip to content

Commit 1de178f

Browse files
authored
chore(dart): refine dart xlang serialization (#3596)
## Why? ## What does this PR do? - comprehensive tests - align time serializers - refactor fixed int support - add bfloat16/float16 support ## Related issues #1194 #1017 ## AI Contribution Checklist - [ ] Substantial AI assistance was used in this PR: `yes` / `no` - [ ] If `yes`, I included a completed [AI Contribution Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs) in this PR description and the required `AI Usage Disclosure`. - [ ] If `yes`, my PR description includes the required `ai_review` summary and screenshot evidence of the final clean AI review results from both fresh reviewers on the current PR diff or current HEAD after the latest code changes. ## Does this PR introduce any user-facing change? - [ ] Does this PR introduce any public API change? - [ ] Does this PR introduce any binary protocol compatibility change? ## Benchmark
1 parent 7b6be90 commit 1de178f

49 files changed

Lines changed: 6087 additions & 463 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dart/packages/fory-test/lib/entity/xlang_test_manual.dart

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,13 @@ final class _Union2Serializer extends UnionSerializer<Union2> {
7070
const _Union2Serializer();
7171

7272
@override
73-
void write(WriteContext context, Union2 value) {
74-
final buffer = context.buffer;
75-
buffer.writeVarUint32(value.index);
76-
context.writeRef(value.value);
77-
}
73+
int caseId(Union2 value) => value.index;
74+
75+
@override
76+
Object caseValue(Union2 value) => value.value;
7877

7978
@override
80-
Union2 read(ReadContext context) {
81-
final buffer = context.buffer;
82-
final index = buffer.readVarUint32();
83-
final value = context.readRef();
79+
Union2 buildValue(int index, Object? value) {
8480
if (index == 0 && value is String) {
8581
return Union2.ofString(value);
8682
}

dart/packages/fory-test/lib/entity/xlang_test_models.dart

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -440,14 +440,14 @@ class CircularRefStruct {
440440
class UnsignedSchemaConsistent {
441441
UnsignedSchemaConsistent();
442442

443-
UInt8 u8Field = UInt8(0);
444-
UInt16 u16Field = UInt16(0);
443+
Uint8 u8Field = Uint8(0);
444+
Uint16 u16Field = Uint16(0);
445445

446446
@Uint32Type(compress: true)
447-
UInt32 u32VarField = UInt32(0);
447+
Uint32 u32VarField = Uint32(0);
448448

449449
@Uint32Type(compress: false)
450-
UInt32 u32FixedField = UInt32(0);
450+
Uint32 u32FixedField = Uint32(0);
451451

452452
@Uint64Type(encoding: LongEncoding.varint)
453453
int u64VarField = 0;
@@ -459,18 +459,18 @@ class UnsignedSchemaConsistent {
459459
int u64TaggedField = 0;
460460

461461
@ForyField(nullable: true)
462-
UInt8? u8NullableField;
462+
Uint8? u8NullableField;
463463

464464
@ForyField(nullable: true)
465-
UInt16? u16NullableField;
465+
Uint16? u16NullableField;
466466

467467
@ForyField(nullable: true)
468468
@Uint32Type(compress: true)
469-
UInt32? u32VarNullableField;
469+
Uint32? u32VarNullableField;
470470

471471
@ForyField(nullable: true)
472472
@Uint32Type(compress: false)
473-
UInt32? u32FixedNullableField;
473+
Uint32? u32FixedNullableField;
474474

475475
@ForyField(nullable: true)
476476
@Uint64Type(encoding: LongEncoding.varint)
@@ -502,18 +502,18 @@ class UnsignedSchemaCompatible {
502502
UnsignedSchemaCompatible();
503503

504504
@ForyField(nullable: true)
505-
UInt8? u8Field1;
505+
Uint8? u8Field1;
506506

507507
@ForyField(nullable: true)
508-
UInt16? u16Field1;
508+
Uint16? u16Field1;
509509

510510
@ForyField(nullable: true)
511511
@Uint32Type(compress: true)
512-
UInt32? u32VarField1;
512+
Uint32? u32VarField1;
513513

514514
@ForyField(nullable: true)
515515
@Uint32Type(compress: false)
516-
UInt32? u32FixedField1;
516+
Uint32? u32FixedField1;
517517

518518
@ForyField(nullable: true)
519519
@Uint64Type(encoding: LongEncoding.varint)
@@ -527,14 +527,14 @@ class UnsignedSchemaCompatible {
527527
@Uint64Type(encoding: LongEncoding.tagged)
528528
int? u64TaggedField1;
529529

530-
UInt8 u8Field2 = UInt8(0);
531-
UInt16 u16Field2 = UInt16(0);
530+
Uint8 u8Field2 = Uint8(0);
531+
Uint16 u16Field2 = Uint16(0);
532532

533533
@Uint32Type(compress: true)
534-
UInt32 u32VarField2 = UInt32(0);
534+
Uint32 u32VarField2 = Uint32(0);
535535

536536
@Uint32Type(compress: false)
537-
UInt32 u32FixedField2 = UInt32(0);
537+
Uint32 u32FixedField2 = Uint32(0);
538538

539539
@Uint64Type(encoding: LongEncoding.varint)
540540
int u64VarField2 = 0;

dart/packages/fory/README.md

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ cases.
1313
- Compatible mode for schema evolution
1414
- Optional reference tracking for shared and circular object graphs
1515
- Manual serializers for external types, custom payloads, and unions
16-
- Explicit xlang value wrappers such as `Int32`, `UInt32`, `Float16`,
17-
`Float32`, `LocalDate`, and `Timestamp`
16+
- Explicit xlang value wrappers such as `Int32`, `Uint32`, `Float16`,
17+
`Bfloat16`, `Float32`, `LocalDate`, and `Timestamp`, plus `Duration`
18+
support
1819

1920
## Getting Started
2021

@@ -219,37 +220,47 @@ void main() {
219220

220221
## Type Mapping
221222

222-
Dart has no native fixed-width 8/16/32-bit integer or single-precision float
223-
types. Fory Dart provides thin wrapper types (`Int8`, `Int16`, `Int32`, `UInt8`,
224-
`UInt16`, `UInt32`, `Float16`, `Float32`) imported from `package:fory/fory.dart`
225-
to represent these xlang wire types.
226-
227-
| Fory xlang type | Dart type |
228-
| --------------- | ------------------------ |
229-
| bool | `bool` |
230-
| int8 | `fory.Int8` (wrapper) |
231-
| int16 | `fory.Int16` (wrapper) |
232-
| int32 | `fory.Int32` (wrapper) |
233-
| int64 | `int` |
234-
| float16 | `fory.Float16` (wrapper) |
235-
| float32 | `fory.Float32` (wrapper) |
236-
| float64 | `double` |
237-
| string | `String` |
238-
| binary | `Uint8List` |
239-
| local_date | `LocalDate` |
240-
| timestamp | `Timestamp` |
241-
| list | `List` |
242-
| set | `Set` |
243-
| map | `Map` |
244-
| enum | `enum` |
245-
| named_struct | `class` |
246-
| bool_array | `List<bool>` |
247-
| int8_array | `Int8List` |
248-
| int16_array | `Int16List` |
249-
| int32_array | `Int32List` |
250-
| int64_array | `Int64List` |
251-
| float32_array | `Float32List` |
252-
| float64_array | `Float64List` |
223+
Dart has no native fixed-width 8/16/32-bit integer, unsigned 64-bit integer,
224+
or single-precision float types. Fory Dart provides thin wrapper types
225+
(`Int8`, `Int16`, `Int32`, `Uint8`, `Uint16`, `Uint32`, `Uint64`, `Float16`,
226+
`Bfloat16`, `Float32`) imported from `package:fory/fory.dart` to represent
227+
these xlang wire types. For 16-bit floating-point arrays, Dart exposes
228+
`Float16List` and `Bfloat16List` as contiguous fixed-length buffers.
229+
230+
| Fory xlang type | Dart type |
231+
| --------------- | ------------------------- |
232+
| bool | `bool` |
233+
| int8 | `fory.Int8` (wrapper) |
234+
| int16 | `fory.Int16` (wrapper) |
235+
| int32 | `fory.Int32` (wrapper) |
236+
| int64 | `int` |
237+
| uint8 | `fory.Uint8` (wrapper) |
238+
| uint16 | `fory.Uint16` (wrapper) |
239+
| uint32 | `fory.Uint32` (wrapper) |
240+
| uint64 | `fory.Uint64` (wrapper) |
241+
| float16 | `fory.Float16` (wrapper) |
242+
| bfloat16 | `fory.Bfloat16` (wrapper) |
243+
| float32 | `fory.Float32` (wrapper) |
244+
| float64 | `double` |
245+
| string | `String` |
246+
| binary | `Uint8List` |
247+
| duration | `Duration` |
248+
| local_date | `LocalDate` |
249+
| timestamp | `Timestamp` |
250+
| list | `List` |
251+
| set | `Set` |
252+
| map | `Map` |
253+
| enum | `enum` |
254+
| named_struct | `class` |
255+
| bool_array | `List<bool>` |
256+
| int8_array | `Int8List` |
257+
| int16_array | `Int16List` |
258+
| int32_array | `Int32List` |
259+
| int64_array | `Int64List` |
260+
| float16_array | `Float16List` |
261+
| bfloat16_array | `Bfloat16List` |
262+
| float32_array | `Float32List` |
263+
| float64_array | `Float64List` |
253264

254265
## Public API
255266

@@ -265,9 +276,9 @@ The main exported API includes:
265276
annotations
266277
- `Int32Type`, `Int64Type`, `Uint32Type`, `Uint64Type` — numeric encoding
267278
overrides
268-
- Numeric wrappers: `Int8`, `Int16`, `Int32`, `UInt8`, `UInt16`, `UInt32`,
269-
`Float16`, `Float32`
270-
- Temporal wrappers: `LocalDate`, `Timestamp`
279+
- Numeric wrappers: `Int8`, `Int16`, `Int32`, `Uint8`, `Uint16`, `Uint32`,
280+
`Uint64`, `Float16`, `Bfloat16`, `Float32`
281+
- Temporal types: `LocalDate`, `Timestamp`, `Duration`
271282

272283
## Cross-Language Notes
273284

dart/packages/fory/lib/fory.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,15 @@ export 'src/meta/type_ids.dart';
4949
export 'src/serializer/enum_serializer.dart';
5050
export 'src/serializer/serializer.dart';
5151
export 'src/serializer/union_serializer.dart';
52-
export 'src/types/fixed_ints.dart';
52+
export 'src/types/bfloat16.dart';
5353
export 'src/types/float16.dart';
5454
export 'src/types/float32.dart';
55+
export 'src/types/int16.dart';
56+
export 'src/types/int32.dart';
57+
export 'src/types/int8.dart';
5558
export 'src/types/local_date.dart';
5659
export 'src/types/timestamp.dart';
60+
export 'src/types/uint16.dart';
61+
export 'src/types/uint32.dart';
62+
export 'src/types/uint64.dart';
63+
export 'src/types/uint8.dart';

dart/packages/fory/lib/src/buffer.dart

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import 'dart:typed_data';
2222

2323
import 'package:meta/meta.dart';
2424

25+
import 'package:fory/src/types/bfloat16.dart';
2526
import 'package:fory/src/types/float16.dart';
2627

2728
final BigInt _mask64Big = (BigInt.one << 64) - BigInt.one;
@@ -255,6 +256,12 @@ final class Buffer {
255256
/// Reads a half-precision floating-point value.
256257
Float16 readFloat16() => Float16.fromBits(readUint16());
257258

259+
/// Writes a bfloat16 floating-point value.
260+
void writeBfloat16(Bfloat16 value) => writeUint16(value.toBits());
261+
262+
/// Reads a bfloat16 floating-point value.
263+
Bfloat16 readBfloat16() => Bfloat16.fromBits(readUint16());
264+
258265
/// Writes [value] verbatim.
259266
void writeBytes(List<int> value) {
260267
ensureWritable(value.length);
@@ -409,13 +416,12 @@ final class Buffer {
409416

410417
/// Writes a tagged unsigned 64-bit integer.
411418
void writeTaggedUint64(int value) {
412-
final unsigned = _toUnsigned64(value);
413-
if (unsigned <= 0x7fffffff) {
414-
writeInt32((unsigned << 1) & 0xffffffff);
419+
if (value >= 0 && value <= 0x7fffffff) {
420+
writeInt32(value << 1);
415421
return;
416422
}
417423
writeUint8(0x01);
418-
writeUint64(unsigned);
424+
writeUint64(value);
419425
}
420426

421427
/// Reads an unsigned 64-bit integer written by [writeTaggedUint64].
@@ -487,8 +493,6 @@ Uint8List bufferBytes(Buffer buffer) => buffer._bytes;
487493
@internal
488494
ByteData bufferByteData(Buffer buffer) => buffer._view;
489495

490-
int _toUnsigned64(int value) => (BigInt.from(value) & _mask64Big).toInt();
491-
492496
extension on Buffer {
493497
void _writeVarUint64BigInt(BigInt value) {
494498
var remaining = value & _mask64Big;

0 commit comments

Comments
 (0)