bhylu.com

Advertisements

Swift Workshop Booking Project

Combine checked state changes and explicit refused requests in a small value model.

How it works

A booking counter has one valid capacity and a current booked count. A request succeeds only if it is positive and fits; a failure must preserve the earlier state. This model is intentionally in-memory and single-threaded. The Actor lesson owns the separate concurrent variant.

Run this Swift example

Install the toolchain for your platform from Swift.org, then check swift --version. The reviewed portable baseline is Swift 6.4.2 in Swift 6 mode on Ubuntu 26.04 x86_64 through the PC’s existing WSL installation. These are real Linux executions, not claims of Windows-native or Apple-platform test results. Windows Swift has separate C++/SDK prerequisites in its official setup guide.

Save the complete source as booking-project.swift in a new learning folder. On Linux/macOS compile with swiftc -swift-version 6 -parse-as-library booking-project.swift -o lesson, then run ./lesson. On a configured Windows toolchain use an output such as lesson.exe and run .\lesson.exe. The parse-as-library option supports the explicit @main entry point used by these sources. Compile each ordinary lesson separately.

Bhylu has no Swift browser runner. The JavaScript/Python editors do not run these sources; Apache, PHP and MySQL are not required. Downloads are source text, never executable teaching endpoints.

Download the complete booking-project.swift · Download all source files with hash checks

For the optional collection, save download-examples.mjs in a new folder and run node download-examples.mjs. A local preview uses node download-examples.mjs http://127.0.0.1:8000/examples/swift/. It refuses an existing bhylu-swift-examples folder and installs or executes no Swift automatically. Apple-only files remain separate Xcode learning examples, not a portable Swift package target.

Example

booking-project.swift

struct BookingCounter {
    let capacity: Int
    private(set) var booked = 0
    var free: Int { capacity - booked }
    init?(capacity: Int) { guard capacity >= 0 else { return nil }; self.capacity = capacity }
    mutating func book(_ amount: Int) -> Bool {
        guard amount > 0, amount <= free else { return false }
        booked += amount
        return true
    }
}

@main
struct Lesson {
    static func main() {
        var counter = BookingCounter(capacity: 5)!
        for amount in [2, 0, 4, 3] { print(counter.book(amount), counter.booked) }
        print("free", counter.free)
    }
}

Expected result

true 2
false 2
false 2
true 5
free 0

The known fixed capacity is force-unwrapped only after using a literal fixture whose validity is visible; ordinary external input should use optional binding. The sequence includes two refused requests between successes. The package tests additional ranges and maximum-Int boundaries.

A real Swift package

The source collection includes Package.swift, a WorkshopCore library, a WorkshopCLI executable and actual XCTest files. Inside bhylu-swift-examples run node setup-lab.mjs. It checks source hashes before creating a new pottery-lab folder and refuses existing output. Change to pottery-lab and run swift test, then swift run WorkshopCLI. No third-party package dependency is needed. A properly installed platform toolchain supplies its own runtime/SDK; the private review setup is not shipped to readers.

Package.swift

Download Package.swift

Package.swift

// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "PotteryLab",
    products: [
        .library(name: "WorkshopCore", targets: ["WorkshopCore"]),
        .executable(name: "WorkshopCLI", targets: ["WorkshopCLI"])
    ],
    targets: [
        .target(name: "WorkshopCore"),
        .executableTarget(name: "WorkshopCLI", dependencies: ["WorkshopCore"]),
        .testTarget(name: "WorkshopCoreTests", dependencies: ["WorkshopCore"])
    ]
)

WorkshopCore.swift

Download WorkshopCore.swift

WorkshopCore.swift

import Foundation

public struct BookingCounter: Sendable {
    public let capacity: Int
    public private(set) var booked = 0
    public var free: Int { capacity - booked }
    public init?(capacity: Int) {
        guard capacity >= 0 else { return nil }
        self.capacity = capacity
    }
    public mutating func book(_ amount: Int) -> Bool {
        guard amount > 0, amount <= free else { return false }
        booked += amount
        return true
    }
}

public struct Booking: Sendable {
    public let id: String
    public let room: String
    public let minutes: Int
    public init(id: String, room: String, minutes: Int) {
        self.id = id; self.room = room; self.minutes = minutes
    }
}
public enum ReportError: Error { case invalid }

