Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/fory_compiler/generators/csharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@ def generate_registration_class(self) -> List[str]:
lines.append(f"{self.indent_str}private static ThreadSafeFory CreateFory()")
lines.append(f"{self.indent_str}{{")
lines.append(
f"{self.indent_str * 2}ThreadSafeFory fory = Fory.Builder().Xlang(true).TrackRef(true).BuildThreadSafe();"
f"{self.indent_str * 2}ThreadSafeFory fory = Fory.Builder().TrackRef(true).BuildThreadSafe();"
)
lines.append(f"{self.indent_str * 2}Register(fory);")
lines.append(f"{self.indent_str * 2}return fory;")
Expand Down
1 change: 0 additions & 1 deletion csharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ Use consistent registration mappings across languages.

```csharp
Fory fory = Fory.Builder()
.Xlang(true)
.Compatible(true)
.Build();

Expand Down
67 changes: 39 additions & 28 deletions csharp/src/Fory/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,53 @@ namespace Apache.Fory;

/// <summary>
/// Immutable runtime configuration used by <see cref="Fory"/> and <see cref="ThreadSafeFory"/>.
/// Instances are created by <see cref="ForyBuilder"/>.
/// </summary>
/// <param name="Xlang">Whether cross-language protocol mode is enabled.</param>
/// <param name="TrackRef">Whether shared and circular reference tracking is enabled.</param>
/// <param name="Compatible">Whether schema-compatible mode is enabled.</param>
/// <param name="CheckStructVersion">Whether generated struct schema hash checks are enforced.</param>
/// <param name="MaxDepth">Maximum allowed nesting depth for dynamic object payload reads.</param>
public sealed record Config(
bool Xlang = true,
bool TrackRef = false,
bool Compatible = false,
bool CheckStructVersion = false,
int MaxDepth = 20);
public sealed class Config
{
internal Config(
bool trackRef,
bool compatible,
bool checkStructVersion,
int maxDepth)
{
TrackRef = trackRef;
Compatible = compatible;
CheckStructVersion = checkStructVersion;
MaxDepth = maxDepth;
}

/// <summary>
/// Gets whether shared and circular reference tracking is enabled.
/// </summary>
public bool TrackRef { get; }

/// <summary>
/// Gets whether schema-compatible mode is enabled.
/// </summary>
public bool Compatible { get; }

/// <summary>
/// Gets whether generated struct schema hash checks are enforced.
/// </summary>
public bool CheckStructVersion { get; }

/// <summary>
/// Gets the maximum allowed nesting depth for dynamic object payload reads.
/// </summary>
public int MaxDepth { get; }
}

/// <summary>
/// Fluent builder for creating <see cref="Fory"/> and <see cref="ThreadSafeFory"/> runtimes.
/// </summary>
public sealed class ForyBuilder
{
private bool _xlang = true;
private bool _trackRef;
private bool _compatible;
private bool _checkStructVersion;
private int _maxDepth = 20;

/// <summary>
/// Enables or disables cross-language protocol mode.
/// </summary>
/// <param name="enabled">Whether to enable cross-language mode. Defaults to <c>true</c>.</param>
/// <returns>The same builder instance.</returns>
public ForyBuilder Xlang(bool enabled = true)
{
_xlang = enabled;
return this;
}

/// <summary>
/// Enables or disables reference tracking for shared and circular object graphs.
/// </summary>
Expand Down Expand Up @@ -107,11 +119,10 @@ public ForyBuilder MaxDepth(int value)
private Config BuildConfig()
{
return new Config(
Xlang: _xlang,
TrackRef: _trackRef,
Compatible: _compatible,
CheckStructVersion: _checkStructVersion,
MaxDepth: _maxDepth);
trackRef: _trackRef,
compatible: _compatible,
checkStructVersion: _checkStructVersion,
maxDepth: _maxDepth);
}

/// <summary>
Expand Down
8 changes: 2 additions & 6 deletions csharp/src/Fory/Fory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,7 @@ public T Deserialize<T>(ref ReadOnlySequence<byte> payload)
/// <param name="isNone">Whether the payload value is null.</param>
internal void WriteHead(ByteWriter writer, bool isNone)
{
byte bitmap = 0;
if (Config.Xlang)
{
bitmap |= ForyHeaderFlag.IsXlang;
}
byte bitmap = ForyHeaderFlag.IsXlang;

if (isNone)
{
Expand All @@ -255,7 +251,7 @@ internal bool ReadHead(ByteReader reader)
{
byte bitmap = reader.ReadUInt8();
bool peerIsXlang = (bitmap & ForyHeaderFlag.IsXlang) != 0;
if (peerIsXlang != Config.Xlang)
if (!peerIsXlang)
{
throw new InvalidDataException("xlang bitmap mismatch");
}
Expand Down
14 changes: 3 additions & 11 deletions docs/guide/csharp/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ license: |
---

This page covers `ForyBuilder` options and default configuration values for Apache Fory™ C#.
`Config` is an immutable runtime snapshot created by `ForyBuilder`.

## Build a Runtime

Expand All @@ -36,23 +37,15 @@ ThreadSafeFory threadSafe = Fory.Builder().BuildThreadSafe();

| Option | Default | Description |
| -------------------- | ------- | ---------------------------------------------- |
| `Xlang` | `true` | Cross-language protocol mode |
| `TrackRef` | `false` | Reference tracking disabled |
| `Compatible` | `false` | Schema-consistent mode (no evolution metadata) |
| `CheckStructVersion` | `false` | Struct schema hash checks disabled |
| `MaxDepth` | `20` | Max dynamic nesting depth |

## Builder Options

### `Xlang(bool enabled = true)`

Controls cross-language mode.

```csharp
Fory fory = Fory.Builder()
.Xlang(true)
.Build();
```
C# always uses xlang-compatible framing, so `ForyBuilder` does not expose a separate `Xlang(...)`
toggle.

### `TrackRef(bool enabled = false)`

Expand Down Expand Up @@ -111,7 +104,6 @@ Fory fory = Fory.Builder()

```csharp
Fory fory = Fory.Builder()
.Xlang(true)
.Compatible(true)
.TrackRef(true)
.Build();
Expand Down
8 changes: 4 additions & 4 deletions docs/guide/csharp/cross-language.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ license: |

