Table of Contents

Bodu.Core - Core concepts

This page is the vocabulary the rest of the documentation assumes. Read it once before the getting-started samples or the guides, and refer back whenever a term feels imprecise.

Part of the Core Foundations topic.

For the high-level shape of the library and the namespace map, start with the introduction. The collection vocabulary - fixed capacity, ring backing, eviction policies, navigation, sketches - lives on the Bodu.Collections concepts page, and the concurrency vocabulary on the Bodu.Collections.Concurrent concepts page.

WeekPattern

WeekPattern is an immutable readonly struct that represents a set of days within a seven-day week, packed into a 7-bit bitmask. It supports:

  • Composition - With(DayOfWeek) and Without(DayOfWeek) return new patterns; the bitwise operators |, &, ^, ~ compose set union, intersection, symmetric difference, and complement.
  • Parsing - WeekPattern.Parse("_MTWTF_") produces the weekday set; the text form is a seven-character mask of day initials in Sunday-first order (Monday-first is auto-detected, or forced with ParseExact(input, "M")), with _ for absent days, or seven 0/1 bits. Presets WeekPattern.Empty, WeekPattern.Weekdays, WeekPattern.Weekend, and WeekPattern.AllDays cover the common cases, and the regional working-week presets (MondayToFriday, MondayToSaturday, SundayToThursday, SaturdayToWednesday, …) mirror the members of WorkingDaysOfWeek.
  • Enumeration - implements IEnumerable<DayOfWeek>, yielding selected days in DayOfWeek order.

Because the receiver is a value type, every mutation returns a new instance. WorkingDaysOfWeek is the companion enum naming the common working-week patterns; conversion to and from WeekPattern is via the extension methods on WorkingDaysOfWeekExtensions.

Pooled buffer

A pooled buffer is a writer-style builder backed by ArrayPool<T> rather than new T[]. PooledBufferBuilder<T> rents an array on construction, grows it by re-renting when needed, exposes WrittenSpan for zero-copy reads, and returns the array to the pool on Dispose.

Ownership semantics:

  • The builder owns the rented array; callers must call Dispose (or use using) to return it.
  • WrittenSpan and WrittenMemory are valid only while the builder is alive. Copy out before disposal if the data must outlive the using block.
  • For reference-typed T, the live portion is cleared before the array is returned, preventing unintended object retention.
  • Reset discards the accumulated content and reuses the current rented buffer without a pool round-trip.

The builder implements IBufferWriter<T> and IMemoryOwner<T>, so it slots into standard Span<T> / Memory<T> pipelines.

Railway-oriented outcomes

The Bodu.Functional namespace models "this might not produce a value" as data rather than control flow. Three value types cover the three shapes of the problem:

  • Option<T> - a value that may be absent: Some(value) or None. Reach for it when absence is normal and carries no explanation (a cache miss, an optional setting).
  • Result / Result<T> - success or failure, where failure carries a ResultError (optional code, never-null message, optional captured exception). Reach for it when the caller needs to know why an operation failed without paying for a thrown exception.
  • Either<TLeft, TRight> - a symmetric disjoint union of two equally valid alternatives, with no success/failure bias.

The railway style chains these through combinators instead of if/throw ladders: Map transforms the value on the success track, Bind sequences a fallible step, Filter demotes a Some to None, and Match forces both tracks to be handled at the exit. Task-based companions (MapAsync / BindAsync / MatchAsync / TapAsync on OptionAsyncExtensions and ResultAsyncExtensions) keep the chain flowing through async steps.

Because all three are readonly structs, each defines its default contract - what an unassigned field means:

Type default means
Option<T> None - absence, safely.
Result<T> A failure carrying an empty error - never a phantom success.
Either<TLeft,TRight> An explicit uninitialized state - neither side is fabricated.

Natural ordering

Ordinal string comparison sorts file10 before file2 because '1' < '2' - correct for code, wrong for humans. Natural ordering compares embedded digit runs numerically while comparing the surrounding text as text, so file2 sorts before file10.

NaturalStringComparer implements this as a standard IComparer<string> with ordinal, case-insensitive, and culture-aware modes, so it drops into OrderBy, SortedSet<string>, Array.Sort, or any API that accepts a comparer. Its companions ComparableExtensions and ComparableHelper round out ordering ergonomics for any IComparable<T> - Min, Max, Clamp, and readable comparison predicates (IsGreaterThan, IsGreaterThanOrEqual). See the Natural string comparer guide.

