Rustly 10.2.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package Rustly --version 10.2.1
                    
NuGet\Install-Package Rustly -Version 10.2.1
                    
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="Rustly" Version="10.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Rustly" Version="10.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Rustly" />
                    
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 Rustly --version 10.2.1
                    
#r "nuget: Rustly, 10.2.1"
                    
#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 Rustly@10.2.1
                    
#: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=Rustly&version=10.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Rustly&version=10.2.1
                    
Install as a Cake Tool

Rustly (v10.2.1)

Rust-inspired Result<T, E>, Option<T>, Unit, and EnumValue types for C#. Replace exceptions with explicit, composable error handling. Zero-allocation value types.

All types and helpers are auto-imported when you add the package -- no using statements needed.

Installation

dotnet add package Rustly --version 10.2.1

Types

Type Description
Result<T, E> Success (Ok) or error (Err) -- discriminated union
Option<T> Some(T) or None -- nullable alternative
Unit Void replacement for Result<Unit, E>
[EnumValue] Associate data with enum members (Rust-style variants)

Usage

Option<T>

// Implicit conversion: T -> Some(T)
Option<int> age = 25;                        // Some(25)
Option<string> name = "Alice";               // Some("Alice")

// None via default
Option<int> empty = default;                 // None
Option<string> noName = default;             // None

// Note: Option<object> cannot be assigned null directly -- use default
Option<object> obj = default;                // None (correct)
// Option<object> obj = null;                // compile error

// Explicit cast: Option<T> -> T (equivalent to Unwrap)
int value = (int)age;                        // 25

// Safe access
Option<string> FindUser(int id) =>
    id == 1 ? Some("Admin") : None<string>();

string name = FindUser(1).UnwrapOr("Unknown");

// Chaining
var greeting = FindUser(1)
    .Map(n => $"Hello, {n}!")
    .UnwrapOr("Hello, stranger!");

// Filtering
var admin = FindUser(1).Filter(n => n == "Admin");

// Convert to Result
Result<string, string> r = FindUser(42).OkOr("User not found");

// Pattern matching (U is inferred from lambdas)
var message = FindUser(42).Match(
    n => $"Found: {n}",
    () => "Not found"
);

Result<T, E>

// Implicit conversion: T -> Ok(T)
Result<int, string> Divide(int a, int b) =>
    b == 0 ? Err<int, string>("Division by zero") : a / b;

// Explicit cast: E -> Err(E)
Result<int, string> err = (Result<int, string>)"something went wrong";

// Explicit cast: Result<T, E> -> T (equivalent to Unwrap)
int value = (int)Divide(10, 2);              // 5

// Pattern matching (U is inferred from lambdas)
string message = Divide(10, 0).Match(
    value => $"Result: {value}",
    error => $"Error: {error}"
);

// Chaining
var doubled = Divide(10, 2)
    .Map(x => x * 2)
    .UnwrapOr(0);

// Composition
var final = Divide(10, 2)
    .AndThen(x => Divide(x, 3))
    .MapErr(e => $"Pipeline failed: {e}");

// Querying
bool isPositive = Divide(10, 2).IsOkAnd(x => x > 0);
bool isBadInput = Divide(10, 0).ContainsErr("Division by zero");

Result<Unit, E> (void operations)

Result<Unit, string> SaveFile(string path)
{
    // ... operation ...
    return Unit.Value;  // implicit Unit -> Ok
}

SaveFile("/tmp/data.txt")
    .InspectErr(e => Console.WriteLine($"Save failed: {e}"));

Combining

// Zip two options
var pair = Some(1).Zip(Some("hello"));  // Some((1, "hello"))

// Flatten nested types
Option<Option<int>> nested = Some(Some(42));
Option<int> flat = nested.Flatten();  // Some(42)

// Transpose
Option<Result<int, string>> optRes = Some(Ok<int, string>(42));
Result<Option<int>, string> resOpt = optRes.Transpose();  // Ok(Some(42))

// Xor
var a = Some(1);
var b = None<int>();
var x = a.Xor(b);  // Some(1) -- exactly one is Some

EnumValue -- Rust-style Enum Variants

public enum LogLevel
{
    [EnumValue("TRC")] Trace,
    [EnumValue("DBG")] Debug,
    [EnumValue("INF")] Info,
}

// Value<T>() returns Option<T> -- no nullable
Option<string> label = LogLevel.Trace.Value<string>();   // Some("TRC")
Option<string> none  = LogLevel.Trace.Value<int>();      // None (wrong type)

// RawValue() returns Option<object>
Option<object> raw = LogLevel.Info.RawValue();           // Some("INF")

EnumValue JSON Serialization

// System.Text.Json -- apply per-enum or globally via factory
using System.Text.Json;
using Rustly.Serialization;