public func roomTotals(_ rows: [Booking]) throws -> [String: Int] {
    guard rows.count <= 1000 else { throw ReportError.invalid }
    var seen: Set<String> = []
    var totals: [String: Int] = [:]
    for row in rows {
        guard !row.id.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
              !row.room.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
              (1...240).contains(row.minutes), seen.insert(row.id).inserted else { throw ReportError.invalid }
        totals[row.room, default: 0] += row.minutes
    }
    return totals
}

WorkshopCLI.swift

Download WorkshopCLI.swift

WorkshopCLI.swift

import WorkshopCore

@main struct WorkshopCLI {
    static func main() throws {
        guard var desk = BookingCounter(capacity: 5) else { fatalError("Invalid fixture") }
        for amount in [2, 0, 4, 3] { print(desk.book(amount), desk.booked) }
        print("free", desk.free)
        let totals = try roomTotals([
            Booking(id: "W-21", room: "Cedar", minutes: 20),
            Booking(id: "W-22", room: "Ash", minutes: 35),
            Booking(id: "W-23", room: "Cedar", minutes: 25)
        ])
        for key in totals.keys.sorted() { print(key, totals[key] ?? 0) }
    }
}

WorkshopCoreTests.swift

Download WorkshopCoreTests.swift

WorkshopCoreTests.swift

import XCTest
@testable import WorkshopCore

final class WorkshopCoreTests: XCTestCase {
    func testCapacityRefusalsAndIndependentSequence() {
        XCTAssertNil(BookingCounter(capacity: -1))
        for capacity in 0...20 {
            guard var desk = BookingCounter(capacity: capacity) else { return XCTFail("Valid capacity refused") }
            var expected = 0
            for amount in [1, 2, 0, -1, 4, 1, 19, 1] {
                let accepted = amount > 0 && Int64(expected) + Int64(amount) <= Int64(capacity)
                if accepted { expected += amount }
                XCTAssertEqual(desk.book(amount), accepted)
                XCTAssertEqual(desk.booked, expected)
                XCTAssertEqual(desk.free, capacity - expected)
            }
        }
    }
    func testMaximumIntDoesNotOverflowOnRefusal() {
        guard var desk = BookingCounter(capacity: Int.max) else { return XCTFail("Maximum capacity refused") }
        XCTAssertTrue(desk.book(Int.max - 1))
        XCTAssertFalse(desk.book(2))
        XCTAssertEqual(desk.booked, Int.max - 1)
        XCTAssertTrue(desk.book(1))
        XCTAssertEqual(desk.free, 0)
        XCTAssertFalse(desk.book(1))
    }
    func testReportIndependentTotalsAndEmptyInput() throws {
        for size in 0...30 {
            let rows = (0..<size).map { Booking(id: String($0), room: $0 % 3 == 0 ? "Cedar" : "Ash", minutes: $0 + 1) }
            let actual = try roomTotals(rows)
            let cedar = (0..<size).filter { $0 % 3 == 0 }.reduce(0) { $0 + $1 + 1 }
            let ash = (0..<size).filter { $0 % 3 != 0 }.reduce(0) { $0 + $1 + 1 }
            XCTAssertEqual(actual["Cedar", default: 0], cedar)
            XCTAssertEqual(actual["Ash", default: 0], ash)
        }
    }
    func testReportRejectsInvalidWholeInput() {
        let cases: [[Booking]] = [
            [Booking(id: "", room: "Cedar", minutes: 1)],
            [Booking(id: "x", room: " ", minutes: 1)],
            [Booking(id: "x", room: "Cedar", minutes: 0)],
            [Booking(id: "x", room: "Cedar", minutes: 241)],
            [Booking(id: "x", room: "Cedar", minutes: 1), Booking(id: "x", room: "Ash", minutes: 2)],
            (0..<1001).map { Booking(id: String($0), room: "Cedar", minutes: 1) }
        ]
        for rows in cases { XCTAssertThrowsError(try roomTotals(rows)) }
    }
}

Primary references: The Swift Programming Language and Apple framework documentation. Use the selected platform’s current requirements. Fictional workshop examples do not establish production safety or deployment approval.

Advertisements