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 e1d8d364b2d68023d3b1e32550a15a517e9e37de
Author: chaokunyang <[email protected]>
AuthorDate: Thu May 28 05:22:50 2026 +0000

    πŸ”„ synced local 'docs/guide/' with remote 'docs/guide/'
---
 docs/guide/csharp/schema-metadata.md              | 13 ++++++----
 docs/guide/kotlin/static-generated-serializers.md | 27 +++++++++++++++-----
 docs/guide/rust/schema-evolution.md               | 24 ++++++++++++------
 docs/guide/scala/schema-idl.md                    | 31 +++++++++++++++--------
 docs/guide/scala/schema-metadata.md               | 24 ++++++++++++------
 docs/guide/swift/schema-metadata.md               | 15 ++++++++---
 6 files changed, 93 insertions(+), 41 deletions(-)

diff --git a/docs/guide/csharp/schema-metadata.md 
b/docs/guide/csharp/schema-metadata.md
index 52ae4cea85..65baa8d460 100644
--- a/docs/guide/csharp/schema-metadata.md
+++ b/docs/guide/csharp/schema-metadata.md
@@ -86,7 +86,10 @@ Nullability comes from the C# carrier type. Use 
`List<ulong?>` for nullable list
 Generated union cases use `[ForyCase]` for both the stable case ID and optional
 case payload schema type. Do not put `[ForyField]` on union case payload
 members. Known case record names use PascalCase FDL case names; payload types
-use qualified references when needed to avoid name conflicts.
+use qualified references when needed to avoid name conflicts. A typed union 
must
+declare at least one non-`Unknown` case; `Unknown(UnknownCase)` is only the
+runtime forward-compatibility carrier. The marker only selects the carrier and
+does not add an entry to the schema case table.
 
 ```csharp
 using Apache.Fory;
@@ -97,13 +100,13 @@ public abstract partial record Shape
 {
     private Shape() {}
 
-    [ForyCase(0)]
-    public sealed partial record UnknownCase(int CaseId, object? Value) : 
Shape;
+    [ForyUnknownCase]
+    public sealed partial record Unknown(UnknownCase Value) : Shape;
 
-    [ForyCase(1)]
+    [ForyCase(0)]
     public sealed partial record Circle(global::example.Circle Value) : Shape;
 
-    [ForyCase(2, Type = typeof(S.Fixed<S.Int32>))]
+    [ForyCase(1, Type = typeof(S.Fixed<S.Int32>))]
     public sealed partial record Code(int Value) : Shape;
 }
 ```
diff --git a/docs/guide/kotlin/static-generated-serializers.md 
b/docs/guide/kotlin/static-generated-serializers.md
index f24e598e17..97f8150e1e 100644
--- a/docs/guide/kotlin/static-generated-serializers.md
+++ b/docs/guide/kotlin/static-generated-serializers.md
@@ -220,20 +220,35 @@ serialization.
 
 KSP generates serializers for top-level sealed classes annotated with
 `@ForyUnion`. Each schema case is a nested class annotated with `@ForyCase` and
-one constructor property named `value`. Case ID `0` is reserved for the unknown
-case carrier:
+one constructor property named `value`. `Unknown(UnknownCase)` is marked with
+`@ForyUnknownCase` as the runtime-owned forward-compatibility carrier. It is
+omitted from the schema case table because the marker only selects the carrier
+and does not add a schema entry. A typed union must declare at least one
+non-`Unknown` case:
 
 ```kotlin
+package example
+
+import org.apache.fory.annotation.ForyCase
+import org.apache.fory.annotation.ForyUnion
+import org.apache.fory.annotation.ForyUnknownCase
+import org.apache.fory.type.union.UnknownCase
+
 @ForyUnion
 sealed class Animal {
-  @ForyCase(id = 0)
-  data class UnknownCase(val caseId: Int, val value: Any?) : Animal()
+  @ForyUnknownCase
+  data class Unknown(val value: UnknownCase) : Animal()
 
-  @ForyCase(id = 1)
-  data class DogCase(val value: Dog) : Animal()
+  @ForyCase(id = 0)
+  data class Dog(val value: example.Dog) : Animal()
 }
 ```
 
+When a generated Kotlin union case name matches the payload type simple name,
+packaged output keeps the case name and qualifies the payload type. If a target
+output mode cannot express a legal qualifier for a conflict, the IDL compiler
+appends `Case` to the generated case class name.
+
 Generated schema modules register sealed unions through 
