Rustly 10.2.1
See the version list below for details.
dotnet add package Rustly --version 10.2.1
NuGet\Install-Package Rustly -Version 10.2.1
<PackageReference Include="Rustly" Version="10.2.1" />
<PackageVersion Include="Rustly" Version="10.2.1" />
<PackageReference Include="Rustly" />
paket add Rustly --version 10.2.1
#r "nuget: Rustly, 10.2.1"
#:package Rustly@10.2.1
#addin nuget:?package=Rustly&version=10.2.1
#tool nuget:?package=Rustly&version=10.2.1
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 | Versions 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. |
-
.NETStandard 2.1
- Newtonsoft.Json (>= 13.0.3)
-
net10.0
- Newtonsoft.Json (>= 13.0.3)
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.1 | 169 | 4/15/2026 | |
| 10.5.0 | 217 | 4/15/2026 | |
| 10.4.0 | 232 | 4/15/2026 | |
| 10.3.1 | 227 | 4/14/2026 | |
| 10.2.1 | 665 | 4/14/2026 | |
| 10.2.0 | 1,233 | 4/13/2026 | |
| 10.1.1 | 127 | 4/13/2026 | |
| 10.1.0 | 139 | 4/13/2026 | |
| 10.0.3 | 131 | 4/13/2026 | |
| 10.0.2 | 235 | 4/8/2026 | |
| 10.0.1 | 130 | 4/8/2026 | |
| 10.0.0 | 128 | 4/8/2026 | |
| 10.0.0-rc2 | 119 | 4/8/2026 | |
| 10.0.0-rc | 124 | 4/8/2026 |
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