Zero-cost bit manipulation, Rust-style error handling, endian-safe integers, and high-performance fixed-width 256-bit math for modern .NET. One NuGet package. One source generator. No runtime dependencies.
Stardust.Utilities is a library, not a framework. You pick the pieces you need and use them exactly where you need them -- parsing a packet, decoding a register, shaping an API result. Nothing runs on its own, nothing calls home, and nothing ships with your binary except the code you touch.
- Why Stardust.Utilities?
- See It In One Snippet
- Try It Live
- Installation
- What's In The Box
- Features
- Compatibility
- Common Gotchas
- What's New
- License
- Contributing
- Security
- Privacy
- Zero abstraction penalty. Source-generated
[BitFields]types compile to the same IL as hand-coded shift/mask -- benchmark is statistically identical to raw bit manipulation across 160 independent runs (BITFIELDS.md -- Performance). - Zero heap allocations. Every value-type operation -- arithmetic, parsing, formatting, JSON round-trips, span I/O -- is stack-only. Value types never box.
- Competitive 256-bit math.
UInt256/Int256match or beat the leading managed 256-bit libraries on the operations that matter (add, sub, mul, div, parse, format). See the comparison table in the Large Integers section. - No runtime dependency. The source generator runs at build time and ships only as an analyzer. Your compiled app picks up nothing extra -- no second DLL, no reflection, no interface-based dispatch.
- Full modern .NET surface, generated for you.
IParsable<T>,ISpanParsable<T>,ISpanFormattable,System.Text.Json, full operator overloading, implicit conversions, span-based serialization -- all produced by the generator, not hand-written per struct. - Rust-inspired ergonomics, no religion.
Result<T, TError>andOption<T>live alongside normal exceptions. Use them where they fit; don't let them take over the codebase. - Runs everywhere .NET 7+ runs. Multi-targets
net7.0/net8.0/net9.0/net10.0. Tested on x64, ARM64, and big-endian architectures (via QEMU in CI).
If you have ever hand-rolled a bit-packed protocol header, juggled BinaryPrimitives.ReverseEndianness, or written the same if (result.IsOk) ... else ... boilerplate for the twentieth time -- this package removes that code.
Parse a live IPv4 header straight out of the packet buffer, zero copies:
using Stardust.Utilities;
// Define the RFC 791 layout once. No hand-written shift/mask anywhere.
[BitFields(ByteOrder.BigEndian, BitOrder.BitZeroIsMsb)]
public partial record struct IPv4Header
{
[BitField(0, 3)] public partial byte Version { get; set; }
[BitField(4, 7)] public partial byte IHL { get; set; }
[BitField(8, 15)] public partial byte TypeOfService{ get; set; }
[BitField(16, 31)] public partial ushort TotalLength { get; set; }
[BitField(64, 71)] public partial byte TTL { get; set; }
[BitField(72, 79)] public partial byte Protocol { get; set; }
[BitField(96, 127)] public partial uint SourceIP { get; set; }
}
// Read directly from the packet. No allocations, no copies.
byte[] packet = ReceiveFromNetwork();
var hdr = new IPv4Header(packet);
if (hdr.Version == 4 && hdr.Protocol == 6)
Console.WriteLine($"TCP packet, length {hdr.TotalLength}, TTL {hdr.TTL}");The generator emits inline bit-shift/mask property implementations with compile-time constants. There is no runtime reflection, no boxing, and no allocation. See BITFIELDS.md for the full model.
Launch the interactive web demo -- explore [BitFields], PE headers, network packets, CPU registers, and RFC diagrams directly in your browser. No install required.
Prefer video? Watch a walkthrough of the demo app.
| RFC bit-field diagram | PE header viewer | Composable floating-point lab |
|---|---|---|
![]() |
![]() |
![]() |
<PackageReference Include="Stardust.Utilities" />That's it. NuGet restores the latest stable version; the badge above shows what that is today. To pin a specific version add Version="x.y.z" -- useful for reproducible builds, but most projects don't need it.
| Feature | What it does | Deep dive |
|---|---|---|
| BitFields value types | Generate zero-cost bit-packed structs with operators, parsing, JSON, and span I/O | BITFIELDS.md |
| BitFields zero-copy views | Read/write bits directly on a Memory<byte> buffer -- no copies |
BITFIELDS.md |
| Result<T, TError> / Result<TError> | Explicit railway-oriented error handling without exceptions | RESULT.md |
| Option<T> | Explicit optional values without null, zero-cost on the hot path |
OPTION.md |
| Endian types (16 through 256 bits) | Type-safe big- and little-endian integers that compile to a single BSWAP |
ENDIAN.md |
| UInt256 / Int256 | Fixed-width 256-bit arithmetic with native CPU instructions (BMI2, DivRem) | LARGE_INTEGERS.md |
| Hi / Lo / Saturating extensions | Upper/lower byte access and clamped arithmetic on every integer type | EXTENSIONS.md |
| RFC diagram generator | Render ASCII bit-field diagrams from any [BitFields] struct at runtime |
BITFIELDS.md -- RFC Diagram Generator |
| IEEE 754 / Decimal decomposers | Pre-built [BitFields] types for Half, float, double, decimal |
BITFIELDS.md -- Numeric Decomposition Types |
One attribute. Two struct kinds. Hardware-speed bit access with no boilerplate.
Annotate a partial struct for a self-contained value type, or a partial record struct for a zero-copy view over an external Memory<byte> buffer. Both use the same [BitField] / [BitFlag] property attributes and produce identical JSON and span I/O:
using Stardust.Utilities;
// Value type: backed by a storage primitive (byte, uint, ulong, UInt128, UInt256, ...)
[BitFields(StorageType.Byte)]
public partial struct StatusRegister
{
[BitFlag(0)] public partial bool Ready { get; set; }
[BitFlag(1)] public partial bool Error { get; set; }
[BitFlag(7)] public partial bool Busy { get; set; }
[BitField(2, End = 4)] public partial byte Mode { get; set; } // 3 bits
[BitField(5, End = 6)] public partial byte Priority { get; set; } // 2 bits
}
StatusRegister reg = 0x42;
reg.Ready = true;
reg.Mode = 5; // bits 2-4
byte raw = reg; // implicit conversion to storage type
var next = reg.WithPriority(2); // fluent, immutable-style update
string j = JsonSerializer.Serialize(reg); // "0x4D"Proven zero-overhead (500M iterations, .NET 10 -- full methodology in BITFIELDS.md):
| Operation | Raw bit ops | Generated property | Difference |
|---|---|---|---|
| Boolean GET | 271 ms | 263 ms | ~0% (noise) |
| Boolean SET | 506 ms | 494 ms | ~0% (noise) |
| Field GET (shift+mask) | 124 ms | 123 ms | ~0% (noise) |
Choosing between the two shapes:
partial struct (value type) |
partial record struct (view) |
|
|---|---|---|
| Backing | Private value field | External Memory<byte> |
| Copy cost | Copies all data | Copies a 24-byte view header |
| Max size | ~16 KB (or up to 16,384 bits via [BitFields(N)]) |
Unlimited |
| Operators | Full arithmetic, bitwise, comparison | None (it is a view, not a value) |
| Typical use | Registers, opcodes, flags, network fields | Network packets, file headers, DMA buffers |
Key benefits:
- Identical-to-hand-coded performance, confirmed by statistical benchmarking.
- Full modern .NET surface generated per type:
IParsable<T>,ISpanParsable<T>,ISpanFormattable,IComparable<T>,IEquatable<T>,System.Text.Jsonconverter, span constructors,ReadFrom/WriteTo/TryWriteTo,ToByteArray. - Storage types from
byteup toUInt256, plus auto-sizing, plus arbitrary-width[BitFields(N)]from 1 to 16,384 bits. MustBe/UndefinedBitsMustBeenforce reserved-bit invariants at every entry point with under 1 ns construction overhead and zero getter overhead.- Composition: value types nest in views, views nest in views,
UInt256nests in anything -- each nested type carries its own byte/bit order.
See BITFIELDS.md for the complete attribute reference, storage types, composition rules, JSON/span I/O, compiler diagnostics, and real-world protocol examples.
Railway-oriented error handling without exceptions. Inspired by Rust's Result<T, E>.
// Enable clean Ok() / Err() syntax via global using
global using static Stardust.Utilities.Result<int, string>;
Result<int, string> Divide(int a, int b) =>
b == 0 ? Err("Division by zero") : Ok(a / b);
var message = Divide(10, 2)
.Map(x => x * 2) // transform the value
.AndThen(x => Divide(x, 4)) // chain another Result
.Inspect(x => Console.WriteLine(x)) // side effect on success
.MapOrElse(
onOk: v => $"Answer: {v}",
onErr: e => $"Failed: {e}");Key benefits:
- Explicit success/failure in the type signature -- impossible to forget error handling.
- Full monadic surface:
Map,MapErr,AndThen,OrElse,Inspect,InspectErr,Flatten,Transpose,MapOr,MapOrElse. - Interop with
Option<T>viaToOption/OkOr/Transpose. - Void form
Result<TError>for save/send/delete operations that succeed or fail but return nothing. - Works with
async/awaitend-to-end.
See RESULT.md for the full API, custom error types, real-world examples, and async patterns.
Explicit optional values without null. Inspired by Rust's Option<T>.
global using static Stardust.Utilities.Option;
Option<int> ParsePositive(string s) =>
int.TryParse(s, out var n) && n > 0 ? Some(n) : None;
int port = ParsePositive(input).UnwrapOr(8080);
var email = GetUserById(id)
.AndThen(user => user.Email)
.Filter(e => e.Contains('@'));Zero-cost on the hot path (100M iterations, .NET 10):
| Operation | Option<T> |
T? |
Difference |
|---|---|---|---|
| Create Some | 35 ms | 34 ms | ~0% (noise) |
IsSome check |
46 ms | 49 ms | ~0% (noise) |
UnwrapOr (??) |
122 ms | 127 ms | ~0% (noise) |
Key benefits:
- State checks, value extraction, and defaults are statistically identical to hand-written
T?code. - Delegate-based transforms (
Map,AndThen,Filter) add 1-2 ns -- fine outside tight inner loops. - Bidirectional interop with
Result<T, TError>. Noneas a static singleton means no allocation on theNonebranch.
See OPTION.md for the full API, performance analysis, interop patterns, and async support.
Type-safe endian-aware integers at native speed. 16 types covering 16 through 256 bits, big-endian and little-endian, signed and unsigned.
using Stardust.Utilities;
// Big-endian wire values with native arithmetic
UInt32Be seq = 0x12345678; // stored as 12 34 56 78
UInt32Be next = seq + 1; // arithmetic works natively
Span<byte> buf = stackalloc byte[4];
next.WriteTo(buf); // zero-allocation serialization
// Read back from a packet
var incoming = new UInt32Be(receivedBytes);
uint native = incoming; // implicit conversionNo performance penalty (BenchmarkDotNet, .NET 10):
| Width | Le vs. native |
Be vs. hand-coded BSWAP |
|---|---|---|
| 16-bit | 1.0x | 1.0x (single register rotate) |
| 32-bit | 1.0x | 1.0x (single BSWAP) |
| 64-bit | 1.0x | 1.0x (single BSWAP) |
| 128-bit | 1.0x | 1.0x (two BSWAPs + swap halves) |
| 256-bit | 1.0x | 7-19x faster than BigInteger-backed alternatives |
Key benefits:
[StructLayout(LayoutKind.Explicit)]guarantees byte ordering in memory regardless of host.- Full operator set: arithmetic, bitwise, shift, comparison, equality.
- Modern .NET interfaces generated:
IParsable<T>,ISpanParsable<T>,ISpanFormattable. - Zero-allocation
ReadOnlySpan<byte>constructors plusWriteTo/TryWriteTo/ReadFrom, all with an optionalint offsetand anisBigEndianoverride for reading or writing the opposite byte order. - Parallel
byte[]overloads on every read/write API -- no.AsSpan()required to reach the offset / byte-order overloads. - PropertyGrid
TypeConverterfor every type. - Per-field endian override inside
[BitFields]views -- mix big- and little-endian fields in the same buffer.
See ENDIAN.md for the full type matrix, benchmark tables, migration guide from manual ReverseEndianness, and real-world examples.
Fixed-width 256-bit signed and unsigned integers that are competitive with the leading managed alternatives on every operation that matters.
UInt256 and Int256 fill the gap between the BCL's UInt128 / Int128 and the heap-allocated, arbitrary-precision BigInteger. They are the right tool for cryptographic digests, Ethereum / EVM-style values, large accumulators, GUID-scale identifiers, and any fixed-32-byte quantity that needs real arithmetic -- not just byte manipulation.
using Stardust.Utilities;
UInt256 a = 42;
UInt256 b = UInt256.Parse("115792089237316195423570985008687907853269984665640564039457584007913129639935");
UInt256 hash = (a * 31 + b) ^ UInt256.MaxValue;
// Zero-allocation wire I/O
ReadOnlySpan<byte> wire = ReceivePacket(); // 32 bytes, network order
UInt256Be be = new(wire);
UInt256 value = be; // implicit conversion to host-nativeCompetitive with the leading managed 256-bit libraries — table below shows UInt256 (the more commonly used of the two; the signed Int256 numbers are similar shape and are tabulated in LARGE_INTEGERS.md). Measured on .NET 10 x64, median of three full runs; 1.0x is the Stardust baseline; lower = faster:
| Operation | Stardust.Utilities.UInt256 |
Nethermind.Numerics.Int256 1.5.0 |
MissingValues.UInt256 2.2.1 |
BigInteger (BCL) |
|---|---|---|---|---|
| Add | 1.0x | 1.8x | 1.0x | 44x |
| Sub | 1.0x | 1.6x | 1.0x | 46x |
| Mul | 1.0x | 1.7x | 1.2x | 24x |
| Div | 1.0x | 1.1x | 2.0x | 7.4x |
| Mod | 1.0x | 1.2x | 2.2x | 7.0x |
| ToString | 1.0x | 1.5x | 1.0x | 2.0x |
| Parse | 1.0x | 4.1x | 2.2x | 4.4x |
Ratios rounded to 2 significant digits (the third digit is in the run-to-run noise band). Stardust substantially beats MissingValues on Div, Mod, and Parse (2.0-2.2x); a small win on Mul (~1.2x); tied within noise on Add, Sub, and ToString. Stardust beats Nethermind on every operation. BigInteger allocates 2-3 MB per 10,000-iteration run and triggers GC; the 7-46x ratios reflect that cost, not raw throughput. All three fixed-width libraries are high-quality implementations. Library versions, .NET runtime versions, and hardware all move the numbers -- re-run BenchmarkSuite1/Int256LibraryComparisonBenchmarks.cs against current packages on your target hardware if the decision matters. See LARGE_INTEGERS.md -- Performance for the full methodology, the parallel Int256 table, and noise-band analysis.
Key benefits:
- Zero heap allocations on the hot path (
readonly structbacked by fourulongvalues). - Native CPU instructions: multiply via BMI2
MULX, divide viaX86Base.X64.DivRem, with hand-rolled carry-chain fallbacks on ARM64 and non-x64 platforms. - Full BCL
UInt128/Int128API parity.INumber<T>,IBinaryInteger<T>,IBinaryNumber<T>,IMinMaxValue<T>,IUnsignedNumber<T>/ISignedNumber<T>, plusIUtf8SpanFormattable/IUtf8SpanParsable<T>on .NET 8+. Every member a caller expects fromUInt128/Int128is present:Abs,Clamp,CopySign,DivRem,Max,Min,MaxMagnitude,MinMagnitude,Sign,LeadingZeroCount,TrailingZeroCount,PopCount,Log2,RotateLeft,RotateRight,Read/Write/TryRead/TryWriteBigEndian/LittleEndian, checked operators (checked + - * / ++ --and unary-),CreateChecked/CreateSaturating/CreateTruncatingfor every BCL numeric type, and explicit conversions to/fromfloat,double,decimal, andchar. - Wire-format safety via
UInt256Be/UInt256Lewith zero conversion cost on LE hardware. - First-class
[BitFields]citizen:[BitFields(typeof(UInt256))]gets a 4-ulong backing store with full operator and JSON support. - PropertyGrid
TypeConverterfor both raw (UInt256/Int256) and wire-format (UInt256Be/Le,Int256Be/Le) types. - Fuzz-tested on every build:
Int256NativeArithmeticTestscross-validates every operation againstBigIntegeron randomized inputs.
See LARGE_INTEGERS.md for the full API, benchmark methodology, and guidance on choosing between UInt256, UInt128, and BigInteger.
Upper/lower byte access and clamped arithmetic on every integer type, native or endian.
using Stardust.Utilities;
ushort word = 0x1234;
byte hi = word.Hi(); // 0x12
byte lo = word.Lo(); // 0x34
word = word.SetHi(0xFF); // 0xFF34
// Saturating arithmetic: clamps instead of overflowing
int r1 = int.MaxValue.SaturatingAdd(1); // int.MaxValue
uint r2 = 10u.SaturatingSub(20u); // 0
UInt256 r3 = UInt256.MaxValue.SaturatingAdd(new UInt256(1UL)); // UInt256.MaxValue
Int256 r4 = Int256.MinValue.SaturatingSub(new Int256(1L)); // Int256.MinValueKey benefits:
- Works uniformly on native (
ushort...Int256), big-endian (UInt16Be...Int256Be), and little-endian types. Hi()/Lo()return the upper/lower half as the appropriate half-width type.SetHi()/SetLo()produce a new value -- no mutation, no allocation.SaturatingAdd/SaturatingSubclamp to the type's representable range.
See EXTENSIONS.md for the full method list and performance notes.
Render RFC 2360-style ASCII bit-field diagrams from any [BitFields] struct at runtime.
var diagram = new BitFieldDiagram(typeof(IPv4HeaderView));
string output = diagram.RenderToString().Value;
// Render multiple structs in a single diagram with consistent scale
var combined = new BitFieldDiagram(
[typeof(M68020DataRegisters), typeof(M68020SR)],
description: "68020 Registers");
Console.WriteLine(combined.RenderToString().Value);Cells auto-size to fit field names, byte offsets label each row, and undefined bits are clearly marked. See BITFIELDS.md -- RFC Diagram Generator for configuration options and examples.
Four pre-built [BitFields] types that decompose .NET numeric types into their constituent fields. Just using Stardust.Utilities; and start using them -- no struct definitions required.
| Type | Storage | Use case |
|---|---|---|
IEEE754Half |
Half (16-bit) |
Half-precision analysis |
IEEE754Single |
float (32-bit) |
Single-precision analysis |
IEEE754Double |
double (64-bit) |
Double-precision analysis |
DecimalBitFields |
decimal (128-bit) |
Decimal inspection |
IEEE754Double pi = Math.PI;
pi.Sign; // false
pi.BiasedExponent; // 1024 (raw stored value, includes +1023 bias)
pi.Exponent; // 1 (true mathematical power: 2^1, since 2 <= pi < 4)
pi.Mantissa; // 0x921FB54442D18
pi.IsNormal; // true
var rebuilt = IEEE754Double.Zero
.WithExponent(pi.Exponent!.Value)
.WithMantissa(pi.Mantissa);
double result = rebuilt; // == Math.PIAll four types include implicit conversions to and from their storage type, full operator support, classification properties (IsNormal, IsNaN, IsInfinity, IsDenormalized, IsZero), both the raw BiasedExponent field and a computed Exponent property that removes the bias, and a WithExponent(int) fluent method that sets the exponent from its true mathematical value.
See Numeric Decomposition Types in BITFIELDS.md for full details, bit-layout diagrams, constants, and classification reference.
| Dimension | Supported |
|---|---|
| Target frameworks | net7.0, net8.0, net9.0, net10.0 |
| Process architectures | x86, x64, ARM64 (nint/nuint diagnostics steer you around 32-bit pitfalls) |
| Host endianness | Little-endian (x86/x64/ARM) native; big-endian fully supported and CI-tested via QEMU |
| Runtime deps | None (source generator ships as an analyzer; no extra DLL in your output) |
| Trimming / AOT | Value types and generated code are trim-safe; no reflection on the hot path |
| Compiler requirement | C# 13+ (VS 2022 17.0+ for incremental generator support) |
Three most-frequent issues and their fixes. For the full diagnostic reference (every SD00xx error and warning, browser/WASM notes, how to view generated code) see TROUBLESHOOTING.md.
CS9248: partial property must have an implementation part-- add thepartialkeyword to every[BitField]/[BitFlag]property. If you also seeSD0004, the generator is pointing directly at the missing keyword.- Generated code didn't update -- make sure the type is
partial structorpartial record struct(notclass), then clean and rebuild. Any classes containing thispartialdefinition (including parent classes all the way up) must also bepartial. - IntelliSense missing for generated members -- build the project at least once, then close and reopen the solution if needed.
Every release gets a dated entry in CHANGELOG.md covering added features, behavior changes, deprecations, and backwards compatibility notes. On nuget.org the same information appears on the package's Release Notes tab.
MIT. See LICENSE.
Contributions are welcome. Please read the guidelines before submitting issues or pull requests.
To report a security vulnerability, please use GitHub's private vulnerability reporting feature. Do not report security issues through public GitHub issues. See SECURITY.md for details.
Stardust.Utilities does not collect, transmit, or store any personal data, telemetry, or usage information. See PRIVACY.md for details.


