JanetSharp 0.1.5

dotnet add package JanetSharp --version 0.1.5
                    
NuGet\Install-Package JanetSharp -Version 0.1.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JanetSharp" Version="0.1.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="JanetSharp" Version="0.1.5" />
                    
Directory.Packages.props
<PackageReference Include="JanetSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add JanetSharp --version 0.1.5
                    
#r "nuget: JanetSharp, 0.1.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package JanetSharp@0.1.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=JanetSharp&version=0.1.5
                    
Install as a Cake Addin
#tool nuget:?package=JanetSharp&version=0.1.5
                    
Install as a Cake Tool

JanetSharp

A .NET bridge for embedding the Janet programming language in C# applications. JanetSharp lets you evaluate Janet code, share data structures, invoke Janet functions from C#, and expose C# callbacks to Janet — all with full GC safety and no risk of runtime crashes from Janet's longjmp-based error handling.

Features

  • Full Janet language — complete stdlib via two-stage boot (defn, loop, map, match, import, macros, and all ~500 stdlib functions)
  • Module system — register Janet modules from C# strings or tables, importable via (import name)
  • Safe interop — C-shim layer catches all Janet panics before they cross P/Invoke boundaries
  • Full type system — strings, symbols, keywords, arrays, tuples, tables, structs, buffers
  • Bi-directional function calls — call Janet functions from C#, register C# callbacks callable from Janet
  • Fibers (coroutines) — create, resume, and yield from Janet fibers with full signal inspection
  • Automatic type coercion — convert between .NET primitives and Janet values with JanetConvert
  • GC-safe smart pointersJanetValue roots/unroots references in Janet's GC automatically
  • Cross-platform — native shim builds for Windows, Linux, and macOS via CMake

Quick Start

using JanetSharp;

// Initialize the Janet runtime (one per thread)
using var runtime = new JanetRuntime();

// Evaluate Janet expressions
var result = runtime.Eval("(+ 1 2 3)");
Console.WriteLine(result.AsNumber()); // 6

// Work with Janet types
using var arr = JanetArray.Create();
arr.Add(Janet.From(1.0));
arr.Add(Janet.From(2.0));
arr.Add(Janet.From(3.0));
Console.WriteLine(arr.Count); // 3

// Invoke Janet functions from C#
using var plus = runtime.GetFunction("+");
var sum = plus.Invoke(Janet.From(10.0), Janet.From(20.0));
Console.WriteLine(sum.AsNumber()); // 30

// Register C# callbacks callable from Janet
using var cb = runtime.Register("double-it", args =>
    Janet.From(args[0].AsNumber() * 2));

var doubled = runtime.Eval("(double-it 21)");
Console.WriteLine(doubled.AsNumber()); // 42

// Fibers (coroutines)
using var yieldFn = runtime.GetFunction("(fn [] (yield 1) (yield 2) 3)");
using var fiber = JanetFiber.Create(yieldFn);

Console.WriteLine(fiber.Status);        // New
Console.WriteLine(fiber.Resume());      // Janet(Number) → yielded 1
Console.WriteLine(fiber.Status);        // Pending
Console.WriteLine(fiber.Resume());      // Janet(Number) → yielded 2
Console.WriteLine(fiber.Resume());      // Janet(Number) → returned 3
Console.WriteLine(fiber.CanResume);     // False

// Wrap .NET objects as Janet abstracts (GC-bridged)
using var abs = JanetAbstract.Create(new List<string> { "hello", "world" });
Console.WriteLine(abs.Type);                       // Abstract
var list = abs.GetTarget<List<string>>();           // same reference
Console.WriteLine(list[0]);                        // "hello"