Apache Fory™ C# supports cross-language serialization with other Fory runtimes.

## Enable Cross-Language Mode
## Cross-Language Runtime

C# defaults to `Xlang(true)`, but it is good practice to configure it explicitly in interoperability code.
C# always writes and reads the xlang frame header. There is no separate `Xlang(...)` builder
option, so interoperability code only needs to configure the remaining runtime behavior such as
compatibility mode and reference tracking.

```csharp
Fory fory = Fory.Builder()
.Xlang(true)
.Compatible(true)
.Build();
```
Expand All @@ -43,7 +44,6 @@ public sealed class Person
}

Fory fory = Fory.Builder()
.Xlang(true)
.Compatible(true)
.Build();

Expand Down
10 changes: 6 additions & 4 deletions docs/guide/csharp/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ Ensure the same type-ID/name mapping exists on both write and read sides.

## `InvalidDataException: xlang bitmap mismatch`

**Cause**: Writer/reader disagree on `Xlang` mode.
**Cause**: The payload is not an xlang Fory frame, or it came from a peer/runtime mode that does
not emit the xlang header C# requires.

**Fix**: Use the same `Xlang(...)` value on both peers.
**Fix**: Ensure the payload was produced by an xlang-compatible Fory runtime. C# always expects the
xlang header and does not expose a separate `Xlang(...)` builder option.

```csharp
Fory writer = Fory.Builder().Xlang(true).Build();
Fory reader = Fory.Builder().Xlang(true).Build();
Fory writer = Fory.Builder().Compatible(true).Build();
Fory reader = Fory.Builder().Compatible(true).Build();
```

## Schema Version Mismatch in Strict Mode
Expand Down
22 changes: 11 additions & 11 deletions docs/guide/go/codegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ license: |
---

:::warning Experimental Feature
Code generation is an **experimental** feature in Fory Go. The API and behavior may change in future releases. The reflection-based path remains the stable, recommended approach for most use cases.
Code generation is an **experimental** feature in Fory Go. The API and behavior may change in future releases. The standard runtime path remains the stable, recommended approach for most use cases.
:::

Fory Go provides optional ahead-of-time (AOT) code generation for performance-critical paths. This eliminates reflection overhead and provides compile-time type safety.
Fory Go provides optional ahead-of-time (AOT) code generation for performance-critical paths. This generates dedicated serializers ahead of time and adds compile-time shape checks.

## Why Code Generation?

| Aspect | Reflection-Based | Code Generation |
| Aspect | Standard Path | Code Generation |
| ----------- | ------------------ | ---------------------- |
| Setup | Zero configuration | Requires `go generate` |
| Performance | Good | Better (no reflection) |
| Type Safety | Runtime | Compile-time |
| Performance | Excellent | Better on hot paths |
| Type Safety | Runtime validation | Compile-time checks |
| Maintenance | Automatic | Requires regeneration |

**Use code generation when**:
Expand All @@ -40,7 +40,7 @@ Fory Go provides optional ahead-of-time (AOT) code generation for performance-cr
- Compile-time type safety is important
- Hot paths are performance-critical

**Use reflection when**:
**Use the standard path when**:

- Simple setup is preferred
- Types change frequently
Expand Down Expand Up @@ -307,7 +307,7 @@ type HotPathStruct struct {
}

