Releases: ibrahimkteish/SwiftRandomKit
Release list
2.1.0
No library changes — SPM consumers are unaffected.
The test suite (37 suites, 179 tests) is migrated from XCTest to Swift Testing: @Test functions with #expect/#require, value-type suites, per-test seeded RNGs, and parallel execution by default. Availability-gated suites (Zip) carry @available per test function, specific-error expectations use #expect(throws: SomeError.case), and the Sudoku validity helper threads sourceLocation so failures point at the calling test.
Validated on Swift 6.0.2 (macOS + Linux), the current Xcode toolchain, and the latest Swift Linux image.
2.0.0
A major release: critical correctness fixes, a rework of the library's concurrency
story, removal of APIs that didn't make sense, and a batch of new generators. If you are
coming from 1.x, build against 1.3.0 first — it deprecates everything 2.0 removes, with
messages naming the replacements.
Concurrency: RandomGenerator no longer requires Sendable
Generators are ordinary values, confined to the isolation domain where they are built
and run:
- The protocol requires neither
SendablenorElement: Sendable. Conformers may hold
non-Sendable state and produce non-Sendable values. - Transform closures (
map,flatMap,filter,retry,tryMap, ...) are plain
closures — they can capture anything the surrounding context can. - Leaf generators (
IntGenerator,FloatGenerator,BoolGenerator,Always,
Character,UnicodeScalar, the seeded RNGs, and all ready-made generators) declare
Sendableexplicitly, and closure-free combinators (Array,Collect,Concat,
Dictionary,Element,Frequency,OneOf,OrNil,Print,Shuffled,Tuple,
Zip, ...) propagate it conditionally — so leaf-only compositions remain shareable. RemoveDuplicatesdrops its lock and@unchecked Sendable; the compiler now enforces
its single-domain confinement.AttemptBounded.FallbackStrategyis no longerSendable(it carries a closure).
Migration: pipelines containing closures are no longer Sendable. Move one into a
Task and region isolation checks the transfer; to use a pipeline from several tasks,
build one per task.
Fixed
AnyRandomGeneratornever advanced the caller's RNG — erased generators (including
the character presets) replayed the same value forever under a seeded RNG. Seeded
sequences involving erased generators change with this fix.Zip(...).map { a, b, c in }compiles again on Swift 6.3 via a pack-argument overload.compactMap/retryMapcould crash on a force-unwrap when the attempt budget was
exhausted; they now produceOptional(nil on exhaustion).retryThrowingproduces
Result(the last failure on exhaustion), runs its transform once per candidate, and
no longer backstops withfatalError.uiColor(alpha:)/swiftUIColor(alpha:)silently ignored their alpha parameter; the
parameter is removed and the generator'sinit(alpha:)visibly governs.UnicodeScalar/Charactergeneration over ranges spanning the surrogate gap
(U+D800–DFFF) no longer biases toward the lower bound or traps; the gap is skipped
uniformly.Frequencyno longer materializes a sum-of-all-weights array on every run (cumulative
bounds + one draw), and fails fast with clear preconditions on empty or all-zero
distributions.AttemptBoundedcounts the initial run towardmaxAttempts(previously
maxAttempts: 3ran the upstream up to 4 times);maxAttemptsmust be ≥ 1.IntGenerator(in: 0..<0)traps with a clear message instead of a confusing
ClosedRangeprecondition.- The package declared iOS 13 but could not compile for iOS at all (
Zip's parameter
packs require the iOS 17 runtime). Platforms are now honestly declared —
iOS 13 / macOS 10.15 / tvOS 13 / watchOS 6 — with onlyZipand its operators gated
behind@available(macOS 14, iOS 17, tvOS 17, watchOS 10). IPAddressGeneratorimports Foundation explicitly.
Added
RandomGenerators.Bernoulli/.bool(probability:)— biased coin.orNil(probability:)— produce nil with a given probability.RandomGenerators.Normal(Box–Muller) andRandomGenerators.Exponential
distributions, with.normal(mean:standardDeviation:)/.exponential(rate:)sugar.RandomGenerators.oneOf(...)— uniform pick across 2–4 generators of different
concrete types sharing an element type.RandomGenerators.string(of:count:)andcharacterGen.string(count:).- Seeded RNGs:
Xoshiro256(xoshiro256++),SplitMix64,PCG(independent streams via
sequence:). Dice(sides:)withd4/d6/d8/d10/d12/d20/d100presets.- Dot-syntax statics:
.int(in:),.float(in:),.bool. RandomGenerators.sudoku(difficulty:)convenience.- DocC catalogs for both modules and the swift-docc-plugin.
- A runnable example target exercising the whole API.
Changed (breaking)
BoolRandomGeneratoris renamedBoolGenerator(deprecated typealias retained).compactMap/retryMapproduceOutput?;retryThrowingproduces
Result<Output, Error>.Frequencyis constructed viaRandomGenerators.frequency(_:); the receiver-ignoring
instance method is removed.UnicodeScalarandCharacterare standalone generators constructed from a range;
the combinator forms (whose upstream was ignored) are removed.
Removed
ZipArrayGenerator,zipAll(),zipGenerators(...)— exact duplicates ofCollect;
use[generators].collect().gen.always(_:),gen.colorGenerator(alpha:)— receiver-ignoring factories; construct
Always(_:)/ColorGenerator(alpha:)directly.CreditCardGenerator.Generated— useElement.
1.3.0
The final planned release of the 1.x line. It backports the features and critical fixes
from the upcoming 2.0 and deprecates every API that 2.0 removes, so migrating is mostly
a matter of following compiler warnings.
Fixed
AnyRandomGeneratornever advanced the caller's RNG. Erased generators — including
the built-innumber,uppercaseLetter,lowercaseLetterandcharacter(in:)
presets — replayed the same value forever under a seeded RNG. Seeded sequences that
involve erased generators will change with this fix; the first draw is unaffected.Zip(...).map { a, b, c in }failed to compile on Swift 6.3 (pack-expansion tuples are
no longer destructured into multi-parameter closures). Amapoverload onZipthat
receives the values as separate arguments restores the spelling, and CI now also builds
with the current Xcode toolchain and the latest Swift Linux image.IPAddressGeneratorimports Foundation explicitly (required under
MemberImportVisibility).Shuffledno longer requiresElement.Element: Equatable; shuffling never compares
elements.
Added
RandomGenerators.Bernoulli/.bool(probability:)— biased coin.orNil(probability:)— produce nil with a given probability.RandomGenerators.Normal(Box–Muller) andRandomGenerators.Exponentialdistribution
generators, with.normal(mean:standardDeviation:)/.exponential(rate:)sugar.RandomGenerators.oneOf(...)— uniform pick across 2–4 generators of different
concrete types sharing an element type.RandomGenerators.string(of:count:)andcharacterGen.string(count:)— build strings
directly from a character generator.- Seeded RNGs:
Xoshiro256(xoshiro256++),SplitMix64, andPCG(with independent
streams viasequence:).LCRNGdocuments its statistical weakness and points
simulations at these. RandomGenerators.frequency(_:)static factory (the 2.0 spelling).BoolGeneratortypealias (the 2.0 name forBoolRandomGenerator).
Deprecated (removed in 2.0)
ZipArrayGenerator,zipAll(),zipGenerators(...)→ use[generators].collect().gen.always(_:)→ constructAlways(_:)directly (the receiver was ignored).gen.colorGenerator(alpha:)→ constructColorGenerator(alpha:)directly.gen.frequency(_:)→RandomGenerators.frequency(_:)(the receiver was never part of
the distribution).gen.character(in:)/gen.unicodeScalar(in:)→RandomGenerators.character(in:)
(the upstream generator was ignored).uiColor(alpha:using:)/swiftUIColor(alpha:using:)→uiColor(using:)/
swiftUIColor(using:)(the alpha parameter was silently ignored; set alpha at
initialization).CreditCardGenerator.Generated→Element.
1.2.0
1.1.0
What's Changed
- Make RandomGenerator Sendable by @ibrahimkteish in #11
- v1.1.0 by @ibrahimkteish in #12
Full Changelog: 1.0.0...1.1.0