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.

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 {
  @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

  numbers.firstMatch(for: pattern)?.range,

// ••••••• 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 •••••••

    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(4, 2, 1)),
    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: 11


Used By

Total: 0


Version 4.2.1 - 2020-01-23 02:27:58

Dependency updates.

Version 4.2.0 - 2020-01-03 04:54:41

New Features

  • AnyLocalization is available to type‐erase localizations.

Bug Fixes

  • Data is available about more localizations.
  • The root collation has been improved.

Version 4.1.0 - 2019-12-27 23:09:51

New Features

  • CoreGraphics types included in the core library edition of Foundation, such as CGFloat, now receive their extensions even when CoreGraphics itself is unavailable.

Bug Fixes

  • Where relevant, implementations have been deferred to the Swift project’s Numerics package.

Version 4.0.2 - 2019-12-17 03:19:21

Bug Fixes

  • An overload has been added to disambiguate contains(_:) between Pattern and StringProtocol.

Version 4.0.1 - 2019-12-03 00:34:13

Bug Fixes

  • Fix a bug where the comparison aids would report faulty orders in some situations.

Version 4.0.0 - 2019-11-28 02:40:14

Breaking Changes

  • The Standard Library difference API has been adopted and legacy API removed. Shimming has been done so that it works on older platforms. Most of the shimmed API is identical, but several extension methods—which could not otherwise be disambiguated—have differing names:
    • changes(from:) instead of difference(from:)
    • applying(changes:) instead of applying(_:)

New Features

  • New short‐circuiting compare functions are available to simplify conforming to Comparable when multiple criteria are involved.

Version 3.1.0 - 2019-10-25 23:28:13

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.

Version 3.0.0 - 2019-10-18 23:06:38

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.

Version 2.6.0 - 2019-10-01 19:15:42

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.

Version 2.5.1 - 2019-09-27 00:23:53

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.

Version 2.5.0 - 2019-09-22 02:34:27

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.

Version 2.4.0 - 2019-09-17 01:26:55

New Features

  • Stabilized localization resolution, which is an opt‐in variant that can help prevent interface elements with a high refresh rate from bouncing rapidly between localizations when several are active at once.

Version 2.3.0 - 2019-09-10 19:06:14

New Features

  • CalendarDate provides date and time representations in more languages.

Version 2.2.0 - 2019-08-27 20:46:23

New Features

  • Some of the underlying data used by SDGLocalization is now accessible to other modules through the StateData and LocalizationData types.

Version 2.1.0 - 2019-07-27 00:38:53

New Features

  • Tailorable text collation.

Bug Fixes

  • Interface‐related components are now localized into German.

Version 2.0.0 - 2019-07-09 20:51:48

Breaking Changes

  • Font and BézierPath are separate encapsulating types instead of type aliases.

Version 1.1.0 - 2019-07-02 04:20:36

New Features

  • Preference has subscripts which enable the mutation of the value with only one statement.

Version 1.0.0 - 2019-06-11 23:36:40

Breaking Changes

  • Modules do not export each other. Each must be imported separately.
    • The @_exported attribute was never officially supported by Swift anyway. As the last remaining thing blocking the 1.0.0 release, it was deemed not important enough to delay until official support. Since it is not strictly necessary for any functionality, it has been removed instead of waiting.

Version 0.18.1 - 2019-05-21 01:37:04

No changes to the public API.

Version 0.18.0 - 2019-05-07 02:30:05

Breaking Changes

  • Methods which throw specific errors types now do so using Result for stronger typing.
    • Affected initializers have been converted into static generator functions, because initializers cannot return a Result.
    • Methods which simply pass on untyped errors from Swift or Foundation are unaffected by this change; they continue to simply throw.
  • Minor adjustments have been made to the vector and point protocol hierarchies. Some protocols have been renamed with “Protocol” at the end to make room for concrete types. (e.g. TwoDimensionalPointTwoDimensionalPointProtocol)

New Features

  • Generic, cross‐platform two‐dimensional point and vector types are available.

Version 0.17.1 - 2019-04-27 20:36:10

New Features

  • StrictString.StringInterpolation and SemanticMarkup.StringInterpolation are available for use by other types.

Version 0.17.0 - 2019-04-20 20:17:49

Breaking Changes

  • iOS 11
  • watchOS 4
  • tvOS 11
  • Operators are no longer duplicated in the umbrella SDGCornerstone module. Import SDGLogic, SDGMathematics and SDGCollections directly to get access to them (until Swift properly exports operators).
  • Interpolation of strict strings and semantic markup require values to be converted to explicit text representations. Existing interpolations which rely on implicit description will no longer compile.
    var strict: StrictString = ""
    // String‐like types can be interpolated directly:
    let string: String = "Hello, world!"
    let character: Unicode.Scalar = "?"
    strict = "\(string) ...\(character)"
    // Most other types must be explicitly converted to some predictable text representation:
    let number = Int.random(in: 0 ... 1000)
    strict = "“\(number.inRomanNumerals())” means the same as “\(number.inDigits())”."
    // The Swift compiler’s own description of any value can still be requested explicitly:
    let something: Any = getError()
    strict = "Error: \(arbitraryDescriptionOf: something)"

Bug Fixes

  • Conditional patterns can be successfully compared against the end of a collection.

Version 0.16.0 - 2019-04-05 02:37:00

Breaking Changes

  • iOS 10
  • watchOS 3
  • tvOS 10
  • BuildConfiguration has been removed. Use the package manager’s new build settings instead.
  • AdditiveArithmetic has been renamed to GenericAdditiveArithmetic and now inherits from the Standard Library’s AdditiveArithmetic.
    • additiveIdentity has been removed in favour of AdditiveArithmetic’s zero.
  • Recommended file system locations are now delegated to Foundation on Linux. The URLs may be different than with previous releases.

New Features

  • StrictString and SemanticMarkup conform to the new ExpressibleByStringInterpolation protocol.

Version 0.15.0 - 2019-03-29 00:45:25

Breaking Changes

  • Swift 5
  • macOS 10.13

Version 0.14.0 - 2019-03-20 01:10:54

Breaking Changes

  • FileManager.RecommendedLocation.temporary has been removed. Use withTemporaryDirectory(appropriateFor:_:) instead. It automates clean‐up and attempts to use the same volume as the specified destination.

Version 0.13.0 - 2019-01-05 05:08:55

Breaking Changes

  • Swift 4.2.1

New Features

  • Types conforming to PatternProtocol or SetDefinition can now be used in switch cases.

Version 0.12.0 - 2018-10-14 09:51:17

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).

Version 0.11.1 - 2018-09-29 11:08:01

Bug Fixes

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

Version 0.11.0 - 2018-09-19 13:00:52

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.

Version 0.10.1 - 2018-07-09 23:55:35

New Features

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