// Modules — register from C#, import from Janet
runtime.Modules.AddModule("mylib", @"
    (defn greet [name] (string ""Hello, "" name ""!""))
");
var greeting = runtime.Eval(@"(import mylib) (mylib/greet ""world"")");
Console.WriteLine(greeting.AsString()); // "Hello, world!"

// Automatic type coercion
Janet j = JanetConvert.ToJanet("hello");
string s = JanetConvert.ToClr<string>(j); // "hello"

Installation

Prerequisites

  • .NET 9.0+ SDK
  • CMake 3.15+
  • C compiler (Visual Studio 2022 Build Tools on Windows, gcc/clang on Linux/macOS)

Build from Source

# Clone with submodules
git clone --recurse-submodules https://github.com/andreamancuso/Janet-CSharp.git
cd Janet-CSharp

# Build the native shim
cd native
cmake -B build
cmake --build build --config Release
cd ..

# Build and test
dotnet build
dotnet test

Note: A self-contained NuGet package (no manual native build required) is planned for a future release.

API Overview

Core Types

Type Description
JanetRuntime Manages the Janet VM lifecycle. One instance per OS thread.
Janet 8-byte NaN-boxed value struct. Lightweight, pass by value.
JanetValue GC-rooted wrapper (IDisposable). Use for heap-allocated Janet values.
JanetFunction Wraps a Janet function for safe invocation from C#.
JanetFiber Wraps a Janet fiber (coroutine) with resume/yield/status.
JanetAbstract Wraps a .NET object as a Janet abstract, GC-bridged.
JanetModule Registers modules importable via Janet's (import name).
JanetCallback Exposes a C# delegate as a Janet-callable function.
JanetConvert Static helper for .NET ↔ Janet type coercion.

Collection Types

Type Janet Type C# Interface
JanetString string JanetValue + ToString(), AsSpan()
JanetSymbol symbol JanetValue + ToString(), AsSpan()
JanetKeyword keyword JanetValue + ToString(), AsSpan()
JanetArray array IList<Janet>
JanetTuple tuple IReadOnlyList<Janet>
JanetTable table IDictionary<Janet, Janet>
JanetStruct struct IReadOnlyDictionary<Janet, Janet>
JanetBuffer buffer JanetValue + WriteByte(), AsSpan()
JanetAbstract abstract JanetValue + Target, GetTarget<T>()

Architecture

JanetSharp uses a C-shim layer (native/janet_shim.c) between .NET and Janet. This is necessary because Janet uses setjmp/longjmp for error handling — if a longjmp unwinds through a managed P/Invoke frame, the CLR crashes. The shim wraps all Janet API calls so panics are caught by janet_pcall and converted to return codes.

Janet values are 64-bit NaN-boxed unions that cross the P/Invoke boundary as long. The Janet struct in C# mirrors this layout. Heap-allocated Janet objects (strings, arrays, tables, etc.) must be GC-rooted via janet_gcroot to prevent Janet's garbage collector from freeing them while C# still holds a reference — JanetValue handles this automatically.

C# callbacks are exposed to Janet as Callable Abstracts. The C shim registers a custom Janet Abstract type that wraps an unmanaged function pointer. When Janet calls the abstract, a metamethod executes the C# delegate, ensuring a seamless and infinitely scalable callback system.

Current Limitations

  • Single-threaded (per runtime) — Janet itself is single-threaded. JanetRuntime enforces thread affinity. However, you can safely create multiple JanetRuntime instances across different OS threads for true concurrency.
  • macOS support — the native shim builds on macOS but crashes during janet_init() on Apple Silicon CI runners. macOS is temporarily disabled in CI. Local macOS builds may work.

Contributing

See CONTRIBUTING.md for build instructions, architecture overview, and development guidelines.

Documentation

See the User Guide for detailed guides on types, function calls, callbacks, type coercion, and memory management.

Roadmap

See ROADMAP.md for the full development plan.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.5 207 4/13/2026
0.1.4 91 4/13/2026
0.1.3 98 4/12/2026
0.1.2 148 3/13/2026
0.1.1 125 3/13/2026
0.1.0 140 3/13/2026
0.0.4 132 3/13/2026
0.0.3 137 3/13/2026
0.0.2 137 3/13/2026
0.0.1 130 3/12/2026