`KotlinSerializers.registerUnion`.
 The runtime discovers the generated `<Target>_ForySerializer` automatically, so
 callers do not pass a serializer instance.
diff --git a/docs/guide/rust/schema-evolution.md 
b/docs/guide/rust/schema-evolution.md
index 154a6e2b32..5886870759 100644
--- a/docs/guide/rust/schema-evolution.md
+++ b/docs/guide/rust/schema-evolution.md
@@ -108,11 +108,11 @@ Apache Foryβ„’ supports three types of enum variants with 
full schema evolution
 - **Named**: Struct-like variants (`Event::Click { x: i32, y: i32 }`)
 
 ```rust
-use fory::{Fory, ForyStruct};
+use fory::{Fory, ForyUnion};
 
-#[derive(Default, ForyStruct, Debug, PartialEq)]
+#[derive(ForyUnion, Debug, PartialEq)]
 enum Value {
-    #[default]
+    #[fory(default)]
     Null,
     Bool(bool),
     Number(f64),
@@ -129,6 +129,13 @@ let decoded: Value = fory.deserialize(&bytes)?;
 assert_eq!(value, decoded);
 ```
 
+For typed ADT unions whose schema cases are unit or single-payload variants,
+`#[fory(unknown)] Unknown(::fory::UnknownCase)` is only the runtime
+forward-compatibility carrier. It cannot be the default variant, and the union
+must include at least one real schema case. The marker only selects the carrier
+and does not add an entry to the schema case table; schema cases use
+non-negative IDs.
+
 ### Enum Schema Evolution
 
 Compatible mode enables robust schema evolution with variant type encoding (2 
bits):
@@ -136,19 +143,20 @@ Compatible mode enables robust schema evolution with 
variant type encoding (2 bi
 - `0b0` = Unit, `0b1` = Unnamed, `0b10` = Named
 
 ```rust
-use fory::{Fory, ForyStruct};
+use fory::{Fory, ForyUnion};
 
 // Old version
-#[derive(ForyStruct)]
+#[derive(ForyUnion)]
 enum OldEvent {
+    #[fory(default)]
     Click { x: i32, y: i32 },
     Scroll { delta: f64 },
 }
 
 // New version - added field and variant
-#[derive(Default, ForyStruct)]
+#[derive(ForyUnion)]
 enum NewEvent {
-    #[default]
+    #[fory(default)]
     Unknown,
     Click { x: i32, y: i32, timestamp: u64 },  // Added field
     Scroll { delta: f64 },
@@ -174,7 +182,7 @@ assert!(matches!(new_event, NewEvent::Click { x: 100, y: 
200, timestamp: 0 }));
 
 **Best practices:**
 
-- Always mark a default variant with `#[default]`
+- Always mark exactly one union variant with `#[fory(default)]`
 - Named variants provide better evolution than unnamed
 - Use compatible mode for cross-version communication
 
diff --git a/docs/guide/scala/schema-idl.md b/docs/guide/scala/schema-idl.md
index f0087eae99..27ab62235d 100644
--- a/docs/guide/scala/schema-idl.md
+++ b/docs/guide/scala/schema-idl.md
@@ -128,28 +128,37 @@ Fory enum IDs from case-level `@ForyEnumId` metadata are 
used in xlang mode.
 IDL unions generate Scala 3 ADT enums with macro-derived serializers:
 
 ```scala
-import org.apache.fory.annotation.{ForyCase, ForyUnion, UInt32Type}
+package example
+
+import org.apache.fory.annotation.{ForyCase, ForyUnion, ForyUnknownCase, 
UInt32Type}
 import org.apache.fory.config.Int32Encoding
 import org.apache.fory.scala.ForySerializer
+import org.apache.fory.`type`.union.UnknownCase
 
 @ForyUnion
 enum SearchTarget derives ForySerializer {
+  @ForyUnknownCase
+  case Unknown(value: UnknownCase)
+
   @ForyCase(id = 0)
-  case UnknownCase(caseId: Int, value: Any)
+  case User(value: _root_.example.User)
 
   @ForyCase(id = 1)
-  case UserCase(value: User)
-
-  @ForyCase(id = 2)
-  case FixedIdCase(value: Long @UInt32Type(encoding = Int32Encoding.FIXED))
+  case FixedId(value: Long @UInt32Type(encoding = Int32Encoding.FIXED))
 }
 ```
 
-Schema-defined union cases must use positive IDs. Case ID `0` is reserved for
-the Scala unknown-case carrier, whose payload stores the original positive case
-ID and the deserialized value. When a reader sees a newer positive case ID, it
-returns `UnknownCase(originalId, value)` instead of failing solely because the
-case ID is not known locally.
+When a generated Scala union case name matches the payload type simple name,
+packaged output keeps the case name and qualifies the payload type. If a target
+output mode cannot express a legal qualifier for a conflict, the IDL compiler
+appends `Case` to the generated case name.
+
+Schema-defined union cases use non-negative IDs, and a typed union must declare
+at least one non-`Unknown` case. The Scala unknown-case carrier is selected by
+`@ForyUnknownCase`, not by a schema case ID. Its payload stores the original 
case
+ID and the deserialized value. When a reader sees a newer case ID, it returns
+`Unknown(UnknownCase)` instead of failing solely because the case ID is not 
known
+locally.
 
 The macro writes the existing xlang union envelope directly. It does not
 allocate temporary Java `Union` carriers.
diff --git a/docs/guide/scala/schema-metadata.md 
b/docs/guide/scala/schema-metadata.md
index 1f96964c01..18cc897afc 100644
--- a/docs/guide/scala/schema-metadata.md
+++ b/docs/guide/scala/schema-metadata.md
@@ -83,25 +83,33 @@ xlang mode.
 IDL unions generate Scala 3 ADT enums with `@ForyUnion` and `@ForyCase` 
metadata:
 
 ```scala
-import org.apache.fory.annotation.{ForyCase, ForyUnion, UInt32Type}
+package example
+
+import org.apache.fory.annotation.{ForyCase, ForyUnion, ForyUnknownCase, 
UInt32Type}
 import org.apache.fory.config.Int32Encoding
 import org.apache.fory.scala.ForySerializer
+import org.apache.fory.`type`.union.UnknownCase
 
 @ForyUnion
 enum SearchTarget derives ForySerializer {
+  @ForyUnknownCase
+  case Unknown(value: UnknownCase)
+
   @ForyCase(id = 0)
-  case UnknownCase(caseId: Int, value: Any)
+  case User(value: _root_.example.User)
 
   @ForyCase(id = 1)
-  case UserCase(value: User)
-
-  @ForyCase(id = 2)
-  case FixedIdCase(value: Long @UInt32Type(encoding = Int32Encoding.FIXED))
+  case FixedId(value: Long @UInt32Type(encoding = Int32Encoding.FIXED))
 }
 ```
 
-Schema-defined union cases must use positive IDs. Case ID `0` is reserved for 
the unknown-case
-carrier used when a reader sees a newer positive case ID.
+Schema-defined union cases use non-negative IDs, and a typed union must declare
+at least one non-`Unknown` case. The unknown-case carrier is selected by
+`@ForyUnknownCase`, not by a schema case ID.
+When a generated Scala union case name matches the payload type simple name,
+packaged output keeps the case name and qualifies the payload type. If a target
+output mode cannot express a legal qualifier for a conflict, the IDL compiler
+appends `Case` to the generated case name.
 
 ## Generated Metadata Source
 
diff --git a/docs/guide/swift/schema-metadata.md 
b/docs/guide/swift/schema-metadata.md
index 79c4fa35d1..bd57c14f54 100644
--- a/docs/guide/swift/schema-metadata.md
+++ b/docs/guide/swift/schema-metadata.md
@@ -107,15 +107,24 @@ Union payloads use the same DSL through 
`@ForyCase(payload:)`:
 
 ```swift
 @ForyUnion
-enum Event: Equatable {
-    @ForyCase(id: 1)
+enum Event {
+    @ForyUnknownCase
+    case unknown(UnknownCase)
+
+    @ForyCase(id: 0)
     case created(String)
 
-    @ForyCase(id: 2, payload: .uint64(encoding: .fixed))
+    @ForyCase(id: 1, payload: .uint64(encoding: .fixed))
     case deleted(UInt64)
 }
 ```
 
+Every `@ForyUnion` must declare `@ForyUnknownCase case unknown(UnknownCase)` 
and
+at least one non-`unknown` case. The unknown case is only the runtime
+forward-compatibility carrier and cannot be the default value source. It is
+omitted from the schema case table because the marker only selects the carrier
+and does not add a schema entry. Schema cases use non-negative IDs.
+
 ## Model Macro Requirements
 
 ### Struct and class fields


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

Reply via email to