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 eac02de3a26ed4736ec53de5514ba2ce7b64b5fc
Author: chaokunyang <[email protected]>
AuthorDate: Fri Jan 23 14:52:29 2026 +0000

    🔄 synced local 'docs/compiler/' with remote 'docs/compiler/'
---
 docs/compiler/fdl-syntax.md      | 37 +++++++++++++++++
 docs/compiler/flatbuffers-idl.md | 40 ++++++++++++++++++-
 docs/compiler/generated-code.md  | 86 ++++++++++++++++++++++++++++++++++++++++
 docs/compiler/protobuf-idl.md    | 26 +++++++-----
 4 files changed, 176 insertions(+), 13 deletions(-)

diff --git a/docs/compiler/fdl-syntax.md b/docs/compiler/fdl-syntax.md
index 0455bb786..a6604c08b 100644
--- a/docs/compiler/fdl-syntax.md
+++ b/docs/compiler/fdl-syntax.md
@@ -672,6 +672,43 @@ message OtherMessage {
 - Within a message, you can reference nested types by simple name
 - From outside, use the qualified name (Parent.Child)
 
+## Union Definition
+
+Unions define a value that can hold exactly one of several case types.
+
+### Basic Syntax
+
+```protobuf
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+```
+
+### Using a Union in a Message
+
+```protobuf
+message Person [id=100] {
+    Animal pet = 1;
+    optional Animal favorite_pet = 2;
+}
+```
+
+### Rules
+
+- Case IDs must be unique within the union
+- Cases cannot be `optional`, `repeated`, or `ref`
+- Union cases do not support field options
+- Case types can be primitives, enums, messages, or other named types
+- Union type IDs (`[id=...]`) are optional but recommended for cross-language 
use
+
+**Grammar:**
+
+```
+union_def  := 'union' IDENTIFIER [type_options] '{' union_field* '}'
+union_field := field_type IDENTIFIER '=' INTEGER ';'
+```
+
 ## Field Definition
 
 Fields define the properties of a message.
diff --git a/docs/compiler/flatbuffers-idl.md b/docs/compiler/flatbuffers-idl.md
index 9f8e932be..e12ac1361 100644
--- a/docs/compiler/flatbuffers-idl.md
+++ b/docs/compiler/flatbuffers-idl.md
@@ -26,7 +26,7 @@ already have FlatBuffers schemas but want Fory-native 
serialization and codegen.
 ## Key Differences vs FDL
 
 - **Field numbering**: FlatBuffers fields have no explicit IDs; Fory assigns
-  sequential field numbers based on declaration order.
+  sequential field numbers based on declaration order, starting at 1.
 - **Tables vs structs**: FlatBuffers `table` maps to a Fory message with
   `evolving=true`; `struct` maps to `evolving=false`.
 - **Default values**: Parsed for compatibility but ignored in generated Fory
@@ -35,7 +35,8 @@ already have FlatBuffers schemas but want Fory-native 
serialization and codegen.
   fields; FDL uses `[option=value]` inline syntax.
 - **Root type**: `root_type` is ignored because Fory does not require a root
   message to serialize.
-- **Unions**: FlatBuffers `union` is not supported yet and raises an error.
+- **Unions**: FlatBuffers `union` is translated into an FDL `union`. Case IDs
+  follow declaration order, starting at 1.
 
 ## Scalar Type Mapping
 
@@ -56,6 +57,41 @@ already have FlatBuffers schemas but want Fory-native 
serialization and codegen.
 
 Vectors (`[T]`) map to Fory list types.
 
+## Union Mapping
+
+FlatBuffers unions are converted to FDL unions and then to native union APIs in
+each target language.
+
+**FlatBuffers:**
+
+```fbs
+union Payload {
+  Note,
+  Metric
+}
+
+table Container {
+  payload: Payload;
+}
+```
+
+**FDL (conceptual):**
+
+```protobuf
+union Payload {
+    Note note = 1;
+    Metric metric = 2;
+}
+
+message Container {
+    Payload payload = 1;
+}
+```
+
+Case IDs are derived from the declaration order in the `union`. The generated
+case names are based on the type names (converted to each language's naming
+convention).
+
 ## Usage
 
 Compile a FlatBuffers schema directly:
diff --git a/docs/compiler/generated-code.md b/docs/compiler/generated-code.md
index 71d08269f..88b8674b3 100644
--- a/docs/compiler/generated-code.md
+++ b/docs/compiler/generated-code.md
@@ -182,6 +182,92 @@ FORY_STRUCT(SearchResponse, results);
 | Rust     | Nested module             | `search_response::Result` |
 | C++      | Nested classes            | `SearchResponse::Result`  |
 
+## Union Generation
+
+FDL unions generate type-safe APIs with an explicit active case. This example 
is
+based on `integration_tests/idl_tests/idl/addressbook.fdl`:
+
+```protobuf
+package addressbook;
+
+message Dog [id=104] {
+    string name = 1;
+    int32 bark_volume = 2;
+}
+
+message Cat [id=105] {
+    string name = 1;
+    int32 lives = 2;
+}
+
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+
+message Person [id=100] {
+    Animal pet = 8;
+}
+```
+
+### Java
+
+```java
+Animal pet = Animal.ofDog(new Dog());
+if (pet.hasDog()) {
+    Dog dog = pet.getDog();
+}
+Animal.AnimalCase caseId = pet.getAnimalCase();
+```
+
+### Python
+
+```python
+pet = Animal.dog(Dog(name="Rex", bark_volume=5))
+if pet.is_dog():
+    dog = pet.dog_value()
+case_id = pet.case_id()
+```
+
+### Go
+
+```go
+pet := DogAnimal(&Dog{Name: "Rex", BarkVolume: 5})
+if dog, ok := pet.AsDog(); ok {
+    _ = dog
+}
+_ = pet.Visit(AnimalVisitor{
+    Dog: func(d *Dog) error { return nil },
+})
+```
+
+### Rust
+
+```rust
+let pet = Animal::Dog(Dog {
+    name: "Rex".into(),
+    bark_volume: 5,
+});
+```
+
+### C++
+
+```cpp
+addressbook::Animal pet = addressbook::Animal::dog(
+    addressbook::Dog{"Rex", 5});
+if (pet.is_dog()) {
+  const addressbook::Dog& dog = pet.dog();
+}
+```
+
+Generated registration helpers also register union types, for example:
+
+- Java: `fory.registerUnion(Animal.class, 106, new UnionSerializer(...))`
+- Python: `fory.register_union(Animal, type_id=106, 
serializer=AnimalSerializer(fory))`
+- Go: `f.RegisterUnion(...)`
+- Rust: `fory.register_union::<Animal>(106)?`
+- C++: `FORY_UNION(addressbook::Animal, ...)`
+
 ## Java
 
 ### Enum Generation
diff --git a/docs/compiler/protobuf-idl.md b/docs/compiler/protobuf-idl.md
index 0971b4a92..2732b34bf 100644
--- a/docs/compiler/protobuf-idl.md
+++ b/docs/compiler/protobuf-idl.md
@@ -207,7 +207,7 @@ message TreeNode {
 | List       | `repeated T`                                                    
                                       | `repeated T`                      |
 | Map        | `map<K, V>`                                                     
                                       | `map<K, V>`                       |
 | Nullable   | `optional T` (proto3)                                           
                                       | `optional T`                      |
-| Oneof      | `oneof`                                                         
                                       | Not supported                     |
+| Oneof      | `oneof`                                                         
                                       | `union` (case id = field number)  |
 | Any        | `google.protobuf.Any`                                           
                                       | Not supported                     |
 | Extensions | `extend`                                                        
                                       | Not supported                     |
 
@@ -276,7 +276,7 @@ user.setAge(30);
 1. **Building gRPC services**: Protobuf is the native format for gRPC
 2. **Maximum backward compatibility**: Protobuf's unknown field handling is 
robust
 3. **Schema evolution is critical**: Adding/removing fields across versions
-4. **You need oneof/Any types**: Complex polymorphism requirements
+4. **You need Any types**: Protobuf-specific dynamic payloads
 5. **Human-readable debugging**: TextFormat and JSON transcoding available
 6. **Ecosystem integration**: Wide tooling support (linting, documentation)
 
@@ -346,21 +346,25 @@ message Person [id=101] {
 
 ```protobuf
 // Proto
-message Result {
-  oneof result {
-    Success success = 1;
-    Error error = 2;
+message Event {
+  oneof payload {
+    string text = 1;
+    int32 number = 2;
   }
 }
 ```
 
 ```protobuf
-// FDL - Use separate optional fields
-message Result [id=102] {
-    optional Success success = 1;
-    optional Error error = 2;
+// FDL - oneof becomes a nested union plus an optional field referencing it
+message Event [id=102] {
+    union payload {
+        string text = 1;
+        int32 number = 2;
+    }
+    optional payload payload = 1;
 }
-// Or model as sealed class hierarchy in generated code
+// Case ids are preserved from the oneof field numbers
+// The field number is the smallest case id in the oneof
 ```
 
 **Well-known types:**


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

Reply via email to