Random Port Generator — Swift source
Generate one or many random TCP/UDP port numbers across registered, ephemeral, or the full range - optionally unique. Runs entirely in your browser with crypto-grade randomness.
This is the Swift implementation — the same logic the interactive tool runs, in a shareable, citable form.
// random-port-generator — Swift port: random/dynamic port picker.
//
// Display port of the CosmoDev Random Port Generator tool — same contract as
// cli/random-port-generator/random-port-generator.go (the live Go twin) and
// src/lib/random-port.ts (the canonical TypeScript implementation). An
// injectable rng makes generation deterministic (the TS test surface);
// invalid custom ranges throw a PortError, mirroring the TS throw. The
// default rng is Double.random(in:) — backed by SystemRandomNumberGenerator,
// a CSPRNG standing in for the TS crypto.getRandomValues default.
enum PortRange: String {
case any, registered, ephemeral, custom
}
enum PortError: Error {
/// assertRange() in the TS lib — the TS Error becomes a thrown error.
case invalidRange(Int, Int)
}
/// PortOptions in the TS lib (count/unique cover randomPorts).
struct PortOptions {
var range: PortRange = .registered // the TS default (registered ports)
var min: Int? // custom-range lower bound
var max: Int? // custom-range upper bound
var count: Int = 1
var unique: Bool = false
var rng: (() -> Double)? // injectable random in [0, 1)
}
let ranges: [PortRange: (Int, Int)] = [
.any: (1, 65_535),
.registered: (1024, 49_151),
.ephemeral: (49_152, 65_535),
]
/// defaultRng() in the TS lib: a CSPRNG draw in [0, 1).
func defaultRng() -> Double {
Double.random(in: 0..<1) // SystemRandomNumberGenerator (CSPRNG)
}
/// resolveRange() in the TS lib.
func resolveRange(_ opts: PortOptions) -> (lo: Int, hi: Int) {
if opts.range == .custom { return (opts.min ?? 1, opts.max ?? 65_535) }
let (lo, hi) = ranges[opts.range]!
return (lo, hi)
}
func assertRange(_ lo: Int, _ hi: Int) throws {
if lo < 0 || lo > 65_535 || hi > 65_535 || lo > hi {
throw PortError.invalidRange(lo, hi)
}
}
/// randomPort() in the TS lib — Port() in the Go twin.
func randomPort(_ opts: PortOptions = PortOptions()) throws -> Int {
let rng = opts.rng ?? defaultRng
let r = resolveRange(opts)
try assertRange(r.lo, r.hi)
return r.lo + Int((rng() * Double(r.hi - r.lo + 1)).rounded(.down))
}
/// randomPorts() in the TS lib — Ports() in the Go twin.
func randomPorts(_ opts: PortOptions = PortOptions()) throws -> [Int] {
let count = max(1, opts.count)
let r = resolveRange(opts)
try assertRange(r.lo, r.hi)
if !opts.unique { return try (0..<count).map { _ in try randomPort(opts) } }
// Fisher-Yates partial shuffle over the range to pick n unique ports.
let capacity = r.hi - r.lo + 1
let n = min(count, capacity)
let rng = opts.rng ?? defaultRng
var pool = Array(r.lo...r.hi)
for i in 0..<n {
let j = i + Int((rng() * Double(capacity - i)).rounded(.down))
pool.swapAt(i, j)
}
return Array(pool.prefix(n))
}
// Vectors from src/lib/random-port.test.ts — a fixed rng pins every draw.
let zero: () -> Double = { 0.0 }
print("registered+0 = \(try randomPort(PortOptions(rng: zero)))") // 1024
print("any+0 = \(try randomPort(PortOptions(range: .any, rng: zero)))") // 1
print("ephemeral+0 = \(try randomPort(PortOptions(range: .ephemeral, rng: zero)))") // 49152
print("custom 8000-8000 @0.9 = \(try randomPort(PortOptions(range: .custom, min: 8000, max: 8000, rng: { 0.9 })))") // 8000
print("resolveRange(custom defaults) = \(resolveRange(PortOptions(range: .custom)))") // (lo: 1, hi: 65535)
print("count=5 @0 = \(try randomPorts(PortOptions(count: 5, rng: zero)))") // [1024 x5]
print("unique 3 in 1..10 @0.5 = \(try randomPorts(PortOptions(range: .custom, min: 1, max: 10, count: 3, unique: true, rng: { 0.5 })))") // [6, 1, 7]
print("unique 5 in 1..3 @0.5 = \(try randomPorts(PortOptions(range: .custom, min: 1, max: 3, count: 5, unique: true, rng: { 0.5 })))") // capped at capacity 3
let p = try randomPort() // default CSPRNG, registered range
print("default rng registered = \(p) (in 1024..49151)")
do {
_ = try randomPort(PortOptions(range: .custom, min: 70000)) // min above 65535
_ = try randomPort(PortOptions(range: .custom, min: 100, max: 50)) // min above max
} catch {
print("invalid: \(error)")
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →