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 bf90e1d14 feat(dart): add uint struct support to the codegen system 
(#3192)
bf90e1d14 is described below

commit bf90e1d14594e574e6f4ec41a9fa278b54e645a6
Author: Ayush Kumar <[email protected]>
AuthorDate: Fri Jan 23 08:20:51 2026 +0530

    feat(dart): add uint struct support to the codegen system (#3192)
    
    ## Why?
    
    While the uint annotation types were integrated into the code generation
    system in the PR #3181 , there were two remaining issues:
    
    1. **No annotated struct support and test coverage for annotated
    structs**: The annotation system was integrated but not tested with
    actual struct fields using the annotations
    2. **Null check error in key_annotation_analyzer**: When fields didn't
    have `@ForyKey` annotations, the code generator crashed with a null
    check error at `key_annotation_analyzer.dart`
    
    ## What does this PR do?
    
    ### 1. Created Test Entity with Annotated Uint Fields
    
    Added `uint_annotated_struct.dart` demonstrating all uint annotation
    variants:
    
    ```dart
    @ForyClass(promiseAcyclic: true)
    class UIntAnnotatedStruct with _$UIntAnnotatedStructFory {
      @Uint8Type()
      final int age;
    
      @Uint16Type()
      final int port;
    
      @Uint32Type()
      final int count;
    
      @Uint32Type(encoding: UintEncoding.varint)
      final int varCount;
    
      @Uint64Type()
      final int id;
    
      @Uint64Type(encoding: UintEncoding.varint)
      final int varId;
    
      @Uint64Type(encoding: UintEncoding.tagged)
      final int taggedId;
    }
    ```
    
    ### 2. Added Comprehensive Test Suite
    
    Created `uint_annotated_struct_test.dart` with test coverage for:
    * Basic serialization/deserialization with annotated fields
    * Max value handling for uint8 (255), uint16 (65535), uint32
    (4294967295)
    * Min value handling (0 for all types)
    * Varint encoding efficiency verification
    
    **Run tests:**
    
    ```bash
    cd dart/packages/fory-test
    dart run build_runner build --delete-conflicting-outputs
    dart test test/struct_test/uint_annotated_struct_test.dart
    ```
    
    ### 3. Fixed Null Check Error in Key Annotation Analyzer
    
    **Problem:** The `key_annotation_analyzer.dart` was attempting to access
    annotation fields even when no `@ForyKey` annotation was present,
    causing a null check operator error.
    
    **Solution:** Added additional check to ensure we only access annotation
    fields when a `@ForyKey` annotation is actually found:
    
    Before
    ```dart
    if (anno != null){
    ```
    After
    ```dart
    if (getMeta && anno != null){
    ```
    
    This ensures that:
    - We only try to read annotation fields when `getMeta` is true (meaning
    we found a `@ForyKey` annotation)
    - Fields without `@ForyKey` annotations correctly default to
    `includeFromFory: true` and `includeToFory: true`
    - Code generation no longer crashes on structs with unannotated fields
    
    ## Related issues
    
    Completes the uint annotation testing and fixes a critical bug that
    prevented code generation from working with fields lacking `@ForyKey`
    annotations.
    
    ## Does this PR introduce any user-facing change?
    
    * [ ] Does this PR introduce any public API change?
      * No new APIs - only adds test coverage and fixes a bug
    
    * [ ] Does this PR introduce any binary protocol compatibility change?
      * No changes to binary encoding format
      * Bug fix only affects code generation, not runtime serialization
    
    ## Benchmark
    
    N/A - This PR adds test coverage and fixes a code generation bug. No
    runtime performance impact.
---
 .../lib/entity/uint_annotated_struct.dart          |  82 ++++++++++
 .../struct_test/uint_annotated_struct_test.dart    | 175 +++++++++++++++++++++
 .../impl/annotation/key_annotation_analyzer.dart   |   2 +-
 3 files changed, 258 insertions(+), 1 deletion(-)

diff --git a/dart/packages/fory-test/lib/entity/uint_annotated_struct.dart 
b/dart/packages/fory-test/lib/entity/uint_annotated_struct.dart
new file mode 100644
index 000000000..dcc8b0595
--- /dev/null
+++ b/dart/packages/fory-test/lib/entity/uint_annotated_struct.dart
@@ -0,0 +1,82 @@
+/*
+ * 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_annotated_struct.g.dart';
+
+/// Test struct for uint type annotations.
+/// Uses native int types with annotations to specify serialization format.
+@ForyClass(promiseAcyclic: true)
+class UIntAnnotatedStruct with _$UIntAnnotatedStructFory {
+  @Uint8Type()
+  final int age;
+
+  @Uint16Type()
+  final int port;
+
+  @Uint32Type()
+  final int count;
+
+  @Uint32Type(encoding: UintEncoding.varint)
+  final int varCount;
+
+  @Uint64Type()
+  final int id;
+
+  @Uint64Type(encoding: UintEncoding.varint)
+  final int varId;
+
+  @Uint64Type(encoding: UintEncoding.tagged)
+  final int taggedId;
+
+  const UIntAnnotatedStruct({
+    required this.age,
+    required this.port,
+    required this.count,
+    required this.varCount,
+    required this.id,
+    required this.varId,
+    required this.taggedId,
+  });
+
+  @override
+  bool operator ==(Object other) {
+    return identical(this, other) ||
+        (other is UIntAnnotatedStruct &&
+            runtimeType == other.runtimeType &&
+            age == other.age &&
+            port == other.port &&
+            count == other.count &&
+            varCount == other.varCount &&
+            id == other.id &&
+            varId == other.varId &&
+            taggedId == other.taggedId);
+  }
+
+  @override
+  int get hashCode =>
+      age.hashCode ^
+      port.hashCode ^
+      count.hashCode ^
+      varCount.hashCode ^
+      id.hashCode ^
+      varId.hashCode ^
+      taggedId.hashCode;
+}
diff --git 
a/dart/packages/fory-test/test/struct_test/uint_annotated_struct_test.dart 
b/dart/packages/fory-test/test/struct_test/uint_annotated_struct_test.dart
new file mode 100644
index 000000000..91fad5f98
--- /dev/null
+++ b/dart/packages/fory-test/test/struct_test/uint_annotated_struct_test.dart
@@ -0,0 +1,175 @@
+/*
+ * 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_annotated_struct.dart';
+import 'package:test/test.dart';
+
+void main() {
+  group('UInt annotated struct serialization', () {
+    test('serializes and deserializes annotated uint fields correctly', () {
+      // Create test instance with native int types
+      var original = UIntAnnotatedStruct(
+        age: 25,
+        port: 8080,
+        count: 1000000,
+        varCount: 500000,
+        id: 9223372036854775807,
+        varId: 4611686018427387903,
+        taggedId: 1152921504606846975,
+      );
+
+      // Serialize
+      var fory = Fory();
+      fory.register($UIntAnnotatedStruct);
+      var bytes = fory.toFory(original);
+
+      expect(bytes.isNotEmpty, isTrue);
+
+      // Deserialize
+      var decoded = fory.fromFory(bytes) as UIntAnnotatedStruct;
+
+      // Verify values
+      expect(decoded.age, 25);
+      expect(decoded.port, 8080);
+      expect(decoded.count, 1000000);
+      expect(decoded.varCount, 500000);
+      expect(decoded.id, 9223372036854775807);
+      expect(decoded.varId, 4611686018427387903);
+      expect(decoded.taggedId, 1152921504606846975);
+    });
+
+    test('handles uint8 max value correctly', () {
+      var original = UIntAnnotatedStruct(
+        age: 255, // Max UInt8
+        port: 100,
+        count: 100,
+        varCount: 100,
+        id: 100,
+        varId: 100,
+        taggedId: 100,
+      );
+
+      var fory = Fory();
+      fory.register($UIntAnnotatedStruct);
+      var bytes = fory.toFory(original);
+      var decoded = fory.fromFory(bytes) as UIntAnnotatedStruct;
+
+      expect(decoded.age, 255);
+    });
+
+    test('handles uint16 max value correctly', () {
+      var original = UIntAnnotatedStruct(
+        age: 100,
+        port: 65535, // Max UInt16
+        count: 100,
+        varCount: 100,
+        id: 100,
+        varId: 100,
+        taggedId: 100,
+      );
+
+      var fory = Fory();
+      fory.register($UIntAnnotatedStruct);
+      var bytes = fory.toFory(original);
+      var decoded = fory.fromFory(bytes) as UIntAnnotatedStruct;
+
+      expect(decoded.port, 65535);
+    });
+
+    test('handles uint32 max value correctly', () {
+      var original = UIntAnnotatedStruct(
+        age: 100,
+        port: 100,
+        count: 4294967295, // Max UInt32
+        varCount: 4294967295, // Max UInt32
+        id: 100,
+        varId: 100,
+        taggedId: 100,
+      );
+
+      var fory = Fory();
+      fory.register($UIntAnnotatedStruct);
+      var bytes = fory.toFory(original);
+      var decoded = fory.fromFory(bytes) as UIntAnnotatedStruct;
+
+      expect(decoded.count, 4294967295);
+      expect(decoded.varCount, 4294967295);
+    });
+
+    test('handles min values correctly', () {
+      var original = UIntAnnotatedStruct(
+        age: 0,
+        port: 0,
+        count: 0,
+        varCount: 0,
+        id: 0,
+        varId: 0,
+        taggedId: 0,
+      );
+
+      var fory = Fory();
+      fory.register($UIntAnnotatedStruct);
+      var bytes = fory.toFory(original);
+      var decoded = fory.fromFory(bytes) as UIntAnnotatedStruct;
+
+      expect(decoded.age, 0);
+      expect(decoded.port, 0);
+      expect(decoded.count, 0);
+      expect(decoded.varCount, 0);
+      expect(decoded.id, 0);
+      expect(decoded.varId, 0);
+      expect(decoded.taggedId, 0);
+    });
+
+    test('varint encoding uses less space for small values', () {
+      var smallValues = UIntAnnotatedStruct(
+        age: 1,
+        port: 1,
+        count: 1,
+        varCount: 1,
+        id: 1,
+        varId: 1,
+        taggedId: 1,
+      );
+
+      var largeValues = UIntAnnotatedStruct(
+        age: 1,
+        port: 1,
+        count: 4294967295,
+        varCount: 4294967295,
+        id: 1,
+        varId: 1,
+        taggedId: 1,
+      );
+
+      var fory = Fory();
+      fory.register($UIntAnnotatedStruct);
+      
+      var smallBytes = fory.toFory(smallValues);
+      var largeBytes = fory.toFory(largeValues);
+
+      // Varint should use less space for small values
+      // Fixed-length uint32 always uses 4 bytes regardless of value
+      expect(smallBytes.length, lessThan(largeBytes.length));
+    });
+  });
+}
diff --git 
a/dart/packages/fory/lib/src/codegen/analyze/impl/annotation/key_annotation_analyzer.dart
 
b/dart/packages/fory/lib/src/codegen/analyze/impl/annotation/key_annotation_analyzer.dart
index 3e5c3344f..d89ec47ae 100644
--- 
a/dart/packages/fory/lib/src/codegen/analyze/impl/annotation/key_annotation_analyzer.dart
+++ 
b/dart/packages/fory/lib/src/codegen/analyze/impl/annotation/key_annotation_analyzer.dart
@@ -57,7 +57,7 @@ class KeyAnnotationAnalyzer {
     // If there is no annotation, both includeFromFory and includeToFory 
default to true.
     bool includeFromFory = true;
     bool includeToFory = true;
-    if (anno != null){
+    if (getMeta && anno != null){
       includeFromFory = anno.getField("includeFromFory")!.toBoolValue()!;
       includeToFory = anno.getField("includeToFory")!.toBoolValue()!;
       // serializeToVar = anno.getField("serializeTo")?.variable;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to