type ColdPathStruct struct {
// Not annotated, uses reflection
// Not annotated, uses the standard runtime serializer
}
```

Expand All @@ -326,12 +326,12 @@ type ColdPathStruct struct {
- Private (unexported) fields
- Custom serializers

### Reflection Fallback
### Standard Path Fallback

If codegen fails, Fory falls back to reflection:
If generated serializers are unavailable, Fory falls back to the standard serializer path:

```go
// If User_ForyGenSerializer not found, uses reflection
// If User_ForyGenSerializer is not linked in, Fory uses the standard path
f.Serialize(&User{})
```

Expand Down Expand Up @@ -405,7 +405,7 @@ type User struct {

### Is codegen required?

No. Reflection-based serialization works without code generation.
No. The standard serializer path works without code generation.

### Does generated code work across Go versions?

Expand Down
17 changes: 5 additions & 12 deletions docs/guide/go/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Apache Fory Go is a high-performance, cross-language serialization library for G
- **Cross-Language**: Seamless data exchange with Java, Python, C++, Rust, and JavaScript
- **Automatic Serialization**: No IDL definitions or schema compilation required
- **Reference Tracking**: Built-in support for circular references and shared objects
- **Type Safety**: Strong typing with compile-time verification (optional codegen)
- **Type Safety**: Strong typing with schema-aware serializers
- **Schema Evolution**: Compatible mode for forward/backward compatibility
- **Thread-Safe Option**: Pool-based thread-safe wrapper for concurrent use

Expand Down Expand Up @@ -84,23 +84,17 @@ func main() {
}
```

## Architecture
## Default Serialization Path

Fory Go provides two serialization paths:

### Reflection-Based (Default)

The default path uses Go's reflection to inspect types at runtime. This works out-of-the-box with any struct. Although this mode uses reflection, it is highly optimized with type caching, inlined hot paths, delivering excellent performance for most use cases:
Fory Go works out-of-the-box with ordinary Go structs. The standard runtime path caches type
metadata and keeps hot serialization paths optimized, so most applications can use it directly
without any extra build step:

```go
f := fory.New()
data, _ := f.Serialize(myStruct)
```

### Code Generation (Experimental)

For performance-critical paths, Fory provides optional ahead-of-time code generation that eliminates reflection overhead. See the [Code Generation](codegen.md) guide for details.

## Configuration

Fory Go uses a functional options pattern for configuration:
Expand Down Expand Up @@ -153,7 +147,6 @@ See [Cross-Language Serialization](cross-language.md) for type mapping and compa
| [Struct Tags](struct-tags.md) | Field-level configuration |
| [Schema Evolution](schema-evolution.md) | Forward/backward compatibility |
| [Cross-Language](cross-language.md) | Multi-language serialization |
| [Code Generation](codegen.md) | Experimental AOT code generation |
| [Thread Safety](thread-safety.md) | Concurrent usage patterns |
| [Troubleshooting](troubleshooting.md) | Common issues and solutions |

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/java/advanced-features.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Advanced Features
sidebar_position: 7
sidebar_position: 10
id: advanced_features
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/java/compression.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Compression
sidebar_position: 6
sidebar_position: 7
id: compression
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
Expand Down
4 changes: 3 additions & 1 deletion docs/guide/java/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ This page documents all configuration options available through `ForyBuilder`.
| `asyncCompilationEnabled` | If enabled, serialization uses interpreter mode first and switches to JIT serialization after async serializer JIT for a class is finished. | `false` |
| `scalaOptimizationEnabled` | Enables or disables Scala-specific serialization optimization. | `false` |
| `copyRef` | When disabled, the copy performance will be better. But fory deep copy will ignore circular and shared reference. Same reference of an object graph will be copied into different objects in one `Fory#copy`. | `false` |
| `serializeEnumByName` | When Enabled, fory serialize enum by name instead of ordinal. | `false` |
| `serializeEnumByName` | When enabled, Fory serializes enum names instead of numeric enum tags. Without this option, Fory writes declaration ordinals by default, or explicit stable ids when the enum is configured with `@ForyEnumId`. | `false` |

## Example Configuration

Expand All @@ -72,6 +72,8 @@ Fory fory = Fory.builder()

## Related Topics

- [Field Configuration](field-configuration.md) - `@ForyField`, `@Ignore`, and integer encoding annotations
- [Enum Configuration](enum-configuration.md) - `serializeEnumByName` and `@ForyEnumId`
- [Schema Evolution](schema-evolution.md) - Compatible mode and meta sharing
- [Compression](compression.md) - Int, long, and array compression details
- [Type Registration](type-registration.md) - Class registration options
2 changes: 1 addition & 1 deletion docs/guide/java/cross-language.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Cross-Language Serialization
sidebar_position: 8
sidebar_position: 11
id: cross_language
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
Expand Down
Loading
Loading