Swiftpack.co - Package - SDGGiesbrecht/SDGCornerstone

macOS • Linux • iOS • watchOS • tvOS



SDGCornerstone forms the foundation of the SDG module family. It establishes design patterns and provides general‐use extensions to the Swift Standard Library and Foundation.

הִנְנִי יִסַּד בְּצִיּוֹן אָבֶן אֶבֶן בֹּחַן פִּנַּת יִקְרַת מוּסָד מוּסָד׃

Behold, I establish in Zion a stone, a tested stone, a precious cornerstone, a sure foundation.



  • Localization tools compatible with the Swift Package Manager and Linux. (SDGLocalization)
  • User preferences compatible with Linux. (PreferenceSet, Preference)
  • Platform‐independent access to best‐practice file system locations. (url(for:in:at:))
  • Shared instances of value types. (Shared<Value>)
  • Generic pattern matching. (SearchableCollection, Pattern<Element>)
  • Customizable randomization. (SDGRandomization)
  • Arbitrary‐precision arithmetic. (SDGPrecisionMathematics)
  • A simple API for running shell commands on desktop platforms. (SDGExternalProcess)

...and much more.

Exampe Usage

// ••••••• Localization •••••••

enum ApplicationLocalization : String, Localization {
    case english = "en"
    case français = "fr"
    static let fallbackLocalization = ApplicationLocalization.english

// Define
let text = UserFacing<StrictString, ApplicationLocalization>({ localization in
    switch localization {
    case .english:
        return "Hello, world!"
    case .français:
        return "Bonjour, le monde !"

// Use
               "Hello, world!")

// ••••••• Preferences •••••••

let preferences = PreferenceSet.applicationPreferences

// Save
preferences["name"].value.set(to: "John Doe")
// Load
let loaded: String? = preferences["name"].value.as(String.self)

               "John Doe")

// ••••••• File System •••••••

let url = FileManager.default.url(in: .applicationSupport, at: "folder/file.txt")
do {
    // Save
    try "Contents".save(to: url)
    // Load
    let loaded = try String(from: url)

} catch {

// ••••••• Shared Values •••••••

class Owner {
    @SharedProperty var property: String = ""

let originalOwner = Owner()
originalOwner.property = "original"
let anotherOwner = Owner()
anotherOwner.$property = originalOwner.$property

anotherOwner.property = "changed"

// ••••••• Pattern Matching •••••••

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let patternFirstPart = [1] // 1
    + ConditionalPattern({ $0.isEven }) // 2
    + ([30, 40] // (∅)
        ∨ [3, 4]) // 3, 4
let pattern = patternFirstPart
    + RepetitionPattern(¬[5, 7]) // 5, 6, 7, 8, 9 (...)
    + [10] // 10

XCTAssertEqual(numbers.firstMatch(for: pattern)?.range,
               numbers.startIndex ..< numbers.endIndex)

// ••••••• Arbitrary Precision Arithmetic •••••••

let tenDuotrigintillion: WholeNumber = "10 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000"
XCTAssert(tenDuotrigintillion.isDivisible(by: 10))

#if !(os(iOS) || os(watchOS) || os(tvOS))

// ••••••• Shell Commands •••••••

XCTAssertEqual(try? Shell.default.run(command: ["echo", "Hello, world!"]).get(),
               "Hello, world!")


SDGCornerstone provides libraries for use with the Swift Package Manager.

Simply add SDGCornerstone as a dependency in Package.swift and specify which of the libraries to use:

let package = Package(
    name: "MyPackage",
    dependencies: [
        .package(url: "https://github.com/SDGGiesbrecht/SDGCornerstone", from: Version(3, 1, 0)),
    targets: [
        .target(name: "MyTarget", dependencies: [
            .productItem(name: "SDGControlFlow", package: "SDGCornerstone"),
            .productItem(name: "SDGLogic", package: "SDGCornerstone"),
            .productItem(name: "SDGLogicTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGMathematics", package: "SDGCornerstone"),
            .productItem(name: "SDGMathematicsTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGCollections", package: "SDGCornerstone"),
            .productItem(name: "SDGCollectionsTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGBinaryData", package: "SDGCornerstone"),
            .productItem(name: "SDGText", package: "SDGCornerstone"),
            .productItem(name: "SDGCollation", package: "SDGCornerstone"),
            .productItem(name: "SDGPersistence", package: "SDGCornerstone"),
            .productItem(name: "SDGPersistenceTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGRandomization", package: "SDGCornerstone"),
            .productItem(name: "SDGRandomizationTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGLocalization", package: "SDGCornerstone"),
            .productItem(name: "SDGLocalizationTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGGeometry", package: "SDGCornerstone"),
            .productItem(name: "SDGGeometryTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGCalendar", package: "SDGCornerstone"),
            .productItem(name: "SDGPrecisionMathematics", package: "SDGCornerstone"),
            .productItem(name: "SDGConcurrency", package: "SDGCornerstone"),
            .productItem(name: "SDGExternalProcess", package: "SDGCornerstone"),
            .productItem(name: "SDGVersioning", package: "SDGCornerstone"),
            .productItem(name: "SDGTesting", package: "SDGCornerstone"),
            .productItem(name: "SDGXCTestUtilities", package: "SDGCornerstone"),

The modules can then be imported in source files:

import SDGControlFlow
import SDGLogic
import SDGLogicTestUtilities
import SDGMathematics
import SDGMathematicsTestUtilities
import SDGCollections
import SDGCollectionsTestUtilities
import SDGBinaryData
import SDGText
import SDGCollation
import SDGPersistence
import SDGPersistenceTestUtilities
import SDGRandomization
import SDGRandomizationTestUtilities
import SDGLocalization
import SDGLocalizationTestUtilities
import SDGGeometry
import SDGGeometryTestUtilities
import SDGCalendar
import SDGPrecisionMathematics
import SDGConcurrency
import SDGExternalProcess
import SDGVersioning
import SDGTesting
import SDGXCTestUtilities


The SDGCornerstone project is maintained by Jeremy David Giesbrecht.

If SDGCornerstone saves you money, consider giving some of it as a donation.

If SDGCornerstone saves you time, consider devoting some of it to contributing back to the project.

Ἄξιος γὰρ ὁ ἐργάτης τοῦ μισθοῦ αὐτοῦ ἐστι.

For the worker is worthy of his wages.



Stars: 10
Help us keep the lights on



3.1.0 - Oct 25, 2019

New Features

  • Font has a new resized(to:) method. (Sunk from SDGInterface’s SDGTextDisplay.)

Bug Fixes

  • SemanticMarkup.richText(font:) now preserves the system font on macOS 10.15, even after the font has been resized.

3.0.0 - Oct 18, 2019

Breaking Changes

  • The pattern API has been rearranged to improve performance. The compiler can now do a much better job of specialization.
    • The Pattern base class has been removed and its subclasses converted to structures.
      • In its place, PatternProtocol has been shortened to simply Pattern.
    • LiteralPattern is no longer needed. Any SearchableCollection can be used directly.
    • Several pattern types have been renamed:
      • CompositePatternConcatenatedPatterns
      • NotPatternNegatedPattern
    • CompositePattern and AlternativePatterns have each been split into several layers that make different tradeoffs between performance and composability.
      1. ConcatenatedPatterns and AlternativePatterns represent heterogeneous pairs of patterns.
        • Pros:
          • These are fast, because the compiler can specialize them.
          • They can be composed at compile time to any level of complexity by stringing them together with + and .
        • Cons:
          • Composed types are heavily generic and make unwieldy properties, parameters or return types.
          • Composition cannot be done iteratively, since each addition changes the type.
      2. NaryConcatenatedPatterns and NaryAlternativePatterns represent n‐ary homogeneous collections of patterns.
        • Pros:
          • These are fast, because the compiler can specialize them.
          • They can be composed iteratively by constructing an array to pass to the initializer.
        • Cons:
          • All components must be of the same type.
      3. AnyPattern can be used to convert various patterns to the same type for use withNaryConcatenatedPatterns and NaryAlternativePatterns.
        • Pros:
          • Infinite composability.
        • Cons:
          • Not nearly as fast.
  • difference(from:) has been renamed to groupedDifferences(from:) to distinguish it from the similar method now available in the Standard Library on some platforms.
  • String index conversions now reflect the fact that the various views’ indices are merely type aliases of one another. Due to the absence of type safety, return values can now be nil if any index can lack a corresponding value, even those indices the type label does not intend. scalar(in:) can be used to get an unoptional scalar index. It rounds down when called on sub‐scalar indices by accident.

New Features

  • A new module, SDGVersioning, provides utilities for working with semantic versions. (It was formerly a part of the SDGSwift package.)
  • Several types can now be used as property wrappers:
    • Shared (indirectly via @SharedProperty). The projected value is the Shared reference.
    • Weak projects itself.

2.6.0 - Oct 1, 2019

New Features

  • All platform deployment target restrictions have been removed.

Bug Fixes

  • SemanticMarkup.richText(font:) now preserves the system font, despite substitutions performed by the new font system on recent Apple platforms.

2.5.1 - Sep 27, 2019

Bug Fixes

  • Impossible XCTest imports have been prevented and dependent symbols removed so that everything else can still be used. This only affects builds that:

    • use the SDGXCTestUtilities module,
    • target iOS or tvOS,
    • target the device, not the simulator, and
    • are performed in an Xcode project created with swift package generate-xcodeproj.

2.5.0 - Sep 22, 2019

Swift 5.1 is required. Older versions of the package manager will not resolve to this release.

New Features

  • Dates descriptions can be adjusted for time zones.
  • SDGXCTestUtilities on iOS and tvOS is no longer limited to the simulator.