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.git
The following commit(s) were added to refs/heads/main by this push:
new 4b53e0ac1 feat(dart): add struct serializer support for unsigned
integer types (#3155)
4b53e0ac1 is described below
commit 4b53e0ac15970315a21692d730509e5a92ef1d1a
Author: Ayush Kumar <[email protected]>
AuthorDate: Mon Jan 19 16:49:15 2026 +0530
feat(dart): add struct serializer support for unsigned integer types (#3155)
## Why?
While unsigned integer types (UInt8, UInt16, UInt32) were added to Fory
in PR #3144 with their primitive serializers and wrapper classes, they
were not integrated into the framework's type system for struct
serialization. This meant users could serialize individual UInt values
but could not use them as fields in structs annotated with `@ForyClass`.
For example:
* A struct with `UInt16 port` field would fail during code generation
* Cross-language data structures using unsigned integers couldn't be
represented in Dart structs
* The type system didn't recognize UInt types as valid field types for
serialization
## What does this PR do?
### 1. Registers Unsigned Integer Types in DartTypeEnum
Added UInt8, UInt16, and UInt32 to the type enumeration in
`dart_type.dart`:
```dart
UINT8(UInt8, true, 'UInt8', 'package', 'fory/src/datatype/uint8.dart',
ObjType.UINT8, true, 'dart:core@UInt8'),
UINT16(UInt16, true, 'UInt16', 'package', 'fory/src/datatype/uint16.dart',
ObjType.UINT16, true, 'dart:core@UInt16'),
UINT32(UInt32, true, 'UInt32', 'package', 'fory/src/datatype/uint32.dart',
ObjType.UINT32, true, 'dart:core@UInt32'),
```
This enables the code generator to recognize unsigned types during
static analysis and generate proper serialization metadata.
### 2. Integrates Serializers into SerializerPool
Registered the serializers in the framework initialization:
```dart
type2Ser[UInt8]!.ser = UInt8Serializer.cache.getSerializer(conf);
type2Ser[UInt16]!.ser = UInt16Serializer.cache.getSerializer(conf);
type2Ser[UInt32]!.ser = UInt32Serializer.cache.getSerializer(conf);
```
This ensures serializers are available when the framework starts and can
be used for struct field serialization.
### 3. Adds Comprehensive Test Suite for Struct Serialization
Created test entity and test cases:
```dart
@ForyClass(promiseAcyclic: true)
class UIntStruct with _$UIntStructFory {
final UInt8 age;
final UInt16 port;
final UInt32 count;
const UIntStruct(this.age, this.port, this.count);
}
```
**Test coverage:**
* Normal value serialization/deserialization
* Maximum boundary values (255, 65535, 4294967295)
* Minimum boundary values (0, 0, 0)
* Round-trip serialization integrity
**Run tests:**
```bash
cd packages/fory-test
dart test test/struct_test/uint_struct_test.dart
```
## Related issues
Completes the unsigned integer types support initiated in PR #3144.
## Does this PR introduce any user-facing change?
* [x] Does this PR introduce any public API change?
* **Dart**: UInt8, UInt16, UInt32 can now be used as fields in
`@ForyClass` structs
* The wrapper classes themselves were already public (added in #3144)
* This PR enables their use in code generation and struct serialization
contexts
* [ ] Does this PR introduce any binary protocol compatibility change?
* No changes to binary encoding format
* Uses existing serializers from #3144 (UInt8: 1 byte, UInt16: 2 bytes
LE, UInt32: 4 bytes LE)
* Type IDs remain the same: UINT8 (40), UINT16 (41), UINT32 (42)
## Benchmark
N/A, The serializers themselves were already implemented in #3144. This
PR only adds registration overhead during framework initialization,
which is negligible..
---
.../packages/fory-test/lib/entity/uint_struct.dart | 48 ++++++++++++
.../test/struct_test/uint_struct_test.dart | 86 ++++++++++++++++++++++
dart/packages/fory/lib/src/const/dart_type.dart | 6 ++
.../fory/lib/src/serializer/serializer_pool.dart | 6 ++
4 files changed, 146 insertions(+)
diff --git a/dart/packages/fory-test/lib/entity/uint_struct.dart
b/dart/packages/fory-test/lib/entity/uint_struct.dart
new file mode 100644
index 000000000..70563e12b
--- /dev/null
+++ b/dart/packages/fory-test/lib/entity/uint_struct.dart
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+import 'package:fory/fory.dart';
+
+part '../generated/uint_struct.g.dart';
+
+@ForyClass(promiseAcyclic: true)
+class UIntStruct with _$UIntStructFory {
+ final UInt8 age;
+ final UInt16 port;
+ final UInt32 count;
+
+ const UIntStruct(
+ this.age,
+ this.port,
+ this.count,
+ );
+
+ @override
+ bool operator ==(Object other) {
+ return identical(this, other) ||
+ (other is UIntStruct &&
+ runtimeType == other.runtimeType &&
+ age == other.age &&
+ port == other.port &&
+ count == other.count);
+ }
+
+ @override
+ int get hashCode => age.hashCode ^ port.hashCode ^ count.hashCode;
+}
diff --git a/dart/packages/fory-test/test/struct_test/uint_struct_test.dart
b/dart/packages/fory-test/test/struct_test/uint_struct_test.dart
new file mode 100644
index 000000000..07af0ad06
--- /dev/null
+++ b/dart/packages/fory-test/test/struct_test/uint_struct_test.dart
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+library;
+
+import 'package:fory/fory.dart';
+import 'package:fory_test/entity/uint_struct.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('UInt struct serialization', () {
+ test('serializes and deserializes UInt fields correctly', () {
+ // Create test instance
+ var original = UIntStruct(
+ UInt8(25),
+ UInt16(8080),
+ UInt32(1000000),
+ );
+
+ // Serialize
+ var fory = Fory();
+ fory.register($UIntStruct);
+ var bytes = fory.toFory(original);
+
+ expect(bytes.isNotEmpty, isTrue);
+
+ // Deserialize
+ var decoded = fory.fromFory(bytes) as UIntStruct;
+
+ // Verify values
+ expect(decoded.age.value, 25);
+ expect(decoded.port.value, 8080);
+ expect(decoded.count.value, 1000000);
+ });
+
+ test('handles max values correctly', () {
+ var original = UIntStruct(
+ UInt8(255), // Max UInt8
+ UInt16(65535), // Max UInt16
+ UInt32(4294967295), // Max UInt32
+ );
+
+ var fory = Fory();
+ fory.register($UIntStruct);
+ var bytes = fory.toFory(original);
+ var decoded = fory.fromFory(bytes) as UIntStruct;
+
+ expect(decoded.age.value, 255);
+ expect(decoded.port.value, 65535);
+ expect(decoded.count.value, 4294967295);
+ });
+
+ test('handles min values correctly', () {
+ var original = UIntStruct(
+ UInt8(0),
+ UInt16(0),
+ UInt32(0),
+ );
+
+ var fory = Fory();
+ fory.register($UIntStruct);
+ var bytes = fory.toFory(original);
+ var decoded = fory.fromFory(bytes) as UIntStruct;
+
+ expect(decoded.age.value, 0);
+ expect(decoded.port.value, 0);
+ expect(decoded.count.value, 0);
+ });
+ });
+}
diff --git a/dart/packages/fory/lib/src/const/dart_type.dart
b/dart/packages/fory/lib/src/const/dart_type.dart
index 41561402e..b6d59b613 100644
--- a/dart/packages/fory/lib/src/const/dart_type.dart
+++ b/dart/packages/fory/lib/src/const/dart_type.dart
@@ -25,6 +25,9 @@ import 'package:fory/src/datatype/float32.dart';
import 'package:fory/src/datatype/int16.dart';
import 'package:fory/src/datatype/int32.dart';
import 'package:fory/src/datatype/int8.dart';
+import 'package:fory/src/datatype/uint8.dart';
+import 'package:fory/src/datatype/uint16.dart';
+import 'package:fory/src/datatype/uint32.dart';
import 'package:fory/src/const/obj_type.dart';
import 'package:fory/src/datatype/local_date.dart';
@@ -41,6 +44,9 @@ enum DartTypeEnum{
INT8(Int8, true, 'Int8', 'package', 'fory/src/datatype/int8.dart',
ObjType.INT8, true, 'dart:core@Int8'),
INT16(Int16, true, 'Int16', 'package', 'fory/src/datatype/int16.dart',
ObjType.INT16, true, 'dart:core@Int16'),
INT32(Int32, true, 'Int32', 'package', 'fory/src/datatype/int32.dart',
ObjType.INT32, true, 'dart:core@Int32'),
+ UINT8(UInt8, true, 'UInt8', 'package', 'fory/src/datatype/uint8.dart',
ObjType.UINT8, true, 'dart:core@UInt8'),
+ UINT16(UInt16, true, 'UInt16', 'package', 'fory/src/datatype/uint16.dart',
ObjType.UINT16, true, 'dart:core@UInt16'),
+ UINT32(UInt32, true, 'UInt32', 'package', 'fory/src/datatype/uint32.dart',
ObjType.UINT32, true, 'dart:core@UInt32'),
INT(int,true, 'int', 'dart', 'core', ObjType.INT64, true, 'dart:core@int'),
FLOAT32(Float32, true, 'Float32', 'package',
'fory/src/datatype/float32.dart', ObjType.FLOAT32, true, 'dart:core@Float32'),
DOUBLE(double,true, 'double', 'dart', 'core', ObjType.FLOAT64, true,
'dart:core@double'),
diff --git a/dart/packages/fory/lib/src/serializer/serializer_pool.dart
b/dart/packages/fory/lib/src/serializer/serializer_pool.dart
index 9329a3ea0..ca6fbbb2c 100644
--- a/dart/packages/fory/lib/src/serializer/serializer_pool.dart
+++ b/dart/packages/fory/lib/src/serializer/serializer_pool.dart
@@ -27,6 +27,9 @@ import 'package:fory/src/datatype/float32.dart';
import 'package:fory/src/datatype/int16.dart';
import 'package:fory/src/datatype/int32.dart';
import 'package:fory/src/datatype/int8.dart';
+import 'package:fory/src/datatype/uint8.dart';
+import 'package:fory/src/datatype/uint16.dart';
+import 'package:fory/src/datatype/uint32.dart';
import 'package:fory/src/datatype/local_date.dart';
import 'package:fory/src/datatype/timestamp.dart';
import 'package:fory/src/meta/type_info.dart';
@@ -63,6 +66,9 @@ class SerializerPool{
type2Ser[Int8]!.ser = Int8Serializer.cache.getSerializer(conf);
type2Ser[Int16]!.ser = Int16Serializer.cache.getSerializer(conf);
type2Ser[Int32]!.ser = Int32Serializer.cache.getSerializer(conf);
+ type2Ser[UInt8]!.ser = UInt8Serializer.cache.getSerializer(conf);
+ type2Ser[UInt16]!.ser = UInt16Serializer.cache.getSerializer(conf);
+ type2Ser[UInt32]!.ser = UInt32Serializer.cache.getSerializer(conf);
type2Ser[Float32]!.ser = Float32Serializer.cache.getSerializer(conf);
type2Ser[String]!.ser = StringSerializer.cache.getSerializer(conf);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]