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
The following commit(s) were added to refs/heads/main by this push:
new 7b0653ca9 π synced local 'docs/guide/' with remote 'docs/guide/'
7b0653ca9 is described below
commit 7b0653ca9ca5fc279df5961d7745fd4d2e380b73
Author: chaokunyang <[email protected]>
AuthorDate: Wed Jan 21 11:47:21 2026 +0000
π synced local 'docs/guide/' with remote 'docs/guide/'
---
docs/guide/cpp/cross-language.md | 2 +-
docs/guide/cpp/custom-serializers.md | 2 +-
docs/guide/cpp/field-configuration.md | 44 ++--
docs/guide/cpp/polymorphism.md | 480 ++++++++++++++++++++++++++++++++++
docs/guide/cpp/row-format.md | 2 +-
docs/guide/cpp/supported-types.md | 2 +-
6 files changed, 503 insertions(+), 29 deletions(-)
diff --git a/docs/guide/cpp/cross-language.md b/docs/guide/cpp/cross-language.md
index 3d0c8b1ea..ce192de8b 100644
--- a/docs/guide/cpp/cross-language.md
+++ b/docs/guide/cpp/cross-language.md
@@ -1,6 +1,6 @@
---
title: Cross-Language Serialization
-sidebar_position: 7
+sidebar_position: 10
id: cross_language
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
diff --git a/docs/guide/cpp/custom-serializers.md
b/docs/guide/cpp/custom-serializers.md
index 187105f50..c17ed0358 100644
--- a/docs/guide/cpp/custom-serializers.md
+++ b/docs/guide/cpp/custom-serializers.md
@@ -1,6 +1,6 @@
---
title: Custom Serializers
-sidebar_position: 4
+sidebar_position: 6
id: custom_serializers
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
diff --git a/docs/guide/cpp/field-configuration.md
b/docs/guide/cpp/field-configuration.md
index 991ed5b22..7469f7bf1 100644
--- a/docs/guide/cpp/field-configuration.md
+++ b/docs/guide/cpp/field-configuration.md
@@ -1,6 +1,6 @@
---
title: Field Configuration
-sidebar_position: 5
+sidebar_position: 7
id: field_configuration
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,16 +23,31 @@ This page explains how to configure field-level metadata
for serialization.
## Overview
-Apache Foryβ’ provides two ways to specify field-level metadata at compile time:
+Apache Foryβ’ provides three ways to configure field-level metadata at compile
time:
-1. **`fory::field<>` template** - Inline metadata in struct definition
-2. **`FORY_FIELD_TAGS` macro** - Non-invasive metadata added separately
+1. **`fory::field<>` template** - Inline metadata in struct definition with
wrapper types
+2. **`FORY_FIELD_TAGS` macro** - Non-invasive metadata for basic field
configuration
+3. **`FORY_FIELD_CONFIG` macro** - Advanced configuration with builder pattern
and encoding control
These enable:
- **Tag IDs**: Assign compact numeric IDs for schema evolution
- **Nullability**: Mark pointer fields as nullable
- **Reference Tracking**: Enable reference tracking for shared pointers
+- **Encoding Control**: Specify wire format for integers (varint, fixed,
tagged)
+- **Dynamic Dispatch**: Control polymorphic type info for smart pointers
+
+**Comparison:**
+
+| Feature | `fory::field<>` | `FORY_FIELD_TAGS` |
`FORY_FIELD_CONFIG` |
+| ----------------------- | --------------------- | ----------------- |
------------------------- |
+| **Struct modification** | Required (wrap types) | None | None
|
+| **Encoding control** | No | No | Yes
(varint/fixed/tagged) |
+| **Builder pattern** | No | No | Yes
|
+| **Dynamic control** | Yes | No | Yes
|
+| **Compile-time verify** | Yes | Limited | Yes
(member pointers) |
+| **Cross-lang compat** | Limited | Limited | Full
|
+| **Recommended for** | Simple structs | Third-party types |
Complex/xlang structs |
## The fory::field Template
@@ -303,16 +318,6 @@ FORY_FIELD_TAGS(Document,
| `std::shared_ptr<T>` | `(field, id)`, `(field, id, nullable)`, `(field, id,
ref)`, `(field, id, nullable, ref)` |
| `std::unique_ptr<T>` | `(field, id)`, `(field, id, nullable)`
|
-### API Comparison
-
-| Aspect | `fory::field<>` Wrapper | `FORY_FIELD_TAGS` Macro
|
-| ----------------------- | ------------------------ | -----------------------
|
-| **Struct definition** | Modified (wrapped types) | Unchanged (pure C++)
|
-| **IDE support** | Template noise | Excellent (clean types)
|
-| **Third-party classes** | Not supported | Supported
|
-| **Header dependencies** | Required everywhere | Isolated to config
|
-| **Migration effort** | High (change all fields) | Low (add one macro)
|
-
## FORY_FIELD_CONFIG Macro
The `FORY_FIELD_CONFIG` macro is the most powerful and flexible way to
configure field-level serialization. It provides:
@@ -516,17 +521,6 @@ FORY_FIELD_CONFIG(DataV2,
| `.tagged()` | Use tagged hybrid encoding |
`uint64_t` only |
| `.compress(v)` | Enable/disable field compression | All
types |
-### Comparing Field Configuration Macros
-
-| Feature | `fory::field<>` | `FORY_FIELD_TAGS` |
`FORY_FIELD_CONFIG` |
-| ----------------------- | --------------------- | ----------------- |
------------------------- |
-| **Struct modification** | Required (wrap types) | None | None
|
-| **Encoding control** | No | No | Yes
(varint/fixed/tagged) |
-| **Builder pattern** | No | No | Yes
|
-| **Compile-time verify** | Yes | Limited | Yes
(member pointers) |
-| **Cross-lang compat** | Limited | Limited | Full
|
-| **Recommended for** | Simple structs | Third-party types |
Complex/xlang structs |
-
## Default Values
- **Nullable**: Only `std::optional<T>` is nullable by default; all other
types (including `std::shared_ptr`) are non-nullable
diff --git a/docs/guide/cpp/polymorphism.md b/docs/guide/cpp/polymorphism.md
new file mode 100644
index 000000000..97f5bad11
--- /dev/null
+++ b/docs/guide/cpp/polymorphism.md
@@ -0,0 +1,480 @@
+---
+title: Polymorphic Serialization
+sidebar_position: 5
+id: polymorphism
+license: |
+ 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.
+---
+
+Apache Foryβ’ supports polymorphic serialization through smart pointers
(`std::shared_ptr` and `std::unique_ptr`), enabling dynamic dispatch and type
flexibility for inheritance hierarchies.
+
+## Supported Polymorphic Types
+
+- `std::shared_ptr<Base>` - Shared ownership with polymorphic dispatch
+- `std::unique_ptr<Base>` - Exclusive ownership with polymorphic dispatch
+- Collections: `std::vector<std::shared_ptr<Base>>`, `std::map<K,
std::unique_ptr<Base>>`
+- Optional: `std::optional<std::shared_ptr<Base>>`
+
+## Basic Polymorphic Serialization
+
+```cpp
+#include "fory/serialization/fory.h"
+
+using namespace fory::serialization;
+
+// Define base class with virtual methods
+struct Animal {
+ virtual ~Animal() = default;
+ virtual std::string speak() const = 0;
+ int32_t age = 0;
+};
+FORY_STRUCT(Animal, age);
+
+// Define derived classes
+struct Dog : Animal {
+ std::string speak() const override { return "Woof!"; }
+ std::string breed;
+};
+FORY_STRUCT(Dog, age, breed);
+
+struct Cat : Animal {
+ std::string speak() const override { return "Meow!"; }
+ std::string color;
+};
+FORY_STRUCT(Cat, age, color);
+
+// Struct with polymorphic field
+struct Zoo {
+ std::shared_ptr<Animal> star_animal;
+};
+FORY_STRUCT(Zoo, star_animal);
+
+int main() {
+ auto fory = Fory::builder().track_ref(true).build();
+
+ // Register all types with unique type IDs
+ fory.register_struct<Zoo>(100);
+ fory.register_struct<Dog>(101);
+ fory.register_struct<Cat>(102);
+
+ // Create object with polymorphic field
+ Zoo zoo;
+ zoo.star_animal = std::make_shared<Dog>();
+ zoo.star_animal->age = 3;
+ static_cast<Dog*>(zoo.star_animal.get())->breed = "Labrador";
+
+ // Serialize
+ auto bytes_result = fory.serialize(zoo);
+ assert(bytes_result.ok());
+
+ // Deserialize - runtime type is preserved
+ auto decoded_result = fory.deserialize<Zoo>(bytes_result.value());
+ assert(decoded_result.ok());
+
+ auto decoded = std::move(decoded_result).value();
+ assert(decoded.star_animal->speak() == "Woof!");
+ assert(decoded.star_animal->age == 3);
+
+ auto* dog_ptr = dynamic_cast<Dog*>(decoded.star_animal.get());
+ assert(dog_ptr != nullptr);
+ assert(dog_ptr->breed == "Labrador");
+}
+```
+
+## Type Registration for Polymorphism
+
+For polymorphic serialization, register derived types with unique type IDs:
+
+```cpp
+// Register with numeric type ID
+fory.register_struct<Derived1>(100);
+fory.register_struct<Derived2>(101);
+```
+
+**Why type ID registration?**
+
+- Compact binary representation
+- Fast type lookup and dispatch
+- Consistent with non-polymorphic type registration
+
+## Automatic Polymorphism Detection
+
+Fory automatically detects polymorphic types using `std::is_polymorphic<T>`:
+
+```cpp
+struct Base {
+ virtual ~Base() = default; // Virtual destructor makes it polymorphic
+ int32_t value = 0;
+};
+
+struct NonPolymorphic {
+ int32_t value = 0; // No virtual methods
+};
+
+// Polymorphic field - type info written automatically
+struct Container1 {
+ std::shared_ptr<Base> ptr; // Auto-detected as polymorphic
+};
+
+// Non-polymorphic field - no type info written
+struct Container2 {
+ std::shared_ptr<NonPolymorphic> ptr; // Not polymorphic
+};
+```
+
+## Controlling Dynamic Dispatch
+
+Use `fory::dynamic<V>` to override automatic polymorphism detection:
+
+```cpp
+struct Animal {
+ virtual ~Animal() = default;
+ virtual std::string speak() const = 0;
+};
+
+struct Pet {
+ // Auto-detected: type info written (Animal has virtual methods)
+ std::shared_ptr<Animal> animal1;
+
+ // Force dynamic: type info written explicitly
+ fory::field<std::shared_ptr<Animal>, 0, fory::dynamic<true>> animal2;
+
+ // Force non-dynamic: skip type info (faster but no runtime subtyping)
+ fory::field<std::shared_ptr<Animal>, 1, fory::dynamic<false>> animal3;
+};
+FORY_STRUCT(Pet, animal1, animal2, animal3);
+```
+
+**When to use `fory::dynamic<false>`:**
+
+- You know the runtime type will always match the declared type
+- Performance is critical and you don't need subtype support
+- Working with monomorphic data despite having a polymorphic base class
+
+### Field Configuration Without Wrapper Types
+
+Use `FORY_FIELD_CONFIG` to configure fields without `fory::field<>` wrapper:
+
+```cpp
+struct Zoo {
+ std::shared_ptr<Animal> star; // Auto-detected as polymorphic
+ std::shared_ptr<Animal> backup; // Nullable polymorphic field
+ std::shared_ptr<Animal> mascot; // Non-dynamic (no subtype dispatch)
+};
+FORY_STRUCT(Zoo, star, backup, mascot);
+
+// Configure fields with tag IDs and options
+FORY_FIELD_CONFIG(Zoo,
+ (star, fory::F(0)), // Tag ID 0, default options
+ (backup, fory::F(1).nullable()), // Tag ID 1, allow nullptr
+ (mascot, fory::F(2).dynamic(false)) // Tag ID 2, disable polymorphism
+);
+```
+
+See [Field Configuration](field-configuration.md) for complete details on
`fory::nullable`, `fory::ref`, and other field-level options
+
+## std::unique_ptr Polymorphism
+
+`std::unique_ptr` works the same way as `std::shared_ptr` for polymorphic
types:
+
+```cpp
+struct Container {
+ std::unique_ptr<Animal> pet;
+};
+FORY_STRUCT(Container, pet);
+
+auto fory = Fory::builder().track_ref(true).build();
+fory.register_struct<Container>(200);
+fory.register_struct<Dog>(201);
+
+Container container;
+container.pet = std::make_unique<Dog>();
+static_cast<Dog*>(container.pet.get())->breed = "Beagle";
+
+auto bytes = fory.serialize(container).value();
+auto decoded = fory.deserialize<Container>(bytes).value();
+
+// Runtime type preserved
+auto* dog = dynamic_cast<Dog*>(decoded.pet.get());
+assert(dog != nullptr);
+assert(dog->breed == "Beagle");
+```
+
+## Collections of Polymorphic Objects
+
+```cpp
+#include <vector>
+#include <map>
+
+struct AnimalShelter {
+ std::vector<std::shared_ptr<Animal>> animals;
+ std::map<std::string, std::unique_ptr<Animal>> registry;
+};
+FORY_STRUCT(AnimalShelter, animals, registry);
+
+auto fory = Fory::builder().track_ref(true).build();
+fory.register_struct<AnimalShelter>(100);
+fory.register_struct<Dog>(101);
+fory.register_struct<Cat>(102);
+
+AnimalShelter shelter;
+shelter.animals.push_back(std::make_shared<Dog>());
+shelter.animals.push_back(std::make_shared<Cat>());
+shelter.registry["pet1"] = std::make_unique<Dog>();
+
+auto bytes = fory.serialize(shelter).value();
+auto decoded = fory.deserialize<AnimalShelter>(bytes).value();
+
+// All runtime types preserved
+assert(dynamic_cast<Dog*>(decoded.animals[0].get()) != nullptr);
+assert(dynamic_cast<Cat*>(decoded.animals[1].get()) != nullptr);
+assert(dynamic_cast<Dog*>(decoded.registry["pet1"].get()) != nullptr);
+```
+
+## Reference Tracking
+
+Reference tracking for `std::shared_ptr` works the same with polymorphic types.
+See [Supported Types](supported-types.md) for details and examples.
+
+## Nested Polymorphism Depth Limit
+
+To prevent stack overflow from deeply nested polymorphic structures, Fory
limits the maximum dynamic nesting depth:
+
+```cpp
+struct Container {
+ virtual ~Container() = default;
+ int32_t value = 0;
+ std::shared_ptr<Container> nested;
+};
+FORY_STRUCT(Container, value, nested);
+
+// Default max_dyn_depth is 5
+auto fory1 = Fory::builder().build();
+assert(fory1.config().max_dyn_depth == 5);
+
+// Increase limit for deeper nesting
+auto fory2 = Fory::builder().max_dyn_depth(10).build();
+fory2.register_struct<Container>(1);
+
+// Create deeply nested structure
+auto level3 = std::make_shared<Container>();
+level3->value = 3;
+
+auto level2 = std::make_shared<Container>();
+level2->value = 2;
+level2->nested = level3;
+
+auto level1 = std::make_shared<Container>();
+level1->value = 1;
+level1->nested = level2;
+
+// Serialization succeeds
+auto bytes = fory2.serialize(level1).value();
+
+// Deserialization succeeds with sufficient depth
+auto decoded = fory2.deserialize<std::shared_ptr<Container>>(bytes).value();
+```
+
+**Depth exceeded error:**
+
+```cpp
+auto fory_shallow = Fory::builder().max_dyn_depth(2).build();
+fory_shallow.register_struct<Container>(1);
+
+// 3 levels exceeds max_dyn_depth=2
+auto result = fory_shallow.deserialize<std::shared_ptr<Container>>(bytes);
+assert(!result.ok()); // Fails with depth exceeded error
+```
+
+**When to adjust:**
+
+- **Increase `max_dyn_depth`**: For legitimate deeply nested polymorphic data
structures
+- **Decrease `max_dyn_depth`**: For stricter security requirements or shallow
data structures
+
+## Nullability for Polymorphic Fields
+
+By default, `std::shared_ptr<T>` and `std::unique_ptr<T>` fields are treated as
+non-nullable in the schema. To allow `nullptr`, wrap the field with
+`fory::field<>` (or `FORY_FIELD_TAGS`) and opt in with `fory::nullable`.
+
+```cpp
+struct Pet {
+ // Non-nullable (default)
+ std::shared_ptr<Animal> primary;
+
+ // Nullable via explicit field metadata
+ fory::field<std::shared_ptr<Animal>, 0, fory::nullable> optional;
+};
+FORY_STRUCT(Pet, primary, optional);
+```
+
+See [Field Configuration](field-configuration.md) for more details.
+
+## Combining Polymorphism with Other Features
+
+### Polymorphism + Reference Tracking
+
+```cpp
+struct GraphNode {
+ virtual ~GraphNode() = default;
+ int32_t id = 0;
+ std::vector<std::shared_ptr<GraphNode>> neighbors;
+};
+FORY_STRUCT(GraphNode, id, neighbors);
+
+struct WeightedNode : GraphNode {
+ double weight = 0.0;
+};
+FORY_STRUCT(WeightedNode, id, neighbors, weight);
+
+// Enable ref tracking to handle shared references and cycles
+auto fory = Fory::builder().track_ref(true).build();
+fory.register_struct<GraphNode>(100);
+fory.register_struct<WeightedNode>(101);
+
+// Create cyclic graph
+auto node1 = std::make_shared<WeightedNode>();
+node1->id = 1;
+
+auto node2 = std::make_shared<WeightedNode>();
+node2->id = 2;
+
+node1->neighbors.push_back(node2);
+node2->neighbors.push_back(node1); // Cycle
+
+auto bytes = fory.serialize(node1).value();
+auto decoded = fory.deserialize<std::shared_ptr<GraphNode>>(bytes).value();
+// Cycle handled correctly
+```
+
+### Polymorphism + Schema Evolution
+
+Use compatible mode for schema evolution with polymorphic types:
+
+```cpp
+auto fory = Fory::builder()
+ .compatible(true) // Enable schema evolution
+ .track_ref(true)
+ .build();
+```
+
+## Best Practices
+
+1. **Use type ID registration** for polymorphic types:
+
+ ```cpp
+ fory.register_struct<DerivedType>(100);
+ ```
+
+2. **Enable reference tracking** for polymorphic types:
+
+ ```cpp
+ auto fory = Fory::builder().track_ref(true).build();
+ ```
+
+3. **Virtual destructors required**: Ensure base classes have virtual
destructors:
+
+ ```cpp
+ struct Base {
+ virtual ~Base() = default; // Required for polymorphism
+ };
+ ```
+
+4. **Register all concrete types** before serialization/deserialization:
+
+ ```cpp
+ fory.register_struct<Derived1>(100);
+ fory.register_struct<Derived2>(101);
+ ```
+
+5. **Use `dynamic_cast`** to downcast after deserialization:
+
+ ```cpp
+ auto* derived = dynamic_cast<DerivedType*>(base_ptr.get());
+ if (derived) {
+ // Use derived-specific members
+ }
+ ```
+
+6. **Adjust `max_dyn_depth`** based on your data structure depth:
+
+ ```cpp
+ auto fory = Fory::builder().max_dyn_depth(10).build();
+ ```
+
+7. **Use `fory::nullable`** for optional polymorphic fields:
+
+ ```cpp
+ fory::field<std::shared_ptr<Base>, 0, fory::nullable> optional_ptr;
+ ```
+
+## Error Handling
+
+```cpp
+auto bytes_result = fory.serialize(obj);
+if (!bytes_result.ok()) {
+ std::cerr << "Serialization failed: "
+ << bytes_result.error().to_string() << std::endl;
+ return;
+}
+
+auto decoded_result = fory.deserialize<MyType>(bytes_result.value());
+if (!decoded_result.ok()) {
+ std::cerr << "Deserialization failed: "
+ << decoded_result.error().to_string() << std::endl;
+ return;
+}
+```
+
+**Common errors:**
+
+- **Type not registered**: Register all concrete types with unique IDs before
use
+- **Depth exceeded**: Increase `max_dyn_depth` for deeply nested structures
+- **Type ID conflict**: Ensure each type has a unique type ID across all
registered types
+
+## Performance Considerations
+
+**Polymorphic serialization overhead:**
+
+- Type metadata written for each polymorphic object (~16-32 bytes)
+- Dynamic type resolution during deserialization
+- Virtual function calls for runtime dispatch
+
+**Optimization tips:**
+
+1. **Use `fory::dynamic<false>`** when runtime type matches declared type:
+
+ ```cpp
+ fory::field<std::shared_ptr<Base>, 0, fory::dynamic<false>> fixed_type;
+ ```
+
+2. **Minimize nesting depth** to reduce metadata overhead
+
+3. **Batch polymorphic objects** in collections rather than individual fields
+
+4. **Consider non-polymorphic alternatives** when polymorphism isn't needed:
+
+ ```cpp
+ std::variant<Dog, Cat> animal; // Type-safe union instead of polymorphism
+ ```
+
+## Related Topics
+
+- [Type Registration](type-registration.md) - Registering types for
serialization
+- [Field Configuration](field-configuration.md) - Field-level metadata and
options
+- [Supported Types](supported-types.md) - Smart pointers and collections
+- [Configuration](configuration.md) - `max_dyn_depth` and other settings
+- [Basic Serialization](basic-serialization.md) - Core serialization concepts
diff --git a/docs/guide/cpp/row-format.md b/docs/guide/cpp/row-format.md
index 672770bcf..a3638ab7c 100644
--- a/docs/guide/cpp/row-format.md
+++ b/docs/guide/cpp/row-format.md
@@ -1,6 +1,6 @@
---
title: Row Format
-sidebar_position: 8
+sidebar_position: 20
id: row_format
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
diff --git a/docs/guide/cpp/supported-types.md
b/docs/guide/cpp/supported-types.md
index ed4d8e674..fb020e00a 100644
--- a/docs/guide/cpp/supported-types.md
+++ b/docs/guide/cpp/supported-types.md
@@ -1,6 +1,6 @@
---
title: Supported Types
-sidebar_position: 6
+sidebar_position: 8
id: supported_types
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]