[JsonConverter(typeof(EnumValueJsonConverter<LogLevel>))]
public enum LogLevel { [EnumValue("TRC")] Trace, [EnumValue("DBG")] Debug }

JsonSerializer.Serialize(LogLevel.Trace);                // "TRC"
JsonSerializer.Deserialize<LogLevel>("\"TRC\"");         // LogLevel.Trace

// Global factory -- auto-detects all enums with [EnumValue]
var options = new JsonSerializerOptions();
options.Converters.Add(new EnumValueJsonConverterFactory());

// Newtonsoft.Json -- works on all platforms including netstandard2.1
using Newtonsoft.Json;
using Rustly.Serialization.Newtonsoft;

var settings = new JsonSerializerSettings();
settings.Converters.Add(new EnumValueNewtonsoftJsonConverter());
JsonConvert.SerializeObject(LogLevel.Trace, settings);   // "TRC"

JSON Serialization (Option & Result)

Option<T> and Result<T, E> work with System.Text.Json automatically (.NET 5+). No registration needed:

// System.Text.Json (auto, .NET 5+)
JsonSerializer.Serialize(Some("hello"));                 // "hello"
JsonSerializer.Serialize(None<string>());                // null
JsonSerializer.Serialize(Ok<int, string>(42));           // {"ok":42}
JsonSerializer.Serialize(Err<int, string>("fail"));      // {"err":"fail"}

// Newtonsoft.Json (register converters)
using Rustly.Serialization.Newtonsoft;

var settings = new JsonSerializerSettings();
settings.Converters.Add(new OptionNewtonsoftJsonConverter());
settings.Converters.Add(new ResultNewtonsoftJsonConverter());

JsonConvert.SerializeObject(Some(42), settings);                     // 42
JsonConvert.SerializeObject(Option<string>.None, settings);          // null
JsonConvert.SerializeObject(Result<int, string>.Ok(42), settings);   // {"ok":42}

EnumValue TypeConverter (Configuration.Binder)

using System.ComponentModel;
using Rustly.Converters;

[TypeConverter(typeof(EnumValueTypeConverter))]
public enum LogLevel
{
    [EnumValue("TRC")] Trace,
    [EnumValue("DBG")] Debug,
}

// appsettings.json: { "MinimumLevel": "TRC" }
// Binds to LogLevel.Trace via EnumValueTypeConverter

Configuration Binding (Option<T>)

public class AppSettings
{
    public Option<string> ConnectionString { get; set; }
    public Option<int> MaxRetries { get; set; }
}

// appsettings.json:  { "MaxRetries": 5 }
var settings = new AppSettings();
configuration.GetSection("App").Bind(settings);

var retries = settings.MaxRetries.UnwrapOr(3);   // 5 (from config)
var connStr = settings.ConnectionString;          // None (not in config)

API Reference

Result<T, E>

Method Rust equivalent Description
Ok(T) / Err(E) Ok(v) / Err(e) Create result
IsOk / IsErr is_ok() / is_err() Check variant
IsOkAnd(f) / IsErrAnd(f) is_ok_and / is_err_and Check variant + predicate
Contains(v) / ContainsErr(e) contains / contains_err Check if contains value
Unwrap() / UnwrapErr() unwrap / unwrap_err Get value (unsafe)
UnwrapOr(T) unwrap_or Get value or default
UnwrapOrElse(Func) unwrap_or_else Get value or compute default
Map(f) / MapErr(f) map / map_err Transform value/error
MapOr(default, f) map_or Map with default fallback
MapOrElse(default_f, f) map_or_else Map with lazy default
AndThen(f) / And(res) and_then / and Chain on Ok
OrElse(f) / Or(res) or_else / or Recover on Err
Inspect(f) / InspectErr(f) inspect / inspect_err Side-effects
Match(ok, err) match Pattern match
Ok() / ToOption() ok() Ok->Some, Err->None
Err() err() Err->Some, Ok->None
implicit T->Result -- Result<int,string> r = 42;
explicit E->Result -- var r = (Result<int,string>)"error";
.Flatten() (ext) flatten Unwrap nested Result
.Transpose() (ext) transpose Result<Option> to Option<Result>

Option<T>

Method Rust equivalent Description
Some(T) / None Some(v) / None Create option
IsSome / IsNone is_some / is_none Check variant
IsSomeAnd(f) is_some_and Check + predicate
Contains(v) contains Check if contains value
Unwrap() unwrap Get value (unsafe)
UnwrapOr(T) / UnwrapOrElse(f) unwrap_or / unwrap_or_else Get or default
Map(f) map Transform value
MapOr(default, f) map_or Map with default
MapOrElse(default_f, f) map_or_else Map with lazy default
Filter(predicate) filter Keep Some only if matches
AndThen(f) / And(opt) and_then / and Chain on Some
Or(opt) / OrElse(f) or / or_else Fallback on None
Xor(opt) xor Exactly one is Some
Zip(opt) zip Combine two Options into tuple
Inspect(f) inspect Side-effect on Some
Match(some, none) match Pattern match
OkOr(e) / OkOrElse(f) ok_or / ok_or_else Convert to Result
implicit T->Option -- Option<int> o = 42;
explicit Option->T -- int v = (int)o;
.Flatten() (ext) flatten Unwrap nested Option
.Transpose() (ext) transpose Option<Result> to Result<Option>
.ZipWith(opt, f) (ext) zip_with Combine with function
.Unzip() (ext) unzip Split Option<tuple>

