Skip to content
Open
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
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,30 @@ jobs:
- name: Run example
working-directory: ./js
run: npm run example

test-csharp:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Restore dependencies
working-directory: ./csharp
run: dotnet restore

- name: Build
working-directory: ./csharp
run: dotnet build --no-restore

- name: Run tests
working-directory: ./csharp
run: dotnet test --no-build --verbosity normal

- name: Run example
working-directory: ./csharp
run: dotnet run --project examples/BasicUsage.csproj
72 changes: 69 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@
[![Tests](https://github.com/link-foundation/lino-objects-codec/actions/workflows/test.yml/badge.svg)](https://github.com/link-foundation/lino-objects-codec/actions/workflows/test.yml)
[![Python Version](https://img.shields.io/pypi/pyversions/lino-objects-codec.svg)](https://pypi.org/project/lino-objects-codec/)

Universal serialization library to encode/decode objects to/from Links Notation format. Available in both **Python** and **JavaScript** with identical functionality and API design.
Universal serialization library to encode/decode objects to/from Links Notation format. Available in **Python**, **JavaScript**, and **C#** with identical functionality and API design.

## 🌍 Multi-Language Support

This library provides universal serialization and deserialization with built-in support for circular references and complex object graphs in:

- **[Python](python/)** - Full implementation for Python 3.8+
- **[JavaScript](js/)** - Full implementation for Node.js 18+
- **[C#](csharp/)** - Full implementation for .NET 8.0+

Both implementations share the same design philosophy and provide feature parity.
All implementations share the same design philosophy and provide feature parity.

## Features

- **Universal Serialization**: Encode objects to Links Notation format
- **Type Support**: Handle all common types in each language:
- **Python**: `None`, `bool`, `int`, `float`, `str`, `list`, `dict`
- **JavaScript**: `null`, `undefined`, `boolean`, `number`, `string`, `Array`, `Object`
- **C#**: `null`, `bool`, `int`, `long`, `float`, `double`, `string`, `List<object?>`, `Dictionary<string, object?>`
- Special float/number values: `NaN`, `Infinity`, `-Infinity`
- **Circular References**: Automatically detect and preserve circular references
- **Object Identity**: Maintain object identity for shared references
Expand Down Expand Up @@ -63,6 +65,27 @@ const decoded = decode(encoded);
console.log(JSON.stringify(decoded) === JSON.stringify(data)); // true
```

### C#

```bash
dotnet add package Lino.Objects.Codec
```

```csharp
using Lino.Objects.Codec;

// Encode and decode
var data = new Dictionary<string, object?>
{
{ "name", "Alice" },
{ "age", 30 },
{ "active", true }
};
var encoded = Codec.Encode(data);
var decoded = Codec.Decode(encoded) as Dictionary<string, object?>;
Console.WriteLine(decoded?["name"]); // Alice
```

## Repository Structure

```
Expand All @@ -77,6 +100,11 @@ console.log(JSON.stringify(decoded) === JSON.stringify(data)); // true
│ ├── tests/ # Test suite
│ ├── examples/ # Usage examples
│ └── README.md # JavaScript-specific docs
├── csharp/ # C# implementation
│ ├── src/ # Source code
│ ├── tests/ # Test suite
│ ├── examples/ # Usage examples
│ └── README.md # C#-specific docs
└── README.md # This file
```

Expand All @@ -86,10 +114,11 @@ For detailed documentation, API reference, and examples, see:

- **[Python Documentation](python/README.md)**
- **[JavaScript Documentation](js/README.md)**
- **[C# Documentation](csharp/README.md)**

## Usage Examples

Both implementations support the same features with language-appropriate syntax:
All implementations support the same features with language-appropriate syntax:

### Circular References

Expand All @@ -115,6 +144,17 @@ const decoded = decode(encode(arr));
console.log(decoded[3] === decoded); // true - Reference preserved
```

**C#:**
```csharp
using Lino.Objects.Codec;

// Self-referencing list
var lst = new List<object?>();
lst.Add(lst);
var decoded = Codec.Decode(Codec.Encode(lst)) as List<object?>;
Console.WriteLine(ReferenceEquals(decoded, decoded?[0])); // True - Reference preserved
```

### Complex Nested Structures

**Python:**
Expand All @@ -141,6 +181,22 @@ const data = {
console.log(JSON.stringify(decode(encode(data))) === JSON.stringify(data));
```

**C#:**
```csharp
var data = new Dictionary<string, object?>
{
{
"users", new List<object?>
{
new Dictionary<string, object?> { { "id", 1 }, { "name", "Alice" } },
new Dictionary<string, object?> { { "id", 2 }, { "name", "Bob" } }
}
},
{ "metadata", new Dictionary<string, object?> { { "version", 1 }, { "count", 2 } } }
};
var decoded = Codec.Decode(Codec.Encode(data));
```

## How It Works

The library uses the [links-notation](https://github.com/link-foundation/links-notation) format as the serialization target. Each object is encoded as a Link with type information:
Expand Down Expand Up @@ -181,6 +237,15 @@ npm test
npm run example
```

### C#

```bash
cd csharp
dotnet build
dotnet test
dotnet run --project examples/BasicUsage.csproj
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.
Expand All @@ -203,6 +268,7 @@ This project is licensed under the Unlicense - see the [LICENSE](LICENSE) file f
- [Links Notation Specification](https://github.com/link-foundation/links-notation)
- [PyPI Package](https://pypi.org/project/lino-objects-codec/) (Python)
- [npm Package](https://www.npmjs.com/package/lino-objects-codec/) (JavaScript)
- [NuGet Package](https://www.nuget.org/packages/Lino.Objects.Codec/) (C#)

## Acknowledgments

Expand Down
55 changes: 55 additions & 0 deletions csharp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio
.vs/
*.user
*.userosscache
*.suo
*.sln.docstates

# NuGet
*.nupkg
*.snupkg
.nuget/
packages/
**/packages.lock.json

# Test results
[Tt]est[Rr]esult*/
[Tt]est[Rr]un*.trx
*.coverage
*.coveragexml
*.dotCover

# Build outputs
*.dll
*.exe
*.pdb
!TestResults/

# User-specific files
*.rsuser
*.suo
*.user
*.sln.docstates

# JetBrains Rider
.idea/
*.sln.iml

# macOS
.DS_Store
25 changes: 25 additions & 0 deletions csharp/Lino.Objects.Codec.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lino.Objects.Codec", "src\Lino.Objects.Codec\Lino.Objects.Codec.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lino.Objects.Codec.Tests", "tests\Lino.Objects.Codec.Tests\Lino.Objects.Codec.Tests.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Loading