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).
  • User preferences access (compatible with Linux).
  • Platform‐independent access to best‐practice file system locations.
  • Shared instances of value types.
  • Generic pattern matching.
  • Arbitrary‐precision arithmetic.
  • Simple API for running shell commands (desktop platforms only).

...and much more.

Use the entire package together by importing the SDGCornerstone product, or pick and choose pieces by importing the various component products.

(For a list of related projects, see here.)


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", .upToNextMinor(from: Version(0, 12, 0))),
    targets: [
        .target(name: "MyTarget", dependencies: [
            .productItem(name: "SDGCornerstone", package: "SDGCornerstone"),
            .productItem(name: "SDGCornerstoneTestUtilities", package: "SDGCornerstone"),
            .productItem(name: "SDGXCTestUtilities", package: "SDGCornerstone"),
            .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: "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: "SDGCalendar", package: "SDGCornerstone"),
            .productItem(name: "SDGPrecisionMathematics", package: "SDGCornerstone"),
            .productItem(name: "SDGConcurrency", package: "SDGCornerstone"),
            .productItem(name: "SDGExternalProcess", package: "SDGCornerstone"),
            .productItem(name: "SDGTesting", package: "SDGCornerstone"),

The libraries’ modules can then be imported in source files:

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

Example 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 {
    var property: Shared<String>
    init(property: Shared<String>) {
        self.property = property

let originalOwner = Owner(property: Shared("original"))
let anotherOwner = Owner(property: originalOwner.property)

anotherOwner.property.value = "changed"

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

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let pattern = CompositePattern([
    LiteralPattern([1]), // 1
    ConditionalPattern({ $0.isEven }), // 2
        LiteralPattern([30, 40]), // (∅)
        LiteralPattern([3, 4]) // 3, 4
    RepetitionPattern(NotPattern(LiteralPattern([5, 7]))), // 5, 6, 7, 8, 9 (...)
    LiteralPattern([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!"]),
               "Hello, world!")


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: 7
Help us keep the lights on


Used By



0.12.0 - Oct 14, 2018

Breaking Changes

  • As part of adoption of CaseIterable:
    • IterableEnumeration has been dropped. Use CaseIterable instead.
    • The related requirements of some protocols have changed. See the respective documentation.
      • OrderedEnumeration
      • InputLocalization
      • EnumerationCalendarComponent
    • All types which used to conform to IterableEnumeration have switched to CaseIterable.
  • As part of adoption of Swift’s own new randomization API:
    • The Randomizer protocol has been removed. Use RandomNumberGenerator instead.
      • PseudorandomNumberGenerator and CyclicalNumberGenerator now conform to RandomNumberGenerator and are structures instead of classes.
        • PseudorandomNumberGenerator no longer has a defaultGenerator. Use SystemRandomNumberGenerator() instead.
      • Randomization of the following types and protocols has been removed. Use the Standard Library’s API instead.
        • Bool (but falseRandomizerValue and trueRandomizerValue remain)
        • IntFamily
        • UInt
        • FloatFamily
        • Collection
      • Randomization of the following types has been altered to follow the pattern of the Standard Library’s API.
        • RangeReplaceableCollection
        • Measurement
    • Randomization has been sunk lower in the protocol hierarchy.
      • Randomization is a new conformance requirement of some protocols:
        • WholeArithmetic
      • RandomizableNumber and testRandomizableNumberConformance have been removed.
    • testRandomizerConformance has been replaced with testRandomNumberGeneratorConformance.
  • ¬= has been removed. Use toggle().
  • Postfix −= has been removed. Use negate().
  • Several obscure parts of the FloatFamily API that were no longer needed have been removed (ln2, init(_: Exponent).

0.11.1 - Sep 29, 2018

Bug Fixes

  • Linux no longer encounters linker errors when depending on SDGCornerstone. (See SR‐8803.)

0.11.0 - Sep 19, 2018

Breaking Changes

  • Swift 4.2
  • Search range arguments have been removed from all search methods. Use these methods on subsequences instead:
    let match: PatternMatch<Collection>? = collection.firstMatch(for: pattern, in: range)
    let match: PatternMatch<Collection.SubSequence>? = collection[range].firstMatch(for: pattern)
    // And if the subsequence is a different type and needs to be converted back:
    let converted: PatternMatch<Collection>? = match?.in(collection)

New Features

  • Range expressions are now supported throughout the API.
  • Pattern types and SearchableCollection literal patterns both conform to a new primitive PatternProtocol, removing the need for method overloads to support each individually.
  • Localization now provides a textDirection property.

0.10.1 - Jul 9, 2018

New Features

  • Sequence gains statistical methods: mean(), median() and statisticalMode().
  • Sequences can be transformed into counted sets (countedSet() -> [Element: Int]).

0.10.0 - May 30, 2018

Breaking Changes

  • Bounded pattern searches no longer report matches stretching outside of the specified bounds. This fix necessitated changes to the signatures of several overridable Pattern methods.