This is an automated email from the ASF dual-hosted git repository. chaokunyang pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/fory-site.git
commit 373e54ec10a71e4c65df65ccfe7d207968f74700 Author: chaokunyang <[email protected]> AuthorDate: Fri May 1 13:57:16 2026 +0000 🔄 synced local 'docs/guide/' with remote 'docs/guide/' --- docs/guide/dart/basic-serialization.md | 12 +++-- docs/guide/dart/code-generation.md | 4 +- docs/guide/dart/cross-language.md | 20 +++++--- docs/guide/dart/field-configuration.md | 37 ++++++++++---- docs/guide/dart/index.md | 11 ++-- docs/guide/dart/schema-evolution.md | 2 +- docs/guide/dart/supported-types.md | 75 ++++++++++++++++++---------- docs/guide/dart/troubleshooting.md | 8 +-- docs/guide/dart/web-platform-support.md | 17 ++++--- docs/guide/xlang/field-reference-tracking.md | 4 +- 10 files changed, 119 insertions(+), 71 deletions(-) diff --git a/docs/guide/dart/basic-serialization.md b/docs/guide/dart/basic-serialization.md index 1f261937ed..87ea752df2 100644 --- a/docs/guide/dart/basic-serialization.md +++ b/docs/guide/dart/basic-serialization.md @@ -43,7 +43,9 @@ class Person { Person(); String name = ''; - Int32 age = Int32(0); + + @ForyField(type: Int32Type()) + int age = 0; } void main() { @@ -57,7 +59,7 @@ void main() { final person = Person() ..name = 'Ada' - ..age = Int32(36); + ..age = 36; final bytes = fory.serialize(person); final roundTrip = fory.deserialize<Person>(bytes); @@ -85,7 +87,7 @@ You can serialize collection values directly: final fory = Fory(); final bytes = fory.serialize(<Object?>[ 'hello', - Int32(42), + 42, true, ]); final value = fory.deserialize<List<Object?>>(bytes); @@ -117,8 +119,8 @@ If you want to avoid allocating a new `Uint8List` on every call, use `serializeT final fory = Fory(); final buffer = Buffer(); -fory.serializeTo(Int32(42), buffer); -final value = fory.deserializeFrom<Int32>(buffer); +fory.serializeTo('Ada', buffer); +final value = fory.deserializeFrom<String>(buffer); ``` This is an optimization. For most applications the default `serialize`/`deserialize` pair is fine. diff --git a/docs/guide/dart/code-generation.md b/docs/guide/dart/code-generation.md index 495a6dd898..d24d8c229b 100644 --- a/docs/guide/dart/code-generation.md +++ b/docs/guide/dart/code-generation.md @@ -43,7 +43,9 @@ class User { User(); String name = ''; - Int32 age = Int32(0); + + @ForyField(type: Int32Type()) + int age = 0; Address address = Address(); } ``` diff --git a/docs/guide/dart/cross-language.md b/docs/guide/dart/cross-language.md index ed843d3d31..f5d7b5476c 100644 --- a/docs/guide/dart/cross-language.md +++ b/docs/guide/dart/cross-language.md @@ -74,14 +74,16 @@ class Person { Person(); String name = ''; - Int32 age = Int32(0); + + @ForyField(type: Int32Type()) + int age = 0; } final fory = Fory(); PersonFory.register(fory, Person, id: 100); final bytes = fory.serialize(Person() ..name = 'Alice' - ..age = Int32(30)); + ..age = 30); ``` ### Java @@ -104,7 +106,7 @@ final fory = Fory(compatible: true); PersonFory.register(fory, Person, id: 100); final bytes = fory.serialize(Person() ..name = 'Alice' - ..age = Int32(30)); + ..age = 30); ``` ### CSharp @@ -134,7 +136,7 @@ final fory = Fory(); PersonFory.register(fory, Person, id: 100); final bytes = fory.serialize(Person() ..name = 'Alice' - ..age = Int32(30)); + ..age = 30); ``` ### Go @@ -159,16 +161,18 @@ Fory matches fields by name or by stable field ID. For robust cross-language int 1. Use the same type identity on every side (same numeric ID or same `namespace + typeName`). 2. Assign stable `@ForyField(id: ...)` values to all fields before shipping the first payload. 3. Keep field names consistent or rely on IDs, since Dart typically uses `lowerCamelCase` while Go uses `PascalCase` for exported fields and C# often uses `PascalCase` properties. -4. Use compatible numeric types: `Int32` in Dart for Java `int`, Go `int32`, and C# `int`; `double` in Dart for 64-bit floats; `Float32` for 32-bit. +4. Use explicit numeric field metadata: `@ForyField(type: Int32Type())` in Dart for Java `int`, Go `int32`, and C# `int`; `double` in Dart for 64-bit floats; `Float32` for 32-bit; `Int64` / `Uint64` for full-range 64-bit values. 5. Use `Timestamp`, `LocalDate`, and `Duration` for temporal fields rather than raw `DateTime`. 6. Validate real round trips across all languages before shipping. ## Type Mapping Notes for Dart -Because Dart `int` is not itself a promise about the exact xlang wire width, prefer wrappers or numeric field annotations when exact cross-language interpretation matters: +Because Dart `int` is not itself a promise about the exact xlang wire width, prefer explicit field metadata when exact cross-language interpretation matters: -- `Int32` for xlang `int32` -- `Uint32` for xlang `uint32` +- `@ForyField(type: Int32Type())` for xlang `int32` +- `@ForyField(type: Uint32Type())` for xlang `uint32` +- `@ForyField(type: Int8Type())` / `@ForyField(type: Int16Type())` / `@ForyField(type: Uint8Type())` / `@ForyField(type: Uint16Type())` for narrower integer widths +- `Int64` and `Uint64` for full-range 64-bit values on web - `Float16`, `Bfloat16`, and `Float32` for reduced-width floating point - `Float16List` and `Bfloat16List` for 16-bit floating-point array payloads - `Timestamp`, `LocalDate`, and `Duration` for explicit temporal semantics diff --git a/docs/guide/dart/field-configuration.md b/docs/guide/dart/field-configuration.md index 5e0b439f02..a7d02904b2 100644 --- a/docs/guide/dart/field-configuration.md +++ b/docs/guide/dart/field-configuration.md @@ -88,32 +88,47 @@ Controls whether Fory writes the concrete runtime type of the field value into t Object? payload; // can hold any registered type at runtime ``` -## Numeric Field Annotations +## Numeric Field Types -Dart `int` is a 64-bit value at runtime. When exchanging messages with Java, Go, or C#, the receiving side may expect a narrower integer. Use a numeric annotation to pin the exact wire format: +Dart `int` is a 64-bit value at runtime. When exchanging messages with Java, Go, or C#, the receiving side may expect a narrower integer. Use `@ForyField(type: ...)` to pin the exact wire format: ```dart @ForyStruct() class Sample { Sample(); - @Int32Type(compress: false) // always writes 4 bytes + @ForyField(type: Int32Type(encoding: Encoding.fixed)) int fixedWidthInt = 0; - @Int64Type(encoding: LongEncoding.tagged) // variable-length encoding - int compactLong = 0; + @ForyField(type: Int64Type(encoding: Encoding.tagged)) + Int64 compactLong = Int64(0); - @Uint32Type(compress: true) // variable-length unsigned + @ForyField(type: Uint32Type()) int smallUnsigned = 0; } ``` -Available annotations: `@Int32Type`, `@Int64Type`, `@Uint8Type`, `@Uint16Type`, `@Uint32Type`, `@Uint64Type`. +Available scalar type nodes include `Int8Type`, `Int16Type`, `Int32Type`, +`Int64Type`, `Uint8Type`, `Uint16Type`, `Uint32Type`, `Uint64Type`, +`Float16Type`, `Bfloat16Type`, and `Float32Type`. -Alternatively, use explicit wrapper types such as `Int32`, `Int64`, `Uint32`, -and `Uint64` as described in [Supported Types](supported-types.md). Wrappers use -compact varint encodings by default; use annotations or generated field -metadata when a fixed-width or tagged encoding is required. +For nested containers, use `ListField`, `SetField`, `MapField`, or a full +`ForyField(type: ...)` tree: + +```dart +@MapField( + value: ListType( + element: Int32Type(encoding: Encoding.fixed), + ), +) +Map<String, List<int?>> metrics = <String, List<int?>>{}; +``` + +Generic `List<int>` still uses the `list` wire type even with primitive element +specs. Packed `*_array` wire kinds come from dedicated carriers such as +`Int32List`, `Uint32List`, `Int64List`, and `Uint64List`. If you annotate a +generic `List<int>` with a non-null fixed-width primitive element spec, code +generation rejects it and tells you to use the matching typed list carrier. ## Aligning Fields Across Languages diff --git a/docs/guide/dart/index.md b/docs/guide/dart/index.md index cab137c48c..34e1da64eb 100644 --- a/docs/guide/dart/index.md +++ b/docs/guide/dart/index.md @@ -68,7 +68,9 @@ class Person { Person(); String name = ''; - Int32 age = Int32(0); + + @ForyField(type: Int32Type()) + int age = 0; Color favoriteColor = Color.red; List<String> tags = <String>[]; } @@ -90,7 +92,7 @@ void main() { final person = Person() ..name = 'Ada' - ..age = Int32(36) + ..age = 36 ..favoriteColor = Color.blue ..tags = <String>['engineer', 'mathematician']; @@ -114,8 +116,9 @@ dart run build_runner build --delete-conflicting-outputs - `fory.serialize(value)` — returns `Uint8List` bytes - `fory.deserialize<T>(bytes)` — returns a `T` - `@ForyStruct()` — marks a class for code generation -- `@ForyField(...)` — per-field options (skip, ID, nullability, references) -- Integer wrappers: `Int8`, `Int16`, `Int32`, `Int64`, `Uint8`, `Uint16`, `Uint32`, `Uint64` +- `@ForyField(...)` — per-field options and canonical `type:` overrides +- `@ListField(...)`, `@SetField(...)`, `@MapField(...)` — container sugar for nested `type:` trees +- Exact-value wrappers: `Int64`, `Uint64`, `Float16`, `Bfloat16`, `Float32` - Float wrappers: `Float16`, `Bfloat16`, `Float32` - 16-bit float arrays: `Float16List`, `Bfloat16List` - Time types: `LocalDate`, `Timestamp`, `Duration` diff --git a/docs/guide/dart/schema-evolution.md b/docs/guide/dart/schema-evolution.md index 8d33297a91..1afbbdeb4f 100644 --- a/docs/guide/dart/schema-evolution.md +++ b/docs/guide/dart/schema-evolution.md @@ -71,7 +71,7 @@ If you add field IDs after payloads are already in production, existing stored m **Unsafe changes** (may break existing messages): - Reuse an existing field ID for a different field. -- Change a field's type to an incompatible type (e.g., `Int32` → `String`). +- Change a field's type to an incompatible type (e.g., `@ForyField(type: Int32Type()) int` → `String`). - Change the registration identity (`id`, `namespace`, or `typeName`) of a type after messages are in production. - Change a field's logical meaning without changing its ID. diff --git a/docs/guide/dart/supported-types.md b/docs/guide/dart/supported-types.md index e7ee82e737..4b43d10e85 100644 --- a/docs/guide/dart/supported-types.md +++ b/docs/guide/dart/supported-types.md @@ -25,17 +25,17 @@ This page lists the Dart types you can use in Fory messages, and flags where you The following Dart types serialize directly without any special handling: -| Dart type | Cross-language notes | -| -------------------- | ----------------------------------------------------------------------------------------------------------- | -| `bool` | Direct mapping | -| `int` | Serialized as 64-bit by default. Use wrappers or `@Int32Type` etc. when the peer expects a narrower integer | -| `double` | Maps to 64-bit float. Use `Float32` wrapper when the peer expects 32-bit | -| `String` | Direct mapping | -| `Uint8List` | Binary blob | -| `List`, `Set`, `Map` | Supported; element types must also be supported | -| `DateTime` | Use `Timestamp` or `LocalDate` wrappers for explicit semantics | - -## Integer Wrappers +| Dart type | Cross-language notes | +| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `bool` | Direct mapping | +| `int` | Serialized as 64-bit by default. Use `@ForyField(type: Int8Type/Int16Type/Int32Type/Uint8Type/Uint16Type/Uint32Type)` when the peer expects a narrower integer | +| `double` | Maps to 64-bit float. Use `Float32` wrapper when the peer expects 32-bit | +| `String` | Direct mapping | +| `Uint8List` | Binary blob | +| `List`, `Set`, `Map` | Supported; element types must also be supported | +| `DateTime` | Use `Timestamp` or `LocalDate` wrappers for explicit semantics | + +## Integer Fields Dart VM/native `int` can represent signed 64-bit values, while Dart web `int` is limited to JavaScript-safe integer precision. If the peer language expects a @@ -43,23 +43,31 @@ is limited to JavaScript-safe integer precision. If the peer language expects a the deserialization may fail or silently truncate. For browser and Flutter web precision rules, see [Web Platform Support](web-platform-support.md). -Use an integer wrapper or field annotation to select the wire type explicitly: +Use field metadata to select the wire type explicitly for 8/16/32-bit fields: ```dart -final Int8 tiny = Int8(-1); // 8-bit signed -final Int16 shortValue = Int16(7); // 16-bit signed -final Int32 age = Int32(36); // 32-bit signed, varint by default -final Int64 seq = Int64(0); // signed 64-bit, varint by default -final Uint8 flags = Uint8(255); // 8-bit unsigned -final Uint16 port = Uint16(65535); // 16-bit unsigned -final Uint32 count = Uint32(4000000000); // 32-bit unsigned, varint by default -final Uint64 offset = Uint64(0); // unsigned 64-bit, varint by default +@ForyStruct() +class Metrics { + Metrics(); + + @ForyField(type: Int8Type()) + int tiny = 0; + + @ForyField(type: Int32Type(encoding: Encoding.fixed)) + int age = 0; + + @ForyField(type: Uint32Type()) + int count = 0; + + Int64 sequence = Int64(0); + Uint64 offset = Uint64(0); +} ``` -Each wrapper clamps or normalizes the stored value to the target bit width. -Root `Int32`, `Int64`, `Uint32`, and `Uint64` values use compact varint wire -types by default. Use `@Int64Type`, `@Uint32Type`, `@Uint64Type`, or generated -field metadata when a fixed-width or tagged encoding is required. +Generated serializers range-check annotated `int` values before writing them. +Use `Int64` and `Uint64` when you need full-range 64-bit values, especially on +web. A plain root `int` value serializes as xlang `int64`; exact 8/16/32-bit +wire widths are selected through field metadata or low-level `Buffer` APIs. On Dart VM, `Int64` and `Uint64` are extension types over `int`. Once a value is passed through an `Object`-typed dynamic/root boundary, the VM cannot recover @@ -115,7 +123,9 @@ class User { User(); String name = ''; - Int32 age = Int32(0); // use Int32 when peers expect a 32-bit integer + + @ForyField(type: Int32Type()) + int age = 0; // use explicit field metadata when peers expect a 32-bit integer } ``` @@ -123,11 +133,22 @@ See [Code Generation](code-generation.md). ## Collections -Fory supports `List<T>`, `Set<T>`, and `Map<K, V>`. Element and key types must also be serializable types. Avoid using mutable objects as map keys. +Fory supports `List<T>`, `Set<T>`, and `Map<K, V>`. Element and key types must +also be serializable types. Avoid using mutable objects as map keys. + +Generic `List<int>` with primitive element metadata still uses the `list` wire +type. Dedicated array wire kinds come from dedicated carriers: + +- `List<bool>` for `bool_array` +- `Int8List`, `Int16List`, `Int32List`, `Int64List` +- `Uint8List`, `Uint16List`, `Uint32List`, `Uint64List` +- `Float16List`, `Bfloat16List`, `Float32List`, `Float64List` ## Compatibility Tip -When in doubt about whether a Dart type will match what the peer expects, use the explicit wrapper types. Guessing the wrong numeric width is one of the most common cross-language bugs. +When in doubt about whether a Dart type will match what the peer expects, make +the width explicit with `@ForyField(type: ...)`. Guessing the wrong numeric +width is one of the most common cross-language bugs. ## Related Topics diff --git a/docs/guide/dart/troubleshooting.md b/docs/guide/dart/troubleshooting.md index 43df08e61e..3938e95a5a 100644 --- a/docs/guide/dart/troubleshooting.md +++ b/docs/guide/dart/troubleshooting.md @@ -74,7 +74,7 @@ Checklist: 1. Same registration identity on both sides (same numeric ID **or** same `namespace + typeName`). 2. Stable `@ForyField(id: ...)` assigned before the first payload was produced. -3. Compatible numeric widths — use `Int32` in Dart when the peer field is `int` (Java), `int32` (Go), or `int` (C#). +3. Compatible numeric widths — use `@ForyField(type: Int32Type())` in Dart when the peer field is `int` (Java), `int32` (Go), or `int` (C#). 4. `Timestamp` / `LocalDate` instead of raw `DateTime` for date/time fields. 5. `compatible: true` on **both** sides if using schema evolution. @@ -114,9 +114,9 @@ class FileBlock { } ``` -`@Int64Type` changes the wire encoding for a Dart `int` field, but it does not -remove the web integer precision limit. Use `Int64` for full-range signed -values and `Uint64` for full-range unsigned values. See +`@ForyField(type: Int64Type(...))` changes the wire encoding for a Dart `int` +field, but it does not remove the web integer precision limit. Use `Int64` for +full-range signed values and `Uint64` for full-range unsigned values. See [Web Platform Support](web-platform-support.md) for the full browser support matrix and migration guidance. diff --git a/docs/guide/dart/web-platform-support.md b/docs/guide/dart/web-platform-support.md index 3ca6154269..4cb63da47f 100644 --- a/docs/guide/dart/web-platform-support.md +++ b/docs/guide/dart/web-platform-support.md @@ -93,21 +93,22 @@ by JavaScript numbers and are precise only in the JS-safe integer range: Use this rule when choosing field types: -| Logical value | Recommended Dart field type on web | Notes | -| ---------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -| Signed 64-bit value within JS-safe range | `int` | Works with default `int64` mapping and `@Int64Type` encodings. | -| Full signed 64-bit range | `Int64` | Preserves values outside the JS-safe range. | -| Unsigned 64-bit value | `Uint64` | Required for values that do not fit in signed or JS-safe Dart `int`. | -| 8/16/32-bit integer | `Int8`, `Int16`, `Int32`, `Uint8`, `Uint16`, `Uint32` or annotations | Use wrappers or numeric annotations to match peer runtimes exactly. | +| Logical value | Recommended Dart field type on web | Notes | +| ---------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------ | +| Signed 64-bit value within JS-safe range | `int` | Works with default `int64` mapping and `@ForyField(type: Int64Type(...))` encodings. | +| Full signed 64-bit range | `Int64` | Preserves values outside the JS-safe range. | +| Unsigned 64-bit value | `Uint64` | Required for values that do not fit in signed or JS-safe Dart `int`. | +| 8/16/32-bit integer | `int` + `@ForyField(type: ...)` | Use explicit field metadata to match peer runtimes exactly. | -`@Int64Type` controls the wire encoding of a Dart `int` field: +`@ForyField(type: Int64Type(...))` controls the wire encoding of a Dart `int` +field: ```dart @ForyStruct() class SafeCounter { SafeCounter(); - @Int64Type(encoding: LongEncoding.tagged) + @ForyField(type: Int64Type(encoding: Encoding.tagged)) int count = 0; // keep web values inside the JS-safe range } ``` diff --git a/docs/guide/xlang/field-reference-tracking.md b/docs/guide/xlang/field-reference-tracking.md index 2aafbf2ee0..d7bfb4ebf1 100644 --- a/docs/guide/xlang/field-reference-tracking.md +++ b/docs/guide/xlang/field-reference-tracking.md @@ -132,11 +132,11 @@ public class Document { String title; // Enable ref tracking for this field - @ForyField(trackingRef = true) + @ForyField(ref = true) Author author; // Shared across documents, track refs to avoid duplicates - @ForyField(trackingRef = true) + @ForyField(ref = true) List<Tag> tags; } ``` --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
