# Extended Swift patterns

Longer examples behind the main skill. Deep Codable work still belongs to
`swift-codable`, and format styles beyond a custom style to `swift-formatstyle`.

## Contents

- [Codable](#codable)
- [Result builders](#result-builders)
- [Property wrappers](#property-wrappers)
- [Advanced Regex](#advanced-regex)
- [Custom FormatStyle](#custom-formatstyle)
- [Collection patterns](#collection-patterns)
- [guard: complex pattern matching](#guard-complex-pattern-matching)
- [Typed throws in protocols](#typed-throws-in-protocols)
- [String interpolation](#string-interpolation)
- [Never: advanced usage](#never-advanced-usage)

## Codable

### Enums with associated values

Encode a discriminator key next to the payload keys, and throw a data
corruption error for a discriminator you do not recognise.

```swift
enum Reward: Codable {
    case points(Int)
    case voucher(code: String, percent: Int)

    private enum CodingKeys: String, CodingKey { case kind, amount, code, percent }

    func encode(to encoder: Encoder) throws {
        var c = encoder.container(keyedBy: CodingKeys.self)
        switch self {
        case .points(let n):
            try c.encode("points", forKey: .kind)
            try c.encode(n, forKey: .amount)
        case .voucher(let code, let percent):
            try c.encode("voucher", forKey: .kind)
            try c.encode(code, forKey: .code)
            try c.encode(percent, forKey: .percent)
        }
    }

    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        let kind = try c.decode(String.self, forKey: .kind)
        switch kind {
        case "points":
            self = .points(try c.decode(Int.self, forKey: .amount))
        case "voucher":
            self = .voucher(code: try c.decode(String.self, forKey: .code),
                            percent: try c.decode(Int.self, forKey: .percent))
        default:
            throw DecodingError.dataCorruptedError(forKey: .kind, in: c,
                debugDescription: "Unrecognised reward kind \(kind)")
        }
    }
}
```

### Date strategies

Set `dateDecodingStrategy` on the `JSONDecoder`:

- `.iso8601` for standard ISO 8601 strings.
- `.secondsSince1970` for Unix timestamps.
- `.formatted(formatter)` with a `DateFormatter` whose locale is
  `en_US_POSIX`, so user settings cannot change parsing.
- `.custom` when the feed mixes formats:

```swift
import Foundation

let reader = JSONDecoder()
reader.dateDecodingStrategy = .custom { decoder in
    let box = try decoder.singleValueContainer()
    let raw = try box.decode(String.self)
    if let stamp = ISO8601DateFormatter().date(from: raw) { return stamp }
    let dayOnly = DateFormatter()
    dayOnly.locale = Locale(identifier: "en_US_POSIX")
    dayOnly.dateFormat = "yyyy-MM-dd"
    if let stamp = dayOnly.date(from: raw) { return stamp }
    throw DecodingError.dataCorruptedError(in: box,
        debugDescription: "Unreadable date \(raw)")
}
```

### Unkeyed containers

A JSON array whose positions carry meaning, such as `[51.5, -0.12, 35]`, maps
onto named fields by reading it in order:

```swift
struct Fix: Decodable {
    var lat: Double, lon: Double, altitude: Double
    private enum CodingKeys: String, CodingKey { case point }

    init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        var point = try c.nestedUnkeyedContainer(forKey: .point)
        lat = try point.decode(Double.self)
        lon = try point.decode(Double.self)
        altitude = try point.decode(Double.self)
    }
}
```

### Skipping bad elements

One malformed element should not fail the whole array. Decode each element
with `try?`; when it fails, decode a throwaway value so the container moves
past it.

```swift
struct Tolerant<Element: Decodable>: Decodable {
    var values: [Element] = []
    private struct Skip: Decodable {}

    init(from decoder: Decoder) throws {
        var list = try decoder.unkeyedContainer()
        while !list.isAtEnd {
            if let item = try? list.decode(Element.self) {
                values.append(item)
            } else {
                _ = try? list.decode(Skip.self)
            }
        }
    }
}
```

### Dynamic member lookup over loose JSON

For payloads with no fixed shape, a `@dynamicMemberLookup` wrapper gives
dot-syntax access over a dictionary, with typed helpers:

```swift
@dynamicMemberLookup
struct LooseJSON {
    private let fields: [String: Any]
    init(_ fields: [String: Any]) { self.fields = fields }

    subscript(dynamicMember key: String) -> LooseJSON? {
        (fields[key] as? [String: Any]).map(LooseJSON.init)
    }
    func text(_ key: String) -> String? { fields[key] as? String }
    func number(_ key: String) -> Double? { fields[key] as? Double }
}

let doc = LooseJSON(["owner": ["name": "Lena", "karma": 12.0]])
let ownerName = doc.owner?.text("name")
```

## Result builders

A builder that joins markup fragments, with optional, either and loop support:

```swift
@resultBuilder
enum MarkupBuilder {
    static func buildBlock(_ parts: String...) -> String { parts.joined(separator: "\n") }
    static func buildOptional(_ part: String?) -> String { part ?? "" }
    static func buildEither(first part: String) -> String { part }
    static func buildEither(second part: String) -> String { part }
    static func buildArray(_ parts: [String]) -> String { parts.joined(separator: "\n") }
}

func section(@MarkupBuilder _ body: () -> String) -> String { "<section>\n\(body())\n</section>" }
func heading(_ t: String) -> String { "<h2>\(t)</h2>" }
func para(_ t: String) -> String { "<p>\(t)</p>" }

let isBeta = true
let page = section {
    heading("Release notes")
    para("Faster sync.")
    if isBeta { para("Beta build.") }
}
```

`buildFinalResult` converts the accumulated component into a different output
type at the very end. A builder can collect `AttributedString` pieces and hand
back a SwiftUI `Text`:

```swift
import SwiftUI

@resultBuilder
enum StyledTextBuilder {
    static func buildExpression(_ s: AttributedString) -> AttributedString { s }
    static func buildBlock(_ parts: AttributedString...) -> AttributedString {
        parts.reduce(into: AttributedString()) { $0.append($1) }
    }
    static func buildFinalResult(_ joined: AttributedString) -> Text { Text(joined) }
}
```

## Property wrappers

### Backed by UserDefaults

```swift
import Foundation

@propertyWrapper
struct Preference<Value> {
    let key: String
    let fallback: Value
    let defaults: UserDefaults

    init(wrappedValue: Value, _ key: String, defaults: UserDefaults = .standard) {
        self.key = key
        self.fallback = wrappedValue
        self.defaults = defaults
    }

    var wrappedValue: Value {
        get { defaults.object(forKey: key) as? Value ?? fallback }
        set { defaults.set(newValue, forKey: key) }
    }
}

struct ReaderSettings {
    @Preference("fontScale") var fontScale = 1.0
    @Preference("nightMode") var nightMode = false
}
```

Passing a suite-specific `UserDefaults` in tests keeps them isolated.

### Validation with a projected flag

```swift
@propertyWrapper
struct Checked {
    private var text = ""
    private let rule: (String) -> Bool
    private(set) var passes = false

    init(wrappedValue: String, _ rule: @escaping (String) -> Bool) {
        self.rule = rule
        self.wrappedValue = wrappedValue
    }

    var wrappedValue: String {
        get { text }
        set { text = newValue; passes = rule(newValue) }
    }
    var projectedValue: Bool { passes }
}

struct SignupForm {
    @Checked({ $0.count >= 3 }) var handle = ""
    @Checked({ $0.contains("@") }) var mail = ""
    var canSubmit: Bool { $handle && $mail }
}
```

## Advanced Regex

A `Reference` names a capture so it can be read by key instead of by tuple
position. `ChoiceOf` lists alternatives.

```swift
import RegexBuilder

let level = Reference(Substring.self)
let message = Reference(Substring.self)
let logLine = Regex {
    "["
    Capture(as: level) { ChoiceOf { "DEBUG"; "NOTICE"; "FAULT" } }
    "] "
    Capture(as: message) { OneOrMore(.any) }
}
if let m = "[FAULT] disk full".firstMatch(of: logLine) {
    print(m[level], m[message])
}
```

Small pieces compose into larger patterns. An IPv4 octet built once and reused:

```swift
let octet = Regex {
    ChoiceOf {
        Regex { "25"; ("0"..."5") }
        Regex { "2"; ("0"..."4"); One(.digit) }
        Regex { Optionally { ("0"..."1") }; One(.digit); Optionally { One(.digit) } }
    }
}
let ipv4 = Regex {
    octet; "."; octet; "."; octet; "."; octet
}
let isAddress = "10.0.254.1".wholeMatch(of: ipv4) != nil
```

## Custom FormatStyle

Conform to `FormatStyle`, name the input and output types, implement
`format(_:)`, then add a static member so call sites read naturally.

```swift
import Foundation

struct PaceStyle: FormatStyle {
    typealias FormatInput = Double
    typealias FormatOutput = String

    func format(_ secondsPerKm: Double) -> String {
        let total = Int(secondsPerKm.rounded())
        return "\(total / 60)'\(String(format: "%02d", total % 60))\" /km"
    }
}

extension FormatStyle where Self == PaceStyle {
    static var pace: PaceStyle { PaceStyle() }
}

let label = 312.0.formatted(.pace)
```

Anything more (locale-aware parsing, attributed output) goes to
`swift-formatstyle`.

## Collection patterns

The Swift Algorithms package (`import Algorithms`) adds sequence helpers:

```swift
import Algorithms

let uploads = Array(1...23)
for batch in uploads.chunks(ofCount: 10) { print(batch.count) }

let readings = [3.0, 5.0, 4.0, 8.0, 6.0]
let smoothed = readings.windows(ofCount: 3).map { $0.reduce(0, +) / 3 }

let stops = ["Depot", "Mill Rd", "Harbour"]
let legs = stops.adjacentPairs().map { "\($0) to \($1)" }
```

`chunks(ofCount:)` batches, `windows(ofCount:)` slides a fixed window (a
moving average here), `adjacentPairs()` pairs each element with the next.

## guard: complex pattern matching

Several clauses in one `guard` can walk untyped JSON. Prefer Codable when the
shape is known; this is for genuinely dynamic input.

```swift
import Foundation

func firstTrackTitle(_ data: Data) -> String? {
    guard let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
          let album = root["album"] as? [String: Any],
          let tracks = album["tracks"] as? [[String: Any]],
          let title = tracks.first?["title"] as? String
    else { return nil }
    return title
}
```

Enum payloads plus extra conditions work inside loops:

```swift
struct Plan { var isEnabled: Bool; var isExpired: Bool }
enum Status { case active(Plan), paused }
struct Account { var name: String; var status: Status }

func billable(_ accounts: [Account]) -> [String] {
    var names: [String] = []
    for account in accounts {
        guard case .active(let plan) = account.status, plan.isEnabled, !plan.isExpired else {
            continue
        }
        names.append(account.name)
    }
    return names
}
```

## Typed throws in protocols

An associated error type lets each conformer throw its own concrete error
while callers keep exhaustive handling.

```swift
protocol Vault {
    associatedtype VaultError: Error
    func read(_ key: String) throws(VaultError) -> Data
    func write(_ data: Data, for key: String) throws(VaultError)
}

final class MemoryVault: Vault {
    enum VaultError: Error { case missing(String), full }
    var slots: [String: Data] = [:]
    let capacity = 8

    func read(_ key: String) throws(VaultError) -> Data {
        guard let data = slots[key] else { throw .missing(key) }
        return data
    }
    func write(_ data: Data, for key: String) throws(VaultError) {
        guard slots.count < capacity || slots[key] != nil else { throw .full }
        slots[key] = data
    }
}
```

## String interpolation

Add `appendInterpolation` overloads to `DefaultStringInterpolation`:

```swift
import Foundation

extension DefaultStringInterpolation {
    mutating func appendInterpolation(json value: some Encodable) {
        let writer = JSONEncoder()
        writer.outputFormatting = [.prettyPrinted, .sortedKeys]
        if let data = try? writer.encode(value), let text = String(data: data, encoding: .utf8) {
            appendLiteral(text)
        } else {
            appendLiteral("<unencodable>")
        }
    }

    mutating func appendInterpolation(ordinal n: Int) {
        let f = NumberFormatter()
        f.numberStyle = .ordinal
        appendLiteral(f.string(from: NSNumber(value: n)) ?? String(n))
    }
}

struct Seat: Encodable { var row: Int; var letter: String }
let dump = "\(json: Seat(row: 12, letter: "C"))"
let place = "You finished \(ordinal: 2)"
```

## Never: advanced usage

- Combine uses `Never` as a failure type: `AnyPublisher<Int, Never>` is a
  stream that cannot fail, which is what `assign(to:)` and SwiftUI bindings
  expect.
- Empty enums are uninhabited too, which makes them good phantom types. A
  generic parameter can carry state in the type, and constrained extensions
  expose methods only in the right state:

```swift
enum Draft {}
enum Published {}

struct Article<Stage> {
    var body: String
}

extension Article where Stage == Draft {
    func publish() -> Article<Published> { Article<Published>(body: body) }
}

extension Article where Stage == Published {
    var shareURL: String { "https://example.com/a/\(body.count)" }
}

let draft = Article<Draft>(body: "Hello")
let live = draft.publish()
```

- Because `Never` has no values, a function taking one can never be called,
  so its body may stay empty with no `return`. An empty `switch impossible {}`
  also type-checks, but the compiler then warns "will never be executed":

```swift
func unreachable<T>(_ impossible: Never) -> T {}
```
