|
1 | 1 | # Apache Fory™ Dart |
2 | 2 |
|
3 | | -## Overview |
| 3 | +Apache Fory™ Dart is the Dart xlang runtime for Apache Fory™. It reads and |
| 4 | +writes Fory's cross-language wire format and works in both Dart and Flutter |
| 5 | +applications. Because Flutter prohibits `dart:mirrors`, the runtime uses static |
| 6 | +code generation for type handling. |
4 | 7 |
|
5 | | -This PR adds Dart language support to Apache Fory™, implementing a comprehensive serialization solution for Dart and Flutter applications. Apache Fory™ Dart consists of approximately 15,000 lines of code and provides an efficient serialization mechanism that works within Flutter's reflection limitations. |
| 8 | +The publishable package lives at `packages/fory/`. See its |
| 9 | +[README](packages/fory/README.md) for the full user-facing documentation |
| 10 | +including getting started, API reference, and code examples. |
6 | 11 |
|
7 | | -## Implementation Approach |
8 | | - |
9 | | -Dart supports reflection, but Flutter explicitly prohibits it. To address this constraint, Apache Fory™ Dart uses a combination of: |
10 | | - |
11 | | -1. Core serialization/deserialization logic |
12 | | -2. Static code generation for type handling |
13 | | - |
14 | | -This approach ensures compatibility with Flutter while maintaining the performance and flexibility expected from Apache Fory™. |
15 | | - |
16 | | -## Features |
17 | | - |
18 | | -- XLANG mode support for cross-language serialization |
19 | | -- Reference tracking for handling object graphs |
20 | | -- Support for primitive types, collections, and custom classes |
21 | | -- Serializer registration system |
22 | | -- Code generation for class and enum serialization |
23 | | -- Support for nested collections with automatic generic type conversion |
24 | | -- Custom serializer registration |
25 | | -- Support for using ByteWriter/ByteReader as serialization sources |
26 | | - |
27 | | -## Usage Examples |
| 12 | +## Project Structure |
28 | 13 |
|
29 | | -### Basic Class Serialization |
| 14 | +| Directory | Description | |
| 15 | +| -------------------------------- | --------------------------------------- | |
| 16 | +| `packages/fory/lib/` | Core runtime and public API | |
| 17 | +| `packages/fory/lib/src/codegen/` | Build-runner code generator | |
| 18 | +| `packages/fory/example/` | Annotated example with generated output | |
| 19 | +| `packages/fory/test/` | Unit and integration tests | |
| 20 | +| `test/` | Cross-language integration tests | |
| 21 | + |
| 22 | +## Type Mapping |
| 23 | + |
| 24 | +| Fory xlang type | Dart type | |
| 25 | +| --------------- | ------------------------ | |
| 26 | +| bool | `bool` | |
| 27 | +| int8 | `fory.Int8` (wrapper) | |
| 28 | +| int16 | `fory.Int16` (wrapper) | |
| 29 | +| int32 | `fory.Int32` (wrapper) | |
| 30 | +| int64 | `int` | |
| 31 | +| float16 | `fory.Float16` (wrapper) | |
| 32 | +| float32 | `fory.Float32` (wrapper) | |
| 33 | +| float64 | `double` | |
| 34 | +| string | `String` | |
| 35 | +| binary | `Uint8List` | |
| 36 | +| local_date | `LocalDate` | |
| 37 | +| timestamp | `Timestamp` | |
| 38 | +| list | `List` | |
| 39 | +| set | `Set` | |
| 40 | +| map | `Map` | |
| 41 | +| enum | `enum` | |
| 42 | +| named_struct | `class` | |
| 43 | +| bool_array | `List<bool>` | |
| 44 | +| int8_array | `Int8List` | |
| 45 | +| int16_array | `Int16List` | |
| 46 | +| int32_array | `Int32List` | |
| 47 | +| int64_array | `Int64List` | |
| 48 | +| float32_array | `Float32List` | |
| 49 | +| float64_array | `Float64List` | |
| 50 | + |
| 51 | +## Quick Start |
| 52 | + |
| 53 | +Annotate your model and run the code generator: |
30 | 54 |
|
31 | 55 | ```dart |
32 | 56 | import 'package:fory/fory.dart'; |
33 | 57 |
|
34 | | -part 'example.g.dart'; |
| 58 | +part 'person.fory.dart'; |
35 | 59 |
|
36 | | -@foryClass |
37 | | -class SomeClass with _$SomeClassFory { |
38 | | - late int id; |
39 | | - late String name; |
40 | | - late Map<String, double> map; |
| 60 | +@ForyStruct() |
| 61 | +class Person { |
| 62 | + Person(); |
41 | 63 |
|
42 | | - SomeClass(this.id, this.name, this.map); |
43 | | -
|
44 | | - SomeClass.noArgs(); |
| 64 | + String name = ''; |
| 65 | + Int32 age = Int32(0); |
45 | 66 | } |
46 | 67 | ``` |
47 | 68 |
|
48 | | -After annotating your class with `@foryClass`, run: |
49 | | - |
50 | 69 | ```bash |
51 | | -dart run build_runner build |
| 70 | +dart run build_runner build --delete-conflicting-outputs |
52 | 71 | ``` |
53 | 72 |
|
54 | | -This generates the necessary code in `example.g.dart` and creates the `_$SomeClassFory` mixin. |
55 | | - |
56 | | -### Serializing and Deserializing |
| 73 | +Serialize and deserialize: |
57 | 74 |
|
58 | 75 | ```dart |
59 | | -Fory fory = Fory(ref: true); |
60 | | -fory.register($SomeClass, typename: "example.SomeClass"); |
61 | | -SomeClass obj = SomeClass(1, 'SomeClass', {'a': 1.0}); |
62 | | -
|
63 | | -// Serialize |
64 | | -Uint8List bytes = fory.serialize(obj); |
| 76 | +final fory = Fory(); |
| 77 | +PersonFory.register(fory, Person, namespace: 'example', typeName: 'Person'); |
65 | 78 |
|
66 | | -// Deserialize |
67 | | -obj = fory.deserialize(bytes) as SomeClass; |
| 79 | +final bytes = fory.serialize(Person()..name = 'Ada'..age = Int32(36)); |
| 80 | +final roundTrip = fory.deserialize<Person>(bytes); |
68 | 81 | ``` |
69 | 82 |
|
70 | | -### Enum Serialization |
71 | | - |
72 | | -```dart |
73 | | -import 'package:fory/fory.dart'; |
| 83 | +## Development |
74 | 84 |
|
75 | | -part 'example.g.dart'; |
| 85 | +Run tests from the workspace root: |
76 | 86 |
|
77 | | -@foryEnum |
78 | | -enum EnumFoo { |
79 | | - A, |
80 | | - B |
81 | | -} |
| 87 | +```bash |
| 88 | +cd packages/fory |
| 89 | +dart test |
82 | 90 | ``` |
83 | 91 |
|
84 | | -Registration is similar to classes: |
| 92 | +Run the code generator on the example: |
85 | 93 |
|
86 | | -```dart |
87 | | -fory.register($EnumFoo, typename: "example.EnumFoo"); |
| 94 | +```bash |
| 95 | +cd packages/fory |
| 96 | +dart run build_runner build --delete-conflicting-outputs |
88 | 97 | ``` |
89 | | - |
90 | | -## Type Support |
91 | | - |
92 | | -Apache Fory™ Dart currently supports the following type mappings in XLANG mode: |
93 | | - |
94 | | -| Fory Type | Dart Type | |
95 | | -| ------------- | ------------------------------------------ | |
96 | | -| bool | bool | |
97 | | -| int8 | fory.Int8 | |
98 | | -| int16 | fory.Int16 | |
99 | | -| int32 | fory.Int32 | |
100 | | -| var_int32 | fory.Int32 | |
101 | | -| int64 | int | |
102 | | -| var_int64 | int | |
103 | | -| sli_int64 | int | |
104 | | -| float32 | fory.Float32 | |
105 | | -| float64 | double | |
106 | | -| string | String | |
107 | | -| enum | Enum | |
108 | | -| named_enum | Enum | |
109 | | -| named_struct | class | |
110 | | -| list | List | |
111 | | -| set | Set (LinkedHashSet, HashSet, SplayTreeSet) | |
112 | | -| map | Map (LinkedHashMap, HashMap, SplayTreeMap) | |
113 | | -| timestamp | fory.TimeStamp | |
114 | | -| local_date | fory.LocalDate | |
115 | | -| binary | Uint8List | |
116 | | -| bool_array | BoolList | |
117 | | -| int8_array | Int8List | |
118 | | -| int16_array | Int16List | |
119 | | -| int32_array | Int32List | |
120 | | -| int64_array | Int64List | |
121 | | -| float32_array | Float32List | |
122 | | -| float64_array | Float64List | |
123 | | - |
124 | | -## Project Structure |
125 | | - |
126 | | -The implementation is organized into three main components: |
127 | | - |
128 | | -1. **Codegen**: Located at `dart/packages/fory/lib/src/codegen` |
129 | | - Handles static code generation for serialization/deserialization. |
130 | | - |
131 | | -2. **ForyCore**: Located at `dart/packages/fory/lib/src` |
132 | | - Contains the core serialization and deserialization logic. |
133 | | - |
134 | | -3. **ForyTest**: Located at `dart/fory-test` |
135 | | - Comprehensive test suite for Apache Fory™ Dart functionality. |
136 | | - |
137 | | -## Testing Approach |
138 | | - |
139 | | -The test suite is inspired by Apache Fory™ Java's testing approach and includes: |
140 | | - |
141 | | -- **Data Type Tests**: Validates custom data types implemented for Dart |
142 | | -- **Code Generation Tests**: Ensures correctness of the generated static code |
143 | | -- **Buffer Tests**: Validates correct memory handling for primitive types |
144 | | -- **Cross-Language Tests**: Tests functionality against other Apache Fory™ implementations |
145 | | -- **Performance Tests**: Simple benchmarks for serialization/deserialization performance |
0 commit comments