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
175 changes: 175 additions & 0 deletions csharp/Platform.Data.Doublets.NativeLibrary/DoubletsNativeLibrary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using Platform.Data.Doublets.Memory.United.Generic;

namespace Platform.Data.Doublets.NativeLibrary
{
public static unsafe class DoubletsNativeLibrary
{
private static readonly Dictionary<IntPtr, UnitedMemoryLinks<ulong>> _instances = new();
private static readonly object _lock = new object();
private static IntPtr _nextHandle = new IntPtr(1);

[UnmanagedCallersOnly(EntryPoint = "UInt64UnitedMemoryLinks_New")]
public static IntPtr CreateLinks(IntPtr pathPtr)
{
try
{
var path = Marshal.PtrToStringAnsi(pathPtr);
if (string.IsNullOrEmpty(path))
return IntPtr.Zero;

var links = new UnitedMemoryLinks<ulong>(path);

lock (_lock)
{
var handle = _nextHandle;
_nextHandle = new IntPtr(_nextHandle.ToInt64() + 1);
_instances[handle] = links;
return handle;
}
}
catch
{
return IntPtr.Zero;
}
}

[UnmanagedCallersOnly(EntryPoint = "UInt64UnitedMemoryLinks_Drop")]
public static void DisposeLinks(IntPtr handle)
{
try
{
lock (_lock)
{
if (_instances.TryGetValue(handle, out var links))
{
links.Dispose();
_instances.Remove(handle);
}
}
}
catch
{
// Ignore disposal errors
}
}

[UnmanagedCallersOnly(EntryPoint = "UInt64UnitedMemoryLinks_Create")]
public static ulong CreateLink(IntPtr handle, ulong* query, nuint queryLen)
{
try
{
lock (_lock)
{
if (!_instances.TryGetValue(handle, out var links))
return 0;

var queryArray = new ulong[queryLen];
for (int i = 0; i < (int)queryLen; i++)
{
queryArray[i] = query[i];
}

return links.Create(queryArray);
}
}
catch
{
return 0;
}
}

[UnmanagedCallersOnly(EntryPoint = "UInt64UnitedMemoryLinks_Count")]
public static ulong CountLinks(IntPtr handle, ulong* query, nuint queryLen)
{
try
{
lock (_lock)
{
if (!_instances.TryGetValue(handle, out var links))
return 0;

var queryArray = new ulong[queryLen];
for (int i = 0; i < (int)queryLen; i++)
{
queryArray[i] = query[i];
}

return links.Count(queryArray);
}
}
catch
{
return 0;
}
}

[UnmanagedCallersOnly(EntryPoint = "UInt64UnitedMemoryLinks_Update")]
public static ulong UpdateLink(IntPtr handle, ulong* query, nuint queryLen, ulong* replacement, nuint replacementLen)
{
try
{
lock (_lock)
{
if (!_instances.TryGetValue(handle, out var links))
return 0;

var queryArray = new ulong[queryLen];
for (int i = 0; i < (int)queryLen; i++)
{
queryArray[i] = query[i];
}

var replacementArray = new ulong[replacementLen];
for (int i = 0; i < (int)replacementLen; i++)
{
replacementArray[i] = replacement[i];
}

return links.Update(queryArray, replacementArray);
}
}
catch
{
return 0;
}
}

[UnmanagedCallersOnly(EntryPoint = "UInt64UnitedMemoryLinks_Delete")]
public static ulong DeleteLink(IntPtr handle, ulong* query, nuint queryLen)
{
try
{
lock (_lock)
{
if (!_instances.TryGetValue(handle, out var links))
return 0;

var queryArray = new ulong[queryLen];
for (int i = 0; i < (int)queryLen; i++)
{
queryArray[i] = query[i];
}

return links.Delete(queryArray);
}
}
catch
{
return 0;
}
}

// Basic version info export
[UnmanagedCallersOnly(EntryPoint = "GetLibraryVersion")]
public static IntPtr GetVersion()
{
var version = "0.1.0-nativeaot";
var ptr = Marshal.StringToHGlobalAnsi(version);
return ptr;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>LinksPlatform's Platform.Data.Doublets Native Library</Description>
<Copyright>konard, FreePhoenix888</Copyright>
<AssemblyTitle>Platform.Data.Doublets.NativeLibrary</AssemblyTitle>
<VersionPrefix>0.1.0</VersionPrefix>
<Authors>konard, FreePhoenix888</Authors>
<TargetFramework>net8</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyName>Platform.Data.Doublets.NativeLibrary</AssemblyName>
<PackageId>Platform.Data.Doublets.NativeLibrary</PackageId>
<PackageTags>LinksPlatform;Data.Doublets;NativeLibrary;CoreRT;NativeAOT</PackageTags>
<PackageProjectUrl>https://linksplatform.github.io/Data.Doublets</PackageProjectUrl>
<PackageLicenseExpression>Unlicense</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>git://github.com/linksplatform/Data.Doublets</RepositoryUrl>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<OutputType>Library</OutputType>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Platform.Data.Doublets\Platform.Data.Doublets.csproj" />
</ItemGroup>

</Project>
111 changes: 111 additions & 0 deletions csharp/Platform.Data.Doublets.NativeLibrary/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Platform.Data.Doublets Native Library

This project implements a native library version of Platform.Data.Doublets using .NET NativeAOT (formerly CoreRT). The native library exposes C-style APIs that can be called from any language that supports C FFI.

## Overview

The native library provides native bindings for the core Platform.Data.Doublets functionality, specifically the `UnitedMemoryLinks<ulong>` implementation. All major operations (Create, Read, Update, Delete, Count) are exposed as C-style function exports.

## Building

### Prerequisites
- .NET 8 SDK or later
- NativeAOT support (included in .NET 8)

### Build Commands

```bash
# Build the native library for Linux x64
dotnet publish -r linux-x64 -c Release --self-contained

# Build for other platforms
dotnet publish -r win-x64 -c Release --self-contained # Windows
dotnet publish -r osx-x64 -c Release --self-contained # macOS
```

Or use the provided build script:
```bash
cd csharp/
./build-native-library.sh
```

## Generated Files

After building, you'll find the native libraries in:
- `bin/Release/net8/[runtime]/publish/Platform.Data.Doublets.NativeLibrary.so` (Linux)
- `bin/Release/net8/[runtime]/publish/Platform.Data.Doublets.NativeLibrary.dll` (Windows)
- `bin/Release/net8/[runtime]/publish/Platform.Data.Doublets.NativeLibrary.dylib` (macOS)

## Exported Functions

The library exports the following C-style functions:

### Instance Management
- `IntPtr UInt64UnitedMemoryLinks_New(IntPtr pathPtr)` - Create a new links instance
- `void UInt64UnitedMemoryLinks_Drop(IntPtr handle)` - Dispose of a links instance

### Link Operations
- `ulong UInt64UnitedMemoryLinks_Create(IntPtr handle, ulong* query, nuint queryLen)` - Create a link
- `ulong UInt64UnitedMemoryLinks_Count(IntPtr handle, ulong* query, nuint queryLen)` - Count matching links
- `ulong UInt64UnitedMemoryLinks_Update(IntPtr handle, ulong* query, nuint queryLen, ulong* replacement, nuint replacementLen)` - Update a link
- `ulong UInt64UnitedMemoryLinks_Delete(IntPtr handle, ulong* query, nuint queryLen)` - Delete a link

### Utility
- `IntPtr GetLibraryVersion()` - Get library version string

## Usage Example (C)

```c
#include <stdio.h>
#include <stdlib.h>

// Function declarations
IntPtr UInt64UnitedMemoryLinks_New(const char* path);
void UInt64UnitedMemoryLinks_Drop(IntPtr handle);
ulong UInt64UnitedMemoryLinks_Create(IntPtr handle, ulong* query, size_t queryLen);
ulong UInt64UnitedMemoryLinks_Count(IntPtr handle, ulong* query, size_t queryLen);

int main() {
// Create a new links database
IntPtr links = UInt64UnitedMemoryLinks_New("test.links");
if (links == 0) {
printf("Failed to create links database\\n");
return 1;
}

// Create a link: [any, any] -> returns created link
ulong query[] = {0, 0};
ulong result = UInt64UnitedMemoryLinks_Create(links, query, 2);
printf("Created link: %llu\\n", result);

// Count all links
ulong count = UInt64UnitedMemoryLinks_Count(links, query, 2);
printf("Total links: %llu\\n", count);

// Clean up
UInt64UnitedMemoryLinks_Drop(links);
return 0;
}
```

## Architecture

The native library implementation:

1. **Uses NativeAOT**: Compiles C# code to native machine code ahead-of-time
2. **C-style exports**: Uses `[UnmanagedCallersOnly]` attribute to export functions
3. **Handle-based API**: Manages C# objects through integer handles to avoid direct memory management
4. **Thread-safe**: Uses locks to ensure thread safety across FFI calls
5. **Error handling**: Returns 0 or null on errors, avoiding exceptions across FFI boundary

## Compatibility

This native library is compatible with the existing FFI interface defined in `c/ffi.h`, providing the same function signatures and behavior as the Rust implementation.

## Benefits over CoreRT

- **Modern approach**: Uses .NET 8 NativeAOT instead of deprecated CoreRT
- **Better performance**: Optimized AOT compilation with latest .NET runtime
- **Self-contained**: No .NET runtime dependency required
- **Smaller footprint**: Native compilation reduces deployment size
- **Cross-platform**: Supports Windows, Linux, and macOS
6 changes: 6 additions & 0 deletions csharp/Platform.Data.Doublets.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Platform.Data.Doublets.Test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Platform.Data.Doublets.Benchmarks", "Platform.Data.Doublets.Benchmarks\Platform.Data.Doublets.Benchmarks.csproj", "{B3526338-1437-41A6-A613-B5B1222D3BB4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Platform.Data.Doublets.NativeLibrary", "Platform.Data.Doublets.NativeLibrary\Platform.Data.Doublets.NativeLibrary.csproj", "{C7F7E2A0-8E3D-4B9C-A1F5-3D2E1A4F8C9B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -27,6 +29,10 @@ Global
{B3526338-1437-41A6-A613-B5B1222D3BB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B3526338-1437-41A6-A613-B5B1222D3BB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B3526338-1437-41A6-A613-B5B1222D3BB4}.Release|Any CPU.Build.0 = Release|Any CPU
{C7F7E2A0-8E3D-4B9C-A1F5-3D2E1A4F8C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7F7E2A0-8E3D-4B9C-A1F5-3D2E1A4F8C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7F7E2A0-8E3D-4B9C-A1F5-3D2E1A4F8C9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7F7E2A0-8E3D-4B9C-A1F5-3D2E1A4F8C9B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
25 changes: 25 additions & 0 deletions csharp/build-native-library.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

# Build script for Platform.Data.Doublets Native Library using NativeAOT

echo "Building Platform.Data.Doublets Native Library with NativeAOT..."

# Navigate to the native library project directory
cd "$(dirname "$0")/Platform.Data.Doublets.NativeLibrary"

# Build for different platforms
echo "Building for Linux x64..."
dotnet publish -r linux-x64 -c Release --self-contained

echo "Building for Windows x64..."
dotnet publish -r win-x64 -c Release --self-contained

echo "Building for macOS x64..."
dotnet publish -r osx-x64 -c Release --self-contained

echo "Build completed. Check the bin/Release/net8/[runtime]/publish/ directories for the native libraries."

# Show the output files
echo ""
echo "Generated native libraries:"
find bin/Release/net8 -name "*Platform.Data.Doublets.NativeLibrary*" -type f 2>/dev/null || echo "No output files found yet."
Loading
Loading