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 7a19a069b feat: add unsigned number for dart (#3144)
7a19a069b is described below

commit 7a19a069b59e9e423f8ee2b790a644ea51656932
Author: Ayush Kumar <[email protected]>
AuthorDate: Sat Jan 17 19:22:56 2026 +0530

    feat: add unsigned number for dart (#3144)
    
    ## Why?
    
    Dart doesn't have native unsigned integer types (only a single 64-bit
    signed int but many other languages (Rust, Go, C++, JavaScript) do. When
    serializing data across languages, we need to properly handle unsigned
    integers to ensure correct values and efficient encoding.
    
    For example:
    
    * A Rust `u32` with value `3_000_000_000` cannot be directly represented
    in Dart without proper unsigned handling
    * Variable-length encoding for unsigned integers can skip zigzag
    encoding overhead
    * Cross-language compatibility requires proper unsigned type support in
    the protocol
    
    ## What does this PR do?
    
    ### 1. Adds Unsigned Integer Type Support (Dart)
    
    **New type IDs**: `UINT8` (40), `UINT16` (41), `UINT32` (42),
    `VAR_UINT32` (43), `UINT64` (44), `VAR_UINT64` (45), `TAGGED_UINT64`
    (46)
    
    Unsigned types use the same bit width as signed types but interpret
    values in the unsigned range.
    
    ### 2. Dart: Adds Wrapper Classes for Fixed-Size Unsigned Integers
    
    Created `UInt8` `UInt16` and `UInt32` wrapper classes that extend
    `FixedNum`:
    
    ```dart
    import 'package:fory/src/datatype/uint8.dart';
    
    var value = UInt8(255);
    var result = value + UInt8(1);  // Automatically wraps to 0
    ```
    
    **Features:**
    * Automatic overflow/underflow wrapping using bitwise operations
    * Full operator support (arithmetic, bitwise, comparison)
    * Type conversions (toInt, toDouble, toString)
    
    **Core wrapping logic:**
    
    ```dart
    static int _convert(num value) {
      if (value is int) {
        return value & 0xFF;  // Keeps only lowest 8 bits for UInt8
      }
      return _convert(value.toInt());
    }
    ```
    
    ### 3. Dart: Adds Serializers for All Unsigned Types
    
    Implemented 7 serializer classes following the existing cache pattern:
    
    ```dart
    final class UInt8Serializer extends Serializer<FixedNum> {
      UInt8 read(ByteReader br, ...) => UInt8(br.readUint8());
      void write(ByteWriter bw, UInt8 v, ...) => bw.writeUint8(v.toInt());
    }
    ```
    
    **ByteReader/Writer methods used:**
    * UInt8/16/32: `readUint8/16/32()`, `writeUint8/16/32()`
    * VarUInt32: `readVarUint32()`, `writeVarUint32()`
    * UInt64: `readUint64()`, `writeUint64()`
    * VarUInt64/TaggedUInt64: `readVarInt64()`, `writeVarInt64()`
    
    ### 4. Dart: Adds Comprehensive Test Suite
    
    Created test coverage for all unsigned types:
    
    ```dart
    test('wraps on overflow', () {
      var a = UInt8(256);  // Overflow to 0
      var b = UInt8(257);  // Overflow to 1
      var c = UInt8(-1);   // Wraps to 255
    
      expect(a.value, 0);
      expect(b.value, 1);
      expect(c.value, 255);
    });
    ```
    
    **Run tests:**
    
    ```bash
    cd dart/packages/fory-test
    dart test test/datatype_test/uint_test.dart
    ```
    
    ## Related Issue
    - Closes #3131
    
    ## Does this PR introduce any user-facing change?
    
    * [x] Does this PR introduce any public API change?
      * **Dart**: New data type classes `UInt8`, `UInt16`, `UInt32`
    * **Dart**: New enum types in `ObjType`: `UINT8`, `UINT16`, `UINT32`,
    `VAR_UINT32`, `UINT64`, `VAR_UINT64`, `TAGGED_UINT64`
      * **Dart**: New serializers for all 7 unsigned types
    
    * [x] Does this PR introduce any binary protocol compatibility change?
      * Adds new type IDs for unsigned integers (40-46)
      * Existing signed integer encoding remains compatible
    * Cross-language compatibility maintained with JavaScript implementation
    ## Benchmark
    
    N/A - This PR focuses on correctness and cross-language compatibility.
    Performance characteristics of unsigned types are similar to their
    signed counterparts.
---
 .../fory-test/test/datatype_test/uint_test.dart    | 232 ++++++++++++++++++++
 dart/packages/fory/lib/fory.dart                   |   4 +
 .../fory/lib/src/annotation/uint_types.dart        | 105 +++++++++
 dart/packages/fory/lib/src/const/obj_type.dart     |  39 +++-
 dart/packages/fory/lib/src/datatype/uint16.dart    | 117 +++++++++++
 dart/packages/fory/lib/src/datatype/uint32.dart    | 117 +++++++++++
 dart/packages/fory/lib/src/datatype/uint8.dart     | 117 +++++++++++
 .../src/serializer/primitive_type_serializer.dart  | 234 +++++++++++++++++++++
 8 files changed, 956 insertions(+), 9 deletions(-)

diff --git a/dart/packages/fory-test/test/datatype_test/uint_test.dart 
b/dart/packages/fory-test/test/datatype_test/uint_test.dart
new file mode 100644
index 000000000..3866b3ec4
--- /dev/null
+++ b/dart/packages/fory-test/test/datatype_test/uint_test.dart
@@ -0,0 +1,232 @@
+/*
+ * 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/src/datatype/uint8.dart';
+import 'package:fory/src/datatype/uint16.dart';
+import 'package:fory/src/datatype/uint32.dart';
+import 'package:test/test.dart';
+
+void main() {
+  group('UInt8 behaviors', () {
+    group('range & conversion', () {
+      test('preserves in-range values', () {
+        var a = UInt8(0);
+        var b = UInt8(255);
+
+        expect(a.value, 0);
+        expect(b.value, 255);
+      });
+
+      test('wraps on overflow', () {
+        var a = UInt8(256);  // Overflow to 0
+        var b = UInt8(257);  // Overflow to 1
+        var c = UInt8(512);  // Overflow to 0
+        var d = UInt8(-1);   // Wraps to 255
+
+        expect(a.value, 0);
+        expect(b.value, 1);
+        expect(c.value, 0);
+        expect(d.value, 255);
+      });
+
+      test('truncates float inputs', () {
+        var a = UInt8(42.7);
+        var b = UInt8(255.9);
+
+        expect(a.value, 42);
+        expect(b.value, 255);
+      });
+
+      test('min/max constants and instances', () {
+        expect(UInt8.MIN_VALUE, 0);
+        expect(UInt8.MAX_VALUE, 255);
+        expect(UInt8.minValue.value, 0);
+        expect(UInt8.maxValue.value, 255);
+      });
+    });
+
+    group('arithmetic operators with overflow', () {
+      test('addition with overflow', () {
+        var a = UInt8(200);
+        var b = UInt8(100);
+        var result = a + b;
+
+        expect(result, isA<UInt8>());
+        expect(result.value, 44); // 200 + 100 = 300, which overflows to 44
+      });
+
+      test('subtraction with underflow', () {
+        var a = UInt8(50);
+        var b = UInt8(100);
+        var result = a - b;
+
+        expect(result, isA<UInt8>());
+        expect(result.value, 206); // 50 - 100 = -50, which wraps to 206
+      });
+
+      test('multiplication with overflow', () {
+        var a = UInt8(20);
+        var b = UInt8(20);
+        var result = a * b;
+
+        expect(result, isA<UInt8>());
+        expect(result.value, 144); // 20 * 20 = 400, which overflows to 144
+      });
+    });
+
+    group('comparison operators', () {
+      test('less than', () {
+        var a = UInt8(10);
+        var b = UInt8(20);
+
+        expect(a < b, isTrue);
+        expect(b < a, isFalse);
+        expect(a < 20, isTrue);
+      });
+
+      test('greater than', () {
+        var a = UInt8(200);
+        var b = UInt8(100);
+
+        expect(a > b, isTrue);
+        expect(b > a, isFalse);
+        expect(a > 100, isTrue);
+      });
+    });
+
+    group('equality & hashCode', () {
+      test('equality', () {
+        var a = UInt8(42);
+        var b = UInt8(42);
+        var c = UInt8(43);
+
+        expect(a == b, isTrue);
+        expect(a == c, isFalse);
+        expect(a == 42, isTrue);
+      });
+
+      test('hashCode consistency', () {
+        var a = UInt8(42);
+        var b = UInt8(42);
+
+        expect(a.hashCode == b.hashCode, isTrue);
+      });
+    });
+  });
+
+  group('UInt16 behaviors', () {
+    group('range & conversion', () {
+      test('preserves in-range values', () {
+        var a = UInt16(0);
+        var b = UInt16(65535);
+
+        expect(a.value, 0);
+        expect(b.value, 65535);
+      });
+
+      test('wraps on overflow', () {
+        var a = UInt16(65536);  // Overflow to 0
+        var b = UInt16(65537);  // Overflow to 1
+        var c = UInt16(-1);     // Wraps to 65535
+
+        expect(a.value, 0);
+        expect(b.value, 1);
+        expect(c.value, 65535);
+      });
+
+      test('min/max constants', () {
+        expect(UInt16.MIN_VALUE, 0);
+        expect(UInt16.MAX_VALUE, 65535);
+        expect(UInt16.minValue.value, 0);
+        expect(UInt16.maxValue.value, 65535);
+      });
+    });
+
+    group('arithmetic operators', () {
+      test('addition with overflow', () {
+        var a = UInt16(60000);
+        var b = UInt16(10000);
+        var result = a + b;
+
+        expect(result, isA<UInt16>());
+        expect(result.value, 4464); // 70000 overflows to 4464
+      });
+
+      test('subtraction with underflow', () {
+        var a = UInt16(1000);
+        var b = UInt16(2000);
+        var result = a - b;
+
+        expect(result, isA<UInt16>());
+        expect(result.value, 64536); // -1000 wraps to 64536
+      });
+    });
+  });
+
+  group('UInt32 behaviors', () {
+    group('range & conversion', () {
+      test('preserves in-range values', () {
+        var a = UInt32(0);
+        var b = UInt32(4294967295);
+
+        expect(a.value, 0);
+        expect(b.value, 4294967295);
+      });
+
+      test('wraps on overflow', () {
+        var a = UInt32(4294967296);  // Overflow to 0
+        var b = UInt32(4294967297);  // Overflow to 1
+        var c = UInt32(-1);          // Wraps to 4294967295
+
+        expect(a.value, 0);
+        expect(b.value, 1);
+        expect(c.value, 4294967295);
+      });
+
+      test('min/max constants', () {
+        expect(UInt32.MIN_VALUE, 0);
+        expect(UInt32.MAX_VALUE, 4294967295);
+        expect(UInt32.minValue.value, 0);
+        expect(UInt32.maxValue.value, 4294967295);
+      });
+    });
+
+    group('arithmetic operators', () {
+      test('addition with overflow', () {
+        var a = UInt32(4000000000);
+        var b = UInt32(500000000);
+        var result = a + b;
+
+        expect(result, isA<UInt32>());
+        expect(result.value, 205032704); // 4500000000 % (2^32) = 205032704
+      });
+
+      test('large value operations', () {
+        var a = UInt32(2147483648); // Half of max value
+        var b = UInt32(2147483648);
+        var result = a + b;
+
+        expect(result, isA<UInt32>());
+        expect(result.value, 0); // Exactly overflows to 0
+      });
+    });
+  });
+}
diff --git a/dart/packages/fory/lib/fory.dart b/dart/packages/fory/lib/fory.dart
index 023277f3f..a6493e9ad 100644
--- a/dart/packages/fory/lib/fory.dart
+++ b/dart/packages/fory/lib/fory.dart
@@ -26,6 +26,7 @@ export 'src/annotation/fory_key.dart';
 export 'src/annotation/fory_class.dart';
 export 'src/annotation/fory_enum.dart';
 export 'src/annotation/fory_constructor.dart';
+export 'src/annotation/uint_types.dart';
 
 // Analysis meta
 export 'src/meta/specs/class_spec.dart';
@@ -56,6 +57,9 @@ export 'src/datatype/fory_fixed_num.dart';
 export 'src/datatype/int8.dart';
 export 'src/datatype/int16.dart';
 export 'src/datatype/int32.dart';
+export 'src/datatype/uint8.dart';
+export 'src/datatype/uint16.dart';
+export 'src/datatype/uint32.dart';
 export 'src/datatype/float32.dart';
 export 'src/datatype/local_date.dart';
 export 'src/datatype/timestamp.dart';
diff --git a/dart/packages/fory/lib/src/annotation/uint_types.dart 
b/dart/packages/fory/lib/src/annotation/uint_types.dart
new file mode 100644
index 000000000..a2b0af97a
--- /dev/null
+++ b/dart/packages/fory/lib/src/annotation/uint_types.dart
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+/// Annotation to mark a field as unsigned 8-bit integer (0-255).
+/// 
+/// Use this annotation on `int` fields to serialize them as UINT8 type.
+/// 
+/// Example:
+/// ```dart
+/// class MyStruct {
+///   @Uint8Type()
+///   int age;  // Serialized as UINT8
+/// }
+/// ```
+class Uint8Type {
+  const Uint8Type();
+}
+
+/// Annotation to mark a field as unsigned 16-bit integer (0-65535).
+/// 
+/// Use this annotation on `int` fields to serialize them as UINT16 type.
+/// 
+/// Example:
+/// ```dart
+/// class MyStruct {
+///   @Uint16Type()
+///   int port;  // Serialized as UINT16
+/// }
+/// ```
+class Uint16Type {
+  const Uint16Type();
+}
+
+/// Encoding options for 32-bit and 64-bit unsigned integers.
+enum UintEncoding {
+  /// Fixed-length encoding (4 bytes for uint32, 8 bytes for uint64)
+  fixed,
+  
+  /// Variable-length encoding (VAR_UINT32 or VAR_UINT64)
+  varint,
+  
+  /// Tagged variable-length encoding (only for uint64)
+  tagged,
+}
+
+/// Annotation to mark a field as unsigned 32-bit integer (0-4294967295).
+/// 
+/// Use this annotation on `int` fields to serialize them as UINT32 or 
VAR_UINT32 type.
+/// 
+/// Example:
+/// ```dart
+/// class MyStruct {
+///   @Uint32Type()
+///   int count;  // Serialized as UINT32 (fixed)
+///   
+///   @Uint32Type(encoding: UintEncoding.varint)
+///   int varCount;  // Serialized as VAR_UINT32
+/// }
+/// ```
+class Uint32Type {
+  final UintEncoding encoding;
+  
+  const Uint32Type({this.encoding = UintEncoding.fixed});
+}
+
+/// Annotation to mark a field as unsigned 64-bit integer.
+/// 
+/// Use this annotation on `int` fields to serialize them as UINT64, 
VAR_UINT64, or TAGGED_UINT64 type.
+/// 
+/// Example:
+/// ```dart
+/// class MyStruct {
+///   @Uint64Type()
+///   int id;  // Serialized as UINT64 (fixed)
+///   
+///   @Uint64Type(encoding: UintEncoding.varint)
+///   int varId;  // Serialized as VAR_UINT64
+///   
+///   @Uint64Type(encoding: UintEncoding.tagged)
+///   int taggedId;  // Serialized as TAGGED_UINT64
+/// }
+/// ```
+class Uint64Type {
+  final UintEncoding encoding;
+  
+  const Uint64Type({this.encoding = UintEncoding.fixed});
+}
diff --git a/dart/packages/fory/lib/src/const/obj_type.dart 
b/dart/packages/fory/lib/src/const/obj_type.dart
index da0c3d3f3..a7fb48df6 100644
--- a/dart/packages/fory/lib/src/const/obj_type.dart
+++ b/dart/packages/fory/lib/src/const/obj_type.dart
@@ -148,28 +148,49 @@ enum ObjType {
   INT8_ARRAY(31, true), // 31
 
   /// One dimensional int16 array.
-  INT16_ARRAY(32, true),
+  INT16_ARRAY(32, true), // 32
 
   /// One dimensional int32 array.
-  INT32_ARRAY(33, true),
+  INT32_ARRAY(33, true), // 33
 
   /// One dimensional int64 array.
-  INT64_ARRAY(34, true),
+  INT64_ARRAY(34, true), // 34
 
   /// One dimensional half_float_16 array.
-  FLOAT16_ARRAY(35, true),
+  FLOAT16_ARRAY(35, true), // 35
 
   /// One dimensional float32 array.
-  FLOAT32_ARRAY(36, true),
+  FLOAT32_ARRAY(36, true), // 36
 
   /// One dimensional float64 array.
-  FLOAT64_ARRAY(37, true),
+  FLOAT64_ARRAY(37, true), // 37
 
   /// An (arrow record batch) object.
-  ARROW_RECORD_BATCH(38, false),
+  ARROW_RECORD_BATCH(38, false), // 38
 
   /// An (arrow table) object.
-  ARROW_TABLE(39, false);
+  ARROW_TABLE(39, false), // 39
+
+  /// Unsigned 8-bit integer
+  UINT8(40, true), // 40
+
+  /// Unsigned 16-bit little-endian integer
+  UINT16(41, true), // 41
+
+  /// Unsigned 32-bit little-endian integer
+  UINT32(42, true), // 42
+
+  /// var_uint32: a 32-bit unsigned integer which uses fory var_uint32 
encoding.
+  VAR_UINT32(43, true), // 43
+
+  /// Unsigned 64-bit little-endian integer
+  UINT64(44, true), // 44
+
+  /// var_uint64: a 64-bit unsigned integer which uses fory var_uint64 
encoding.
+  VAR_UINT64(45, true), // 45
+
+  /// tagged_uint64: a 64-bit unsigned integer which uses fory tagged 
var_uint64 encoding.
+  TAGGED_UINT64(46, true); // 46
 
   final int id;
   final bool independent;
@@ -178,7 +199,7 @@ enum ObjType {
 
   static ObjType? fromId(int id) {
     // The current implementation is linear, so it's simpler here. If the id 
and ordinal become irregular in the future, this won't work.
-    if (id >= 1 && id <= 39) return ObjType.values[id];
+    if (id >= 1 && id <= 46) return ObjType.values[id];
     return null;
   }
 
diff --git a/dart/packages/fory/lib/src/datatype/uint16.dart 
b/dart/packages/fory/lib/src/datatype/uint16.dart
new file mode 100644
index 000000000..e8aa7be69
--- /dev/null
+++ b/dart/packages/fory/lib/src/datatype/uint16.dart
@@ -0,0 +1,117 @@
+/*
+ * 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 'fory_fixed_num.dart';
+
+/// UInt16: 16-bit unsigned integer (0 to 65535)
+final class UInt16 extends FixedNum {
+  static const int MIN_VALUE = 0;
+  static const int MAX_VALUE = 65535;
+
+  static UInt16 get maxValue => UInt16(MAX_VALUE);
+  static UInt16 get minValue => UInt16(MIN_VALUE);
+
+  final int _value;
+
+  UInt16(num input) : _value = _convert(input);
+
+  static int _convert(num value) {
+    if (value is int) {
+      // Apply 16-bit unsigned integer overflow behavior
+      return value & 0xFFFF;  // Keep only the lowest 16 bits (0-65535)
+    } else {
+      return _convert(value.toInt());
+    }
+  }
+
+  @override
+  int get value => _value;
+
+  // Operators
+  UInt16 operator +(dynamic other) =>
+      UInt16(_value + (other is FixedNum ? other.value : other));
+
+  UInt16 operator -(dynamic other) =>
+      UInt16(_value - (other is FixedNum ? other.value : other));
+
+  UInt16 operator *(dynamic other) =>
+      UInt16(_value * (other is FixedNum ? other.value : other));
+
+  double operator /(dynamic other) =>
+      _value / (other is FixedNum ? other.value : other);
+
+  UInt16 operator ~/(dynamic other) =>
+      UInt16(_value ~/ (other is FixedNum ? other.value : other));
+
+  UInt16 operator %(dynamic other) =>
+      UInt16(_value % (other is FixedNum ? other.value : other));
+
+  UInt16 operator -() => UInt16(-_value);
+
+  // Bitwise operations
+  UInt16 operator &(dynamic other) =>
+      UInt16(_value & (other is FixedNum ? other.value : other).toInt());
+
+  UInt16 operator |(dynamic other) =>
+      UInt16(_value | (other is FixedNum ? other.value : other).toInt());
+
+  UInt16 operator ^(dynamic other) =>
+      UInt16(_value ^ (other is FixedNum ? other.value : other).toInt());
+
+  UInt16 operator ~() => UInt16(~_value);
+
+  UInt16 operator <<(int shiftAmount) => UInt16(_value << shiftAmount);
+  UInt16 operator >>(int shiftAmount) => UInt16(_value >> shiftAmount);
+
+  // Comparison
+  bool operator <(dynamic other) =>
+      _value < (other is FixedNum ? other.value : other);
+
+  bool operator <=(dynamic other) =>
+      _value <= (other is FixedNum ? other.value : other);
+
+  bool operator >(dynamic other) =>
+      _value > (other is FixedNum ? other.value : other);
+
+  bool operator >=(dynamic other) =>
+      _value >= (other is FixedNum ? other.value : other);
+
+  // Equality
+  @override
+  bool operator ==(Object other) {
+    if (other is FixedNum) return _value == other.value;
+    if (other is num) return _value == other;
+    return false;
+  }
+
+  @override
+  int get hashCode => _value.hashCode;
+
+  // Common num methods
+  int abs() => _value;
+  int get sign => _value == 0 ? 0 : 1;
+  bool get isNegative => false;
+
+  // Type conversions
+  int toInt() => _value;
+  double toDouble() => _value.toDouble();
+
+  @override
+  String toString() => _value.toString();
+}
diff --git a/dart/packages/fory/lib/src/datatype/uint32.dart 
b/dart/packages/fory/lib/src/datatype/uint32.dart
new file mode 100644
index 000000000..f913cd7af
--- /dev/null
+++ b/dart/packages/fory/lib/src/datatype/uint32.dart
@@ -0,0 +1,117 @@
+/*
+ * 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 'fory_fixed_num.dart';
+
+/// UInt32: 32-bit unsigned integer (0 to 4294967295)
+final class UInt32 extends FixedNum {
+  static const int MIN_VALUE = 0;
+  static const int MAX_VALUE = 4294967295;
+
+  static UInt32 get maxValue => UInt32(MAX_VALUE);
+  static UInt32 get minValue => UInt32(MIN_VALUE);
+
+  final int _value;
+
+  UInt32(num input) : _value = _convert(input);
+
+  static int _convert(num value) {
+    if (value is int) {
+      // Apply 32-bit unsigned integer overflow behavior
+      return value & 0xFFFFFFFF;  // Keep only the lowest 32 bits 
(0-4294967295)
+    } else {
+      return _convert(value.toInt());
+    }
+  }
+
+  @override
+  int get value => _value;
+
+  // Operators
+  UInt32 operator +(dynamic other) =>
+      UInt32(_value + (other is FixedNum ? other.value : other));
+
+  UInt32 operator -(dynamic other) =>
+      UInt32(_value - (other is FixedNum ? other.value : other));
+
+  UInt32 operator *(dynamic other) =>
+      UInt32(_value * (other is FixedNum ? other.value : other));
+
+  double operator /(dynamic other) =>
+      _value / (other is FixedNum ? other.value : other);
+
+  UInt32 operator ~/(dynamic other) =>
+      UInt32(_value ~/ (other is FixedNum ? other.value : other));
+
+  UInt32 operator %(dynamic other) =>
+      UInt32(_value % (other is FixedNum ? other.value : other));
+
+  UInt32 operator -() => UInt32(-_value);
+
+  // Bitwise operations
+  UInt32 operator &(dynamic other) =>
+      UInt32(_value & (other is FixedNum ? other.value : other).toInt());
+
+  UInt32 operator |(dynamic other) =>
+      UInt32(_value | (other is FixedNum ? other.value : other).toInt());
+
+  UInt32 operator ^(dynamic other) =>
+      UInt32(_value ^ (other is FixedNum ? other.value : other).toInt());
+
+  UInt32 operator ~() => UInt32(~_value);
+
+  UInt32 operator <<(int shiftAmount) => UInt32(_value << shiftAmount);
+  UInt32 operator >>(int shiftAmount) => UInt32(_value >> shiftAmount);
+
+  // Comparison
+  bool operator <(dynamic other) =>
+      _value < (other is FixedNum ? other.value : other);
+
+  bool operator <=(dynamic other) =>
+      _value <= (other is FixedNum ? other.value : other);
+
+  bool operator >(dynamic other) =>
+      _value > (other is FixedNum ? other.value : other);
+
+  bool operator >=(dynamic other) =>
+      _value >= (other is FixedNum ? other.value : other);
+
+  // Equality
+  @override
+  bool operator ==(Object other) {
+    if (other is FixedNum) return _value == other.value;
+    if (other is num) return _value == other;
+    return false;
+  }
+
+  @override
+  int get hashCode => _value.hashCode;
+
+  // Common num methods
+  int abs() => _value;
+  int get sign => _value == 0 ? 0 : 1;
+  bool get isNegative => false;
+
+  // Type conversions
+  int toInt() => _value;
+  double toDouble() => _value.toDouble();
+
+  @override
+  String toString() => _value.toString();
+}
diff --git a/dart/packages/fory/lib/src/datatype/uint8.dart 
b/dart/packages/fory/lib/src/datatype/uint8.dart
new file mode 100644
index 000000000..be14b8773
--- /dev/null
+++ b/dart/packages/fory/lib/src/datatype/uint8.dart
@@ -0,0 +1,117 @@
+/*
+ * 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 'fory_fixed_num.dart';
+
+/// UInt8: 8-bit unsigned integer (0 to 255)
+final class UInt8 extends FixedNum {
+  static const int MIN_VALUE = 0;
+  static const int MAX_VALUE = 255;
+
+  static UInt8 get maxValue => UInt8(MAX_VALUE);
+  static UInt8 get minValue => UInt8(MIN_VALUE);
+
+  final int _value;
+
+  UInt8(num input) : _value = _convert(input);
+
+  static int _convert(num value) {
+    if (value is int) {
+      // Apply 8-bit unsigned integer overflow behavior
+      return value & 0xFF;  // Keep only the lowest 8 bits (0-255)
+    } else {
+      return _convert(value.toInt());
+    }
+  }
+
+  @override
+  int get value => _value;
+
+  // Operators
+  UInt8 operator +(dynamic other) =>
+      UInt8(_value + (other is FixedNum ? other.value : other));
+
+  UInt8 operator -(dynamic other) =>
+      UInt8(_value - (other is FixedNum ? other.value : other));
+
+  UInt8 operator *(dynamic other) =>
+      UInt8(_value * (other is FixedNum ? other.value : other));
+
+  double operator /(dynamic other) =>
+      _value / (other is FixedNum ? other.value : other);
+
+  UInt8 operator ~/(dynamic other) =>
+      UInt8(_value ~/ (other is FixedNum ? other.value : other));
+
+  UInt8 operator %(dynamic other) =>
+      UInt8(_value % (other is FixedNum ? other.value : other));
+
+  UInt8 operator -() => UInt8(-_value);
+
+  // Bitwise operations
+  UInt8 operator &(dynamic other) =>
+      UInt8(_value & (other is FixedNum ? other.value : other).toInt());
+
+  UInt8 operator |(dynamic other) =>
+      UInt8(_value | (other is FixedNum ? other.value : other).toInt());
+
+  UInt8 operator ^(dynamic other) =>
+      UInt8(_value ^ (other is FixedNum ? other.value : other).toInt());
+
+  UInt8 operator ~() => UInt8(~_value);
+
+  UInt8 operator <<(int shiftAmount) => UInt8(_value << shiftAmount);
+  UInt8 operator >>(int shiftAmount) => UInt8(_value >> shiftAmount);
+
+  // Comparison
+  bool operator <(dynamic other) =>
+      _value < (other is FixedNum ? other.value : other);
+
+  bool operator <=(dynamic other) =>
+      _value <= (other is FixedNum ? other.value : other);
+
+  bool operator >(dynamic other) =>
+      _value > (other is FixedNum ? other.value : other);
+
+  bool operator >=(dynamic other) =>
+      _value >= (other is FixedNum ? other.value : other);
+
+  // Equality
+  @override
+  bool operator ==(Object other) {
+    if (other is FixedNum) return _value == other.value;
+    if (other is num) return _value == other;
+    return false;
+  }
+
+  @override
+  int get hashCode => _value.hashCode;
+
+  // Common num methods
+  int abs() => _value;
+  int get sign => _value == 0 ? 0 : 1;
+  bool get isNegative => false;
+
+  // Type conversions
+  int toInt() => _value;
+  double toDouble() => _value.toDouble();
+
+  @override
+  String toString() => _value.toString();
+}
diff --git 
a/dart/packages/fory/lib/src/serializer/primitive_type_serializer.dart 
b/dart/packages/fory/lib/src/serializer/primitive_type_serializer.dart
index 1d6ff45b7..40a13871d 100644
--- a/dart/packages/fory/lib/src/serializer/primitive_type_serializer.dart
+++ b/dart/packages/fory/lib/src/serializer/primitive_type_serializer.dart
@@ -24,6 +24,9 @@ import 'package:fory/src/datatype/fory_fixed_num.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/deserializer_pack.dart';
 import 'package:fory/src/memory/byte_reader.dart';
 import 'package:fory/src/memory/byte_writer.dart';
@@ -305,3 +308,234 @@ final class Float64Serializer extends Serializer<double>{
     bw.writeFloat64(v);
   }
 }
+
+final class _UInt8SerializerCache extends PrimitiveSerializerCache{
+  static UInt8Serializer? serRef;
+  static UInt8Serializer? serNoRef;
+
+  const _UInt8SerializerCache();
+
+  @override
+  Serializer getSerWithRef(bool writeRef) {
+    if (writeRef){
+      serRef ??= UInt8Serializer._(true);
+      return serRef!;
+    } else {
+      serNoRef ??= UInt8Serializer._(false);
+      return serNoRef!;
+    }
+  }
+}
+
+final class UInt8Serializer extends Serializer<FixedNum>{
+  static const SerializerCache cache = _UInt8SerializerCache();
+  UInt8Serializer._(bool writeRef): super(ObjType.UINT8, writeRef);
+
+  @override
+  UInt8 read(ByteReader br, int refId, DeserializerPack pack) {
+    return UInt8(br.readUint8());
+  }
+
+  @override
+  void write(ByteWriter bw, covariant UInt8 v, SerializerPack pack) {
+    bw.writeUint8(v.toInt());
+  }
+}
+
+final class _UInt16SerializerCache extends PrimitiveSerializerCache{
+  static UInt16Serializer? serRef;
+  static UInt16Serializer? serNoRef;
+
+  const _UInt16SerializerCache();
+
+  @override
+  Serializer getSerWithRef(bool writeRef) {
+    if (writeRef){
+      serRef ??= UInt16Serializer._(true);
+      return serRef!;
+    } else {
+      serNoRef ??= UInt16Serializer._(false);
+      return serNoRef!;
+    }
+  }
+}
+
+final class UInt16Serializer extends Serializer<FixedNum>{
+  static const SerializerCache cache = _UInt16SerializerCache();
+  UInt16Serializer._(bool writeRef): super(ObjType.UINT16, writeRef);
+
+  @override
+  UInt16 read(ByteReader br, int refId, DeserializerPack pack) {
+    return UInt16(br.readUint16());
+  }
+
+  @override
+  void write(ByteWriter bw, covariant UInt16 v, SerializerPack pack) {
+    bw.writeUint16(v.toInt());
+  }
+}
+
+final class _UInt32SerializerCache extends PrimitiveSerializerCache{
+  static UInt32Serializer? serRef;
+  static UInt32Serializer? serNoRef;
+
+  const _UInt32SerializerCache();
+
+  @override
+  Serializer getSerWithRef(bool writeRef) {
+    if (writeRef){
+      serRef ??= UInt32Serializer._(true);
+      return serRef!;
+    } else {
+      serNoRef ??= UInt32Serializer._(false);
+      return serNoRef!;
+    }
+  }
+}
+
+final class UInt32Serializer extends Serializer<FixedNum>{
+  static const SerializerCache cache = _UInt32SerializerCache();
+  UInt32Serializer._(bool writeRef): super(ObjType.UINT32, writeRef);
+
+  @override
+  UInt32 read(ByteReader br, int refId, DeserializerPack pack) {
+    return UInt32(br.readUint32());
+  }
+
+  @override
+  void write(ByteWriter bw, covariant UInt32 v, SerializerPack pack) {
+    bw.writeUint32(v.toInt());
+  }
+}
+
+final class _VarUInt32SerializerCache extends PrimitiveSerializerCache{
+  static VarUInt32Serializer? serRef;
+  static VarUInt32Serializer? serNoRef;
+
+  const _VarUInt32SerializerCache();
+
+  @override
+  Serializer getSerWithRef(bool writeRef) {
+    if (writeRef){
+      serRef ??= VarUInt32Serializer._(true);
+      return serRef!;
+    } else {
+      serNoRef ??= VarUInt32Serializer._(false);
+      return serNoRef!;
+    }
+  }
+}
+
+final class VarUInt32Serializer extends Serializer<FixedNum>{
+  static const SerializerCache cache = _VarUInt32SerializerCache();
+  VarUInt32Serializer._(bool writeRef): super(ObjType.VAR_UINT32, writeRef);
+
+  @override
+  UInt32 read(ByteReader br, int refId, DeserializerPack pack) {
+    return UInt32(br.readVarUint32());
+  }
+
+  @override
+  void write(ByteWriter bw, covariant UInt32 v, SerializerPack pack) {
+    bw.writeVarUint32(v.toInt());
+  }
+}
+
+final class _UInt64SerializerCache extends PrimitiveSerializerCache{
+  static UInt64Serializer? serRef;
+  static UInt64Serializer? serNoRef;
+
+  const _UInt64SerializerCache();
+
+  @override
+  Serializer getSerWithRef(bool writeRef) {
+    if (writeRef){
+      serRef ??= UInt64Serializer._(true);
+      return serRef!;
+    } else {
+      serNoRef ??= UInt64Serializer._(false);
+      return serNoRef!;
+    }
+  }
+}
+
+final class UInt64Serializer extends Serializer<int> {
+  static const SerializerCache cache = _UInt64SerializerCache();
+  UInt64Serializer._(bool writeRef): super(ObjType.UINT64, writeRef);
+
+  @override
+  int read(ByteReader br, int refId, DeserializerPack pack) {
+    return br.readUint64();
+  }
+
+  @override
+  void write(ByteWriter bw, int v, SerializerPack pack) {
+    bw.writeUint64(v);
+  }
+}
+
+final class _VarUInt64SerializerCache extends PrimitiveSerializerCache{
+  static VarUInt64Serializer? serRef;
+  static VarUInt64Serializer? serNoRef;
+
+  const _VarUInt64SerializerCache();
+
+  @override
+  Serializer getSerWithRef(bool writeRef) {
+    if (writeRef){
+      serRef ??= VarUInt64Serializer._(true);
+      return serRef!;
+    } else {
+      serNoRef ??= VarUInt64Serializer._(false);
+      return serNoRef!;
+    }
+  }
+}
+
+final class VarUInt64Serializer extends Serializer<int> {
+  static const SerializerCache cache = _VarUInt64SerializerCache();
+  VarUInt64Serializer._(bool writeRef): super(ObjType.VAR_UINT64, writeRef);
+
+  @override
+  int read(ByteReader br, int refId, DeserializerPack pack) {
+    return br.readVarInt64();
+  }
+
+  @override
+  void write(ByteWriter bw, int v, SerializerPack pack) {
+    bw.writeVarInt64(v);
+  }
+}
+
+final class _TaggedUInt64SerializerCache extends PrimitiveSerializerCache{
+  static TaggedUInt64Serializer? serRef;
+  static TaggedUInt64Serializer? serNoRef;
+
+  const _TaggedUInt64SerializerCache();
+
+  @override
+  Serializer getSerWithRef(bool writeRef) {
+    if (writeRef){
+      serRef ??= TaggedUInt64Serializer._(true);
+      return serRef!;
+    } else {
+      serNoRef ??= TaggedUInt64Serializer._(false);
+      return serNoRef!;
+    }
+  }
+}
+
+final class TaggedUInt64Serializer extends Serializer<int> {
+  static const SerializerCache cache = _TaggedUInt64SerializerCache();
+  TaggedUInt64Serializer._(bool writeRef): super(ObjType.TAGGED_UINT64, 
writeRef);
+
+  @override
+  int read(ByteReader br, int refId, DeserializerPack pack) {
+    return br.readVarInt64();
+  }
+
+  @override
+  void write(ByteWriter bw, int v, SerializerPack pack) {
+    bw.writeVarInt64(v);
+  }
+}


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


Reply via email to