Async coordination

The Bodu.Threading namespace provides the async-friendly peers of the BCL synchronization types: where lock, Monitor, and ManualResetEvent block a thread, these primitives return awaitables, so a waiting caller yields its thread back to the pool.

The common contract: waiting never blocks a thread, cancellation is honoured through CancellationToken parameters, and lock releases are scoped by IDisposable so a using guarantees the release path. See the Async coordination primitives guide.

ThrowHelper

ThrowHelper centralises the ArgumentException family for the entire Bodu suite - every Bodu library calls into it rather than rolling its own checks. The pattern is:

public static double Average(IReadOnlyList<int> values)
{
    ThrowHelper.ThrowIfNull(values);
    ThrowHelper.ThrowIfZero(values.Count);
    return values.Average();
}

The helpers are partitioned by concern across partial files: Null, Numeric, Comparison, Equality, Array, Collection, Span, Type, String, Ascii. Each helper accepts a [CallerArgumentExpression(nameof(value))] string? paramName = null parameter, so the call site does not need to repeat the argument name. Two parallel partial-class sets target the modern (.NET 8) and netstandard runtimes; the public surface is identical across both.

Centralising the guards means the exception messages, parameter-name capture, and [StackTraceHidden] behaviour stay consistent across every Bodu library - and ThrowHelper is the primary dependency the other Bodu packages take on Bodu.Core.

Random generator abstraction

Several extension helpers - shuffles, sampling, randomised access - and the Bodu.Collections catalogue depend on a pluggable random source rather than a hard-coded Random. The seam is IRandomGenerator, a one-method interface (int Next(int maxValue)).

Two implementations ship in Bodu.Core:

Implementation Use when
XorShiftRandom Tight inner loops, reproducible tests, or shuffle code where the BCL's Random is the measured bottleneck. Subclasses System.Random and implements IRandomGenerator.
SystemRandomAdapter An existing System.Random instance must be reused - for example a seeded Random shared across multiple helpers. Wraps the Random and forwards calls.

Neither implementation is cryptographically secure; both are deterministic given a seed. Callers that need cryptographic randomness should use <xref:System.Security.Cryptography.RandomNumberGenerator> directly. Helpers that accept an IRandomGenerator make the dependency explicit so tests can supply a deterministic generator without monkey-patching globals.

Calendar-shape extensions

The Bodu.Extensions namespace ships several enums that encode the shape of a calendar without implementing one - they parameterise the date arithmetic on DateTimeExtensions and DateOnlyExtensions without pulling in Bodu.Globalization.Calendar:

Type Encodes
CalendarQuarterDefinition The start month of Q1 - JanuaryToDecember, JulyToJune, AprilToMarch, April6ToApril5 (UK tax year), March25ToMarch24 (Lady Day), OctoberToSeptember, FebruaryToJanuary, plus Custom for externally defined rules. Drives FirstDateOfQuarter, LastDateOfQuarter, Quarter, FiscalYear.
WeekOrdinal The ordinal position of a weekday in a month - First, Second, Third, Fourth, Fifth, Last. Drives NthDateOfWeekInMonth and the recurrence-rule patterns.
FiscalWeekPattern The 4-4-5 / 4-5-4 / 5-4-4 split for retail-style 13-week fiscal quarters. Each quarter is always 13 weeks; the pattern only affects fiscal-period boundaries inside the quarter. The extra week in a 53-week fiscal year is always appended to the final period of Q4.
WorkingDaysOfWeek Named working-week presets - MondayToFriday, MondayToSaturday, SaturdayToThursday, SaturdayToWednesday, and others - plus Custom for caller-supplied WeekPattern schedules. Drives IsWeekday, IsWeekend, IsInWorkingWeek, NextWeekday.
IWeekendDefinitionProvider The injection seam for non-enumerable weekend rules - pass an implementation to override the built-in WorkingDaysOfWeek presets when an application needs hybrid, rotating, or domain-specific weekend logic.

These types are pure data carriers. The actual algorithms live on the extension classes (DateTimeExtensions.*, DateOnlyExtensions.*) so the same shapes can be passed to a DateTime, DateOnly, or any future date type without duplicating the enums.

Where to go next