chaokunyang commented on code in PR #3482:
URL: https://github.com/apache/fory/pull/3482#discussion_r3051235091


##########
dart/packages/fory/lib/src/codegen/analyze/impl/struct/enum_analyzer_impl.dart:
##########
@@ -17,26 +17,103 @@
  * under the License.
  */
 
+import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:fory/src/codegen/analyze/analysis_type_identifier.dart';
 import 'package:fory/src/codegen/analyze/interface/enum_analyzer.dart';
 import 'package:fory/src/codegen/meta/impl/enum_spec_generator.dart';
 
 class EnumAnalyzerImpl implements EnumAnalyzer {
   const EnumAnalyzerImpl();
 
+  /// Finds a non-constant field annotated with @ForyEnumId().
+  String? _findIdField(EnumElement enumElement) {
+    for (final FieldElement field in enumElement.fields) {
+      if (field.isEnumConstant || field.isSynthetic) continue;
+      for (final ElementAnnotation annotation in field.metadata) {
+        final DartObject? annotationValue = annotation.computeConstantValue();
+        final Element? typeElement = annotationValue?.type?.element;
+        if (typeElement is ClassElement &&
+            AnalysisTypeIdentifier.isForyEnumId(typeElement)) {
+          return field.name;
+        }
+      }
+    }
+    return null;
+  }
+
+  /// Reads @ForyEnumId(id) from per-value annotation.
+  int? _readEnumId(FieldElement enumField) {
+    for (final ElementAnnotation annotation in enumField.metadata) {
+      final DartObject? annotationValue = annotation.computeConstantValue();
+      final Element? typeElement = annotationValue?.type?.element;
+      if (typeElement is ClassElement &&
+          AnalysisTypeIdentifier.isForyEnumId(typeElement)) {
+        return annotationValue?.getField('id')?.toIntValue();
+      }
+    }
+    return null;
+  }
+
   @override
   EnumSpecGenerator analyze(EnumElement enumElement) {
     String packageName = enumElement.location!.components[0];
+    final String enumName = enumElement.name;
+    final List<FieldElement> enumFields =
+        enumElement.fields.where((FieldElement e) => 
e.isEnumConstant).toList();
+    final List<String> enumValues =
+        enumFields.map((FieldElement e) => e.name).toList();
+
+    final String? idFieldName = _findIdField(enumElement);
+    final Map<String, int> enumIds = <String, int>{};
+    final Map<int, String> usedIds = <int, String>{};
+    final List<String> duplicateIds = <String>[];
+    final List<String> missingIdValues = <String>[];
+
+    for (final FieldElement enumField in enumFields) {
+      final int? id = idFieldName != null

Review Comment:
   Validate @ForyEnumId range before generating enum specs
   
   This accepts any `int` from `@ForyEnumId` and later feeds it to 
`writeVarUint32Small7(...)`. Negative values do not fail cleanly here: I 
reproduced `writeVarUint32Small7(-1)` decoding back as `34359738367`, so 
`@ForyEnumId(-1)` silently writes a different wire id than the one the user 
declared. Please reject ids outside the unsigned 32-bit range during analysis, 
and ideally keep a serializer-side assertion as defense in depth.



##########
dart/packages/fory-test/test/datatype_test/enum_serializer_test.dart:
##########
@@ -0,0 +1,191 @@
+/*
+ * 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:checks/checks.dart';
+import 'package:fory/src/collection/stack.dart';
+import 'package:fory/src/config/fory_config.dart';
+import 'package:fory/src/deserialization_dispatcher.dart';
+import 'package:fory/src/deserialization_context.dart';
+import 'package:fory/src/fory_exception.dart';
+import 'package:fory/src/memory/byte_reader.dart';
+import 'package:fory/src/memory/byte_writer.dart';
+import 'package:fory/src/meta/spec_wraps/type_spec_wrap.dart';
+import 'package:fory/src/resolver/deserialization_ref_resolver.dart';
+import 'package:fory/src/resolver/meta_string_writing_resolver.dart';
+import 'package:fory/src/resolver/serialization_ref_resolver.dart';
+import 'package:fory/src/resolver/struct_hash_resolver.dart';
+import 'package:fory/src/resolver/type_resolver.dart';
+import 'package:fory/src/serialization_dispatcher.dart';
+import 'package:fory/src/serialization_context.dart';
+import 'package:fory/src/serializer/enum_serializer.dart';
+import 'package:fory_test/entity/enum_id_foo.dart';
+import 'package:test/test.dart';
+
+String _unusedTagLookup(Type _) => '';
+
+final ForyConfig _config = ForyConfig();
+final TypeResolver _typeResolver = TypeResolver.newOne(_config);
+
+SerializationContext _newSerializationContext() {
+  return SerializationContext(
+    StructHashResolver.inst,
+    _unusedTagLookup,
+    SerializationDispatcher.I,
+    _typeResolver,
+    SerializationRefResolver.getOne(false),
+    SerializationRefResolver.noRefResolver,
+    MetaStringWritingResolver.newInst,
+    Stack<TypeSpecWrap>(),
+  );
+}
+
+DeserializationContext _newDeserializationContext() {
+  return DeserializationContext(
+    StructHashResolver.inst,
+    _unusedTagLookup,
+    _config,
+    (isXLang: true, oobEnabled: false),
+    DeserializationDispatcher.I,
+    DeserializationRefResolver.getOne(false),
+    _typeResolver,
+    Stack<TypeSpecWrap>(),
+  );
+}
+
+void main() {
+  group('Enum serializer', () {
+    test('writes and reads annotated enum ids when all values are annotated',

Review Comment:
   Add a public Fory round-trip for annotated enums
   
   These tests prove the generated `EnumSpec` shape and the direct 
`EnumSerializer` behavior, but they still do not exercise the public 
`Fory.serialize` / `Fory.deserialize` path with an annotated enum. That leaves 
a gap around the real registration and resolver wiring for this new feature. 
Please add at least one end-to-end round-trip test for an enum that uses 
`@ForyEnumId`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to