Prelude (auto-imported)

Helper Equivalent
Ok<T, E>(value) Result<T, E>.Ok(value)
Err<T, E>(error) Result<T, E>.Err(error)
Some<T>(value) Option<T>.Some(value)
None<T>() Option<T>.None

License

MIT

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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 is compatible.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on Rustly:

Package Downloads
Slotly.Core

Core types for the Slotly plugin framework: IPlugin, IPluginManifest, PluginState, PluginError, IPluginContext.

Rustly.Json

System.Text.Json converters for Rustly Option, Result, and EnumValue. Includes source generators for AOT-friendly serialization. Part of the Rustly ecosystem.

Rustly.Json.Newtonsoft

Newtonsoft.Json converters for Rustly Option, Result, and EnumValue enums. Part of the Rustly ecosystem.

Rustly.Configuration

IConfiguration binding for Rustly types. RBind() handles Option and EnumValue object format seamlessly. Part of the Rustly ecosystem.

TunnelForge.Tun

Cross-platform TUN adapter abstraction for .NET. Unified ITunAdapter interface for Windows (WinTun) and Linux (/dev/net/tun). Error handling via Rustly Result<T, E> — no exceptions.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.6.4 817 4/28/2026
10.6.3 230 4/16/2026
10.6.2 236 4/16/2026
10.6.2-rc6 255 4/16/2026
10.6.2-rc5 299 4/15/2026 10.6.2-rc5 is deprecated because it is no longer maintained and has critical bugs.
10.6.1 169 4/15/2026
10.5.0 217 4/15/2026 10.5.0 is deprecated because it is no longer maintained and has critical bugs.
10.4.0 232 4/15/2026 10.4.0 is deprecated because it is no longer maintained and has critical bugs.
10.3.1 227 4/14/2026 10.3.1 is deprecated because it is no longer maintained and has critical bugs.
10.2.1 665 4/14/2026 10.2.1 is deprecated because it is no longer maintained and has critical bugs.
10.2.0 1,233 4/13/2026 10.2.0 is deprecated because it is no longer maintained and has critical bugs.
10.1.1 127 4/13/2026 10.1.1 is deprecated because it is no longer maintained and has critical bugs.
10.1.0 139 4/13/2026 10.1.0 is deprecated because it is no longer maintained and has critical bugs.
10.0.3 131 4/13/2026 10.0.3 is deprecated because it is no longer maintained and has critical bugs.
10.0.2 235 4/8/2026 10.0.2 is deprecated because it is no longer maintained and has critical bugs.
10.0.1 130 4/8/2026 10.0.1 is deprecated because it is no longer maintained and has critical bugs.
10.0.0 128 4/8/2026 10.0.0 is deprecated because it is no longer maintained and has critical bugs.
10.0.0-rc2 119 4/8/2026 10.0.0-rc2 is deprecated because it is no longer maintained and has critical bugs.
10.0.0-rc 124 4/8/2026 10.0.0-rc is deprecated because it is no longer maintained and has critical bugs.

EN:
Version 10.2.1:
- [BREAKING] EnumValueExtensions: Value<T>() and RawValue() now return Option instead of nullable
- Added EnumValueJsonConverter (System.Text.Json) — serialize enums by [EnumValue]
- Added EnumValueJsonConverterFactory — global auto-detect factory for [EnumValue] enums
- Added EnumValueTypeConverter — TypeConverter for Configuration.Binder with [EnumValue]
- Added Newtonsoft.Json converters: OptionNewtonsoftJsonConverter, ResultNewtonsoftJsonConverter, EnumValueNewtonsoftJsonConverter
- Internal cache refactored to Option

RU:
Версия 10.2.1:
- [BREAKING] EnumValueExtensions: Value<T>() и RawValue() возвращают Option вместо nullable
- Добавлен EnumValueJsonConverter (System.Text.Json) — сериализация enum по [EnumValue]
- Добавлен EnumValueJsonConverterFactory — фабрика автоопределения [EnumValue] enum
- Добавлен EnumValueTypeConverter — TypeConverter для Configuration.Binder с [EnumValue]
- Добавлены Newtonsoft.Json конвертеры: OptionNewtonsoftJsonConverter, ResultNewtonsoftJsonConverter, EnumValueNewtonsoftJsonConverter
- Внутренний кэш на Option вместо nullable