diff --git a/CODEOWNERS b/.github/CODEOWNERS
similarity index 71%
rename from CODEOWNERS
rename to .github/CODEOWNERS
index 706801d4..5d6c72cf 100644
--- a/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,9 +2,8 @@
* @ffried
# Workflow & Deployment related files
-.github/* @ffried
-.jazzy.yaml @ffried
-.codecov.yml @ffried
+.github/* @ffried
+.codecov.yml @ffried
# Project & Source files
*.swift @ffried
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index d85552df..0bf5a9d4 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,13 +1,24 @@
version: 2
updates:
- - package-ecosystem: "github-actions"
- directory: "/"
+ - package-ecosystem: github-actions
+ directory: /
open-pull-requests-limit: 10
schedule:
- interval: "daily"
- time: "08:00"
- timezone: "Europe/Berlin"
+ interval: daily
+ time: 08:00
+ timezone: Europe/Berlin
+ assignees:
+ - ffried
+ reviewers:
+ - ffried
+ - package-ecosystem: swift
+ directory: /
+ open-pull-requests-limit: 10
+ schedule:
+ interval: daily
+ time: 08:00
+ timezone: Europe/Berlin
assignees:
- ffried
reviewers:
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 494b3506..485cc107 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -8,229 +8,19 @@ on:
push:
branches: [ main ]
-jobs:
- release-context:
- runs-on: ubuntu-latest
- outputs:
- version-name: ${{ github.ref_name }}
- is-latest: ${{ steps.compare-tags.outputs.is-latest }}
- steps:
- - uses: joutvhu/get-release@v1
- id: latest-release
- with:
- latest: true
- throwing: false
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: Compare tags
- id: compare-tags
- env:
- REF_TYPE: ${{ github.ref_type }}
- REF_NAME: ${{ github.ref_name }}
- LATEST_TAG: ${{ steps.latest-release.outputs.tag_name }}
- run: |
- if [ "${REF_TYPE}" == 'tag' ] && [ "${REF_NAME}" == "${LATEST_TAG}" ]; then
- echo 'is-latest=true' >> "${GITHUB_OUTPUT}"
- else
- echo 'is-latest=false' >> "${GITHUB_OUTPUT}"
- fi
-
- spm-context:
- runs-on: ubuntu-latest
- outputs:
- package-dump: ${{ steps.dump-package.outputs.package-dump }}
- steps:
- - uses: swift-actions/setup-swift@v1.24.0
- with:
- swift-version: '5.7'
- - uses: actions/checkout@v4
- # We don't use a cache here, because SPM doesn't resolve dependencies when dumping packages.
- - name: Dump package
- id: dump-package
- run: |
- delimiter="$(openssl rand -hex 8)"
- echo "package-dump<<${delimiter}" >> "${GITHUB_OUTPUT}"
- swift package dump-package >> "${GITHUB_OUTPUT}"
- echo "${delimiter}" >> "${GITHUB_OUTPUT}"
+permissions:
+ contents: write
- generate-docs:
- needs:
- - release-context
- - spm-context
- runs-on: macos-12
- strategy:
- matrix:
- target: ${{ fromJson(needs.spm-context.outputs.package-dump).products.*.targets.* }}
- steps:
- - uses: swift-actions/setup-swift@v1.24.0
- id: swift-setup
- with:
- swift-version: '5.7'
- - name: Read OS Version
- uses: sersoft-gmbh/os-version-action@v3
- id: os-version
- - uses: actions/checkout@v4
- - uses: actions/cache@v3
- with:
- path: .build
- key: ${{ runner.os }}-${{ steps.os-version.outputs.version }}-spm-${{ steps.swift-setup.outputs.version }}-${{ hashFiles('**/Package.resolved') }}
- restore-keys: |
- ${{ runner.os }}-${{ steps.os-version.outputs.version }}-spm-${{ steps.swift-setup.outputs.version }}-
- - uses: sersoft-gmbh/swifty-docs-action@v3
- env:
- ENABLE_DOCC_SUPPORT: '1'
- DOCC_JSON_PRETTYPRINT: 'YES'
- with:
- package-version: ${{ needs.release-context.outputs.version-name }}
- targets: ${{ matrix.target }}
- enable-inherited-docs: true
- enable-index-building: false
- transform-for-static-hosting: true
- hosting-base-path: ${{ github.event.repository.name }}/${{ needs.release-context.outputs.version-name }}
- output: ${{ matrix.target }}-docs
- - name: Package docs
- env:
- TARGET: ${{ matrix.target }}
- run: tar -cvf "${TARGET}-docs.tar" "${TARGET}-docs"
- - uses: actions/upload-artifact@v3
- with:
- name: ${{ matrix.target }}-docs
- path: ${{ matrix.target }}-docs.tar
+concurrency:
+ group: ${{ github.ref }}
+ cancel-in-progress: true
- publish-docs:
- needs:
- - release-context
- - spm-context
- - generate-docs
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- with:
- ref: gh-pages
- path: repository
- - uses: actions/download-artifact@v3
- with:
- path: artifacts
- - name: Extract tars
- run: find artifacts -name '*.tar' -execdir tar -xvf '{}' --strip-components 1 \; -delete
- - name: Merge documentations
- env:
- TARGETS: ${{ join(fromJson(needs.spm-context.outputs.package-dump).products.*.targets.*, ' ') }}
- DOCS_BASE_DIR: repository/${{ needs.release-context.outputs.version-name }}
- run: |
- rm -rf "${DOCS_BASE_DIR}"
- is_first=1
- for target in $TARGETS; do
- if [ $is_first -eq 1 ]; then
- echo "Copying initial documentation for ${target}"
- cp -R "artifacts/${target}-docs" "${DOCS_BASE_DIR}"
- is_first=0
- else
- echo "Merging documentation for ${target}"
- cp -R "artifacts/${target}-docs/data/documentation/"* "${DOCS_BASE_DIR}/data/documentation/"
- cp -R "artifacts/${target}-docs/documentation/"* "${DOCS_BASE_DIR}/documentation/"
- fi
- done
- echo "Deleting non-mergable metadata.json"
- rm -f "${DOCS_BASE_DIR}/metadata.json"
- - name: Create version index
- working-directory: repository
- env:
- TARGET_DOCS_DIR: ${{ needs.release-context.outputs.version-name }}/documentation
- INDEX_FILE: ${{ needs.release-context.outputs.version-name }}/index.html
- BASE_URL: 'https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ needs.release-context.outputs.version-name }}/documentation'
- REPO_NAME: ${{ github.event.repository.name }}
- run: |
- target_count=0
- target_list=""
- single_target_name=""
- for target in $(ls "${TARGET_DOCS_DIR}"); do
- if [ -d "${TARGET_DOCS_DIR}/${target}" ]; then
- single_target_name="${target}"
- target_count=$((target_count+1))
- target_list="${target_list}
${target}
Documentation"
- fi
- done
- if [ ${target_count} -gt 1 ]; then
- echo "Found ${target_count} targets. Generating list..."
- cat > "${INDEX_FILE}" <
-
-
- ${REPO_NAME} Documentation
-
-
-
-
-
- EOF
- else
- echo "Found one target. Generating redirect file to target ${single_target_name}"
- cat > "${INDEX_FILE}" <
-
-
- ${REPO_NAME} Documentation
-
-
-
- Redirecting...
-
-
- EOF
- fi
- - name: Create root index
- working-directory: repository
- env:
- REDIRECT_URL: 'https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/latest'
- REPO_NAME: ${{ github.event.repository.name }}
- run: |
- cat > 'index.html' <
-
-
- ${REPO_NAME} Documentation
-
-
-
- Redirecting...
-
-
- EOF
- - name: Create latest symlink
- if: ${{ needs.release-context.outputs.is-latest }}
- working-directory: repository
- env:
- VERSION_NAME: ${{ needs.release-context.outputs.version-name }}
- run: |
- rm -f 'latest'
- ln -s "${VERSION_NAME}" 'latest'
- - name: Determine changes
- id: check-changes
- working-directory: repository
- run: |
- if [ -n "$(git status --porcelain)" ]; then
- echo 'has-changes=true' >> "${GITHUB_OUTPUT}"
- else
- echo 'has-changes=false' >> "${GITHUB_OUTPUT}"
- fi
- - uses: crazy-max/ghaction-github-pages@v4
- if: ${{ steps.check-changes.outputs.has-changes }}
- with:
- keep_history: true
- build_dir: repository
- commit_message: Deploy documentation for '${{ needs.release-context.outputs.version-name }}'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- cleanup:
- needs:
- - generate-docs
- - publish-docs
- if: ${{ always() }}
- runs-on: ubuntu-latest
- steps:
- - name: Cleanup Artifacts
- uses: joutvhu/delete-artifact@v1
+jobs:
+ generate-and-publish-docs:
+ uses: sersoft-gmbh/oss-common-actions/.github/workflows/swift-generate-and-publish-docs.yml@main
+ with:
+ os: macOS
+ swift-version: '5.9'
+ organisation: ${{ github.repository_owner }}
+ repository: ${{ github.event.repository.name }}
+ pages-branch: gh-pages
diff --git a/.github/workflows/enable-auto-merge.yml b/.github/workflows/enable-auto-merge.yml
index 6b3a13af..74fbf988 100644
--- a/.github/workflows/enable-auto-merge.yml
+++ b/.github/workflows/enable-auto-merge.yml
@@ -1,6 +1,8 @@
name: Auto-merge for Dependabot PRs
-on: pull_request
+on:
+ pull_request:
+ branches: [ main ]
permissions:
contents: write
diff --git a/.github/workflows/swift-test.yml b/.github/workflows/swift-test.yml
index 14532738..53c7c234 100644
--- a/.github/workflows/swift-test.yml
+++ b/.github/workflows/swift-test.yml
@@ -6,67 +6,37 @@ on:
pull_request:
branches: [ main ]
+permissions:
+ contents: read
+
jobs:
+ variables:
+ outputs:
+ max-supported-swift-version: '5.9'
+ xcode-scheme: FFFoundation
+ xcode-platform-version: latest
+ fail-if-codecov-fails: true
+ runs-on: ubuntu-latest
+ steps:
+ - run: exit 0
+
test-spm:
+ needs: variables
strategy:
matrix:
- os: [ macos-12 ]
- swift-version: [ '' ]
- xcode-version: [ '^13.4' ]
- include:
- - os: macos-12
- swift-version: ''
- xcode-version: '^14.1'
- - os: ubuntu-20.04
- swift-version: 5.6
- xcode-version: ''
- - os: ubuntu-20.04
- swift-version: 5.7
- xcode-version: ''
- - os: ubuntu-22.04
- swift-version: 5.7
- xcode-version: ''
-
- runs-on: ${{ matrix.os }}
-
- steps:
- - if: ${{ runner.os == 'macOS' }}
- uses: maxim-lobanov/setup-xcode@v1
- with:
- xcode-version: ${{ matrix.xcode-version }}
- - name: Install Swift
- if: ${{ runner.os == 'Linux' }}
- uses: sersoft-gmbh/swifty-linux-action@v3
- with:
- release-version: ${{ matrix.swift-version }}
- platform: ${{ matrix.os }}
- github-token: ${{ secrets.GITHUB_TOKEN }}
- - name: Read OS Version
- uses: sersoft-gmbh/os-version-action@v3
- id: os-version
- - name: Read Swift Version
- uses: sersoft-gmbh/swift-version-action@v3
- id: swift-version
- - uses: actions/checkout@v4
- - uses: actions/cache@v3
- with:
- path: .build
- key: ${{ runner.os }}-${{ steps.os-version.outputs.version }}-spm-${{ steps.swift-version.outputs.version }}-${{ hashFiles('**/Package.resolved') }}
- restore-keys: |
- ${{ runner.os }}-${{ steps.os-version.outputs.version }}-spm-${{ steps.swift-version.outputs.version }}-
- - name: Build & Test
- run: swift test -v --parallel --enable-code-coverage
- - name: Generate Coverage Files
- uses: sersoft-gmbh/swift-coverage-action@v4
- id: coverage-files
- - uses: codecov/codecov-action@v3
- with:
- token: ${{ secrets.CODECOV_TOKEN }}
- files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }}
- fail_ci_if_error: true
+ os: [ macOS, ubuntu ]
+ swift-version-offset: [ 0 ]
+ uses: sersoft-gmbh/oss-common-actions/.github/workflows/swift-test-spm.yml@main
+ with:
+ os: ${{ matrix.os }}
+ max-swift-version: ${{ needs.variables.outputs.max-supported-swift-version }}
+ swift-version-offset: ${{ matrix.swift-version-offset }}
+ fail-if-codecov-fails: ${{ fromJson(needs.variables.outputs.fail-if-codecov-fails) }}
+ secrets:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test-xcode:
- runs-on: macos-12
+ needs: variables
strategy:
matrix:
platform:
@@ -75,76 +45,14 @@ jobs:
- iPadOS
- tvOS
- watchOS
- env:
- XCODE_SCHEME: FFFoundation
- steps:
- - uses: maxim-lobanov/setup-xcode@v1
- with:
- xcode-version: ^14.1
- - name: Read OS Version
- uses: sersoft-gmbh/os-version-action@v3
- id: os-version
- - name: Read Swift Version
- uses: sersoft-gmbh/swift-version-action@v3
- id: swift-version
- - name: Select destination
- id: destination
- env:
- PLATFORM: ${{ matrix.platform }}
- run: |
- DESTINATION=''
- case "${PLATFORM}" in
- 'macOS') DESTINATION='platform=macOS';;
- 'iOS') DESTINATION='platform=iOS Simulator,OS=latest,name=iPhone 13 Pro';;
- 'iPadOS') DESTINATION='platform=iOS Simulator,OS=latest,name=iPad Pro (11-inch) (3rd generation)';;
- 'tvOS') DESTINATION='platform=tvOS Simulator,OS=latest,name=Apple TV 4K (2nd generation)';;
- 'watchOS') DESTINATION='platform=watchOS Simulator,OS=latest,name=Apple Watch Series 7 (45mm)';;
- *) echo "::error title=Unknown platform!::Unknown platform: ${PLATFORM}" && exit 1;;
- esac
- echo "xcode=${DESTINATION}" >> "${GITHUB_OUTPUT}"
- - uses: actions/checkout@v4
- # PIF ISSUES: https://github.com/apple/swift-package-manager/issues/5767
- - uses: actions/cache@v3
- with:
- path: .build
- key: ${{ runner.os }}-${{ steps.os-version.outputs.version }}-spm-${{ steps.swift-version.outputs.version }}-${{ hashFiles('**/Package.resolved') }}
- restore-keys: |
- ${{ runner.os }}-${{ steps.os-version.outputs.version }}-spm-${{ steps.swift-version.outputs.version }}-
- - name: Work around PIF issues
- env:
- DESTINATION: ${{ steps.destination.outputs.xcode }}
- run: |
- swift package dump-pif > /dev/null
- ATTEMPT=0
- while [ -z "${SUCCESS}" ] && [ "${ATTEMPT}" -le 5 ]; do
- xcodebuild clean -scheme "${XCODE_SCHEME}" -destination "${DESTINATION}" | grep -q "CLEAN SUCCEEDED" && SUCCESS=true
- ATTEMPT=$((ATTEMPT + 1))
- done
- # END PIF ISSUES
- - uses: actions/cache@v3
- with:
- path: .derived-data
- key: ${{ runner.os }}-${{ steps.os-version.outputs.version }}-xcode-${{ steps.swift-version.outputs.version }}-${{ matrix.platform }}-${{ hashFiles('**/Package.resolved') }}
- restore-keys: |
- ${{ runner.os }}-${{ steps.os-version.outputs.version }}-xcode-${{ steps.swift-version.outputs.version }}-${{ matrix.platform }}-
- - uses: sersoft-gmbh/xcodebuild-action@v3
- with:
- spm-package: './'
- scheme: ${{ env.XCODE_SCHEME }}
- destination: ${{ steps.destination.outputs.xcode }}
- action: test
- parallel-testing-enabled: ${{ matrix.platform != 'watchOS' }}
- enable-code-coverage: true
- derived-data-path: .derived-data
- - uses: sersoft-gmbh/swift-coverage-action@v4
- id: coverage-files
- with:
- search-paths: |
- ./.build
- ./.derived-data
- $HOME/Library/Developer/Xcode/DerivedData
- - uses: codecov/codecov-action@v3
- with:
- token: ${{ secrets.CODECOV_TOKEN }}
- files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }}
- fail_ci_if_error: true
+ swift-version-offset: [ 0 ]
+ uses: sersoft-gmbh/oss-common-actions/.github/workflows/swift-test-xcode.yml@main
+ with:
+ xcode-scheme: ${{ needs.variables.outputs.xcode-scheme }}
+ max-swift-version: ${{ needs.variables.outputs.max-supported-swift-version }}
+ swift-version-offset: ${{ matrix.swift-version-offset }}
+ platform: ${{ matrix.platform }}
+ platform-version: ${{ needs.variables.outputs.xcode-platform-version }}
+ fail-if-codecov-fails: ${{ fromJson(needs.variables.outputs.fail-if-codecov-fails) }}
+ secrets:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.gitignore b/.gitignore
index d98efc24..13bc1d56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,23 @@
.DS_Store
+
/.build
-/.swiftpm
/Packages
-/*.xcodeproj
-*.xcuserdatad
+xcuserdata/
+DerivedData/
+.swiftpm/configuration/registries.json
+.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+.netrc
+
+# VS Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/FFFoundation.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/FFFoundation.xcscheme
new file mode 100644
index 00000000..7d7743b0
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/FFFoundation.xcscheme
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Package.resolved b/Package.resolved
new file mode 100644
index 00000000..e65252d0
--- /dev/null
+++ b/Package.resolved
@@ -0,0 +1,23 @@
+{
+ "pins" : [
+ {
+ "identity" : "swift-docc-plugin",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-docc-plugin",
+ "state" : {
+ "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247",
+ "version" : "1.3.0"
+ }
+ },
+ {
+ "identity" : "swift-docc-symbolkit",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-docc-symbolkit",
+ "state" : {
+ "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
+ "version" : "1.0.0"
+ }
+ }
+ ],
+ "version" : 2
+}
diff --git a/Package.swift b/Package.swift
index fc3528a2..53f55a57 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,30 +1,41 @@
-// swift-tools-version:5.7
+// swift-tools-version:5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
-import Foundation
+
+let swiftSettings: Array = [
+ .enableUpcomingFeature("ConciseMagicFile"),
+ .enableUpcomingFeature("ExistentialAny"),
+ .enableUpcomingFeature("BareSlashRegexLiterals"),
+ .enableUpcomingFeature("DisableOutwardActorInference"),
+ .enableExperimentalFeature("AccessLevelOnImport"),
+ // .enableExperimentalFeature("VariadicGenerics"),
+ // .unsafeFlags(["-warn-concurrency"], .when(configuration: .debug)),
+]
let package = Package(
name: "FFFoundation",
platforms: [
- .macOS(.v10_13),
- .iOS(.v11),
- .tvOS(.v11),
- .watchOS(.v4),
+ .macOS(.v10_13),
+ .iOS(.v12),
+ .tvOS(.v12),
+ .watchOS(.v4),
],
products: [
- // Products define the executables and libraries produced by a package, and make them visible to other packages.
- .library(name: "FFFoundation",
- targets: ["FFFoundation"]),
- ],
- targets: [
- .target(name: "FFFoundation"),
- .testTarget(
- name: "FFFoundationTests",
- dependencies: ["FFFoundation"]),
- ]
+ // Products define the executables and libraries produced by a package, and make them visible to other packages.
+ .library(name: "FFFoundation",
+ targets: ["FFFoundation"]),
+ ],
+ dependencies: [
+ .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
+ ],
+ targets: [
+ .target(
+ name: "FFFoundation",
+ swiftSettings: swiftSettings),
+ .testTarget(
+ name: "FFFoundationTests",
+ dependencies: ["FFFoundation"],
+ swiftSettings: swiftSettings),
+ ]
)
-
-if ProcessInfo.processInfo.environment["ENABLE_DOCC_SUPPORT"] == "1" {
- package.dependencies.append(.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"))
-}
diff --git a/Package@swift-5.6.swift b/Package@swift-5.6.swift
deleted file mode 100644
index bdc73354..00000000
--- a/Package@swift-5.6.swift
+++ /dev/null
@@ -1,29 +0,0 @@
-// swift-tools-version:5.6
-// The swift-tools-version declares the minimum version of Swift required to build this package.
-
-import PackageDescription
-import Foundation
-
-let package = Package(
- name: "FFFoundation",
- platforms: [
- .macOS(.v10_12),
- .iOS(.v10),
- .tvOS(.v10),
- .watchOS(.v3),
- ],
- products: [
- // Products define the executables and libraries produced by a package, and make them visible to other packages.
- .library(name: "FFFoundation", targets: ["FFFoundation"]),
- ],
- targets: [
- .target(name: "FFFoundation"),
- .testTarget(
- name: "FFFoundationTests",
- dependencies: ["FFFoundation"]),
- ]
-)
-
-if ProcessInfo.processInfo.environment["ENABLE_DOCC_SUPPORT"] == "1" {
- package.dependencies.append(.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"))
-}
diff --git a/Sources/FFFoundation/CacheManager.swift b/Sources/FFFoundation/CacheManager.swift
index 062995a8..15a4fb7d 100644
--- a/Sources/FFFoundation/CacheManager.swift
+++ b/Sources/FFFoundation/CacheManager.swift
@@ -56,7 +56,7 @@ public final class CacheManager {
}
@Synchronized
- private var memoryCache: [ObjectIdentification: Object] = [:]
+ private var memoryCache: Dictionary = .init()
public init(name: Name = .default, shouldMigrateFromOldNamingBehavior: Bool = true) throws {
self.name = name
@@ -65,8 +65,8 @@ public final class CacheManager {
let baseFolder = try CacheManager.cacheFolder(in: fileManager)
let folder = baseFolder.appendingPathComponent(name.rawValue).appendingPathComponent("\(Object.self)")
if shouldMigrateFromOldNamingBehavior,
- case let oldPath = baseFolder.appendingPathComponent(name.rawValue + "\(Object.self)"),
- fileManager.directoryExists(at: oldPath) {
+ case let oldPath = baseFolder.appendingPathComponent(name.rawValue + "\(Object.self)"),
+ fileManager.directoryExists(at: oldPath) {
try fileManager.moveItem(at: oldPath, to: folder)
}
try fileManager.createDirectoryIfNeeded(at: folder)
@@ -75,16 +75,16 @@ public final class CacheManager {
}
// MARK: - Memory warnings
- private var memoryWarningsObserver: NSObjectProtocol?
+ private var memoryWarningsObserver: (any NSObjectProtocol)?
private func registerForMemoryWarnings() {
- #if canImport(UIKit) && !os(watchOS)
- let opQueue = OperationQueue()
- opQueue.underlyingQueue = queue
- let name = UIApplication.didReceiveMemoryWarningNotification
- memoryWarningsObserver = NotificationCenter.default.addObserver(forName: name, object: nil, queue: opQueue) { [weak self] _ in
- self?.clearMemoryCache()
- }
- #endif
+#if canImport(UIKit) && !os(watchOS)
+ let opQueue = OperationQueue()
+ opQueue.underlyingQueue = queue
+ let name = UIApplication.didReceiveMemoryWarningNotification
+ memoryWarningsObserver = NotificationCenter.default.addObserver(forName: name, object: nil, queue: opQueue) { [weak self] _ in
+ self?.clearMemoryCache()
+ }
+#endif
}
// MARK: - Private helpers
@@ -161,17 +161,21 @@ extension CacheManager {
}
extension CacheManager {
+ @frozen
public struct Name: RawRepresentable {
public typealias RawValue = String
public let rawValue: RawValue
- public init(rawValue: RawValue) { self.rawValue = rawValue }
+
+ public init(rawValue: RawValue) {
+ self.rawValue = rawValue
+ }
}
}
public enum CachingError: Error, CustomStringConvertible {
- case couldNotSerialize(underlyingError: Error?)
- case couldNotDeserialize(underlyingError: Error?)
+ case couldNotSerialize(underlyingError: (any Error)?)
+ case couldNotDeserialize(underlyingError: (any Error)?)
public var description: String {
switch self {
@@ -198,30 +202,30 @@ extension String: Cachable {
}
#if canImport(UIKit)
- extension UIImage: Cachable {
- public func cacheData() throws -> Data {
- guard let data = jpegData(compressionQuality: 0.95) else { throw CachingError.couldNotSerialize(underlyingError: nil) }
- return data
- }
+extension UIImage: Cachable {
+ public func cacheData() throws -> Data {
+ guard let data = jpegData(compressionQuality: 0.95) else { throw CachingError.couldNotSerialize(underlyingError: nil) }
+ return data
+ }
- public static func fromCache(data: Data) throws -> Self {
- guard let img = self.init(data: data) else { throw CachingError.couldNotDeserialize(underlyingError: nil) }
- return img
- }
+ public static func fromCache(data: Data) throws -> Self {
+ guard let img = self.init(data: data) else { throw CachingError.couldNotDeserialize(underlyingError: nil) }
+ return img
}
+}
#endif
#if canImport(AppKit) && !os(iOS) // macCatalyst has os(iOS)
- import AppKit
- extension NSImage: Cachable {
- public func cacheData() throws -> Data {
- guard let data = tiffRepresentation else { throw CachingError.couldNotSerialize(underlyingError: nil) }
- return data
- }
+import AppKit
+extension NSImage: Cachable {
+ public func cacheData() throws -> Data {
+ guard let data = tiffRepresentation else { throw CachingError.couldNotSerialize(underlyingError: nil) }
+ return data
+ }
- public static func fromCache(data: Data) throws -> Self {
- guard let img = self.init(data: data) else { throw CachingError.couldNotDeserialize(underlyingError: nil) }
- return img
- }
+ public static func fromCache(data: Data) throws -> Self {
+ guard let img = self.init(data: data) else { throw CachingError.couldNotDeserialize(underlyingError: nil) }
+ return img
}
+}
#endif
diff --git a/Sources/FFFoundation/Containers/CoW.swift b/Sources/FFFoundation/Containers/CoW.swift
index f162abf1..2b6cd287 100644
--- a/Sources/FFFoundation/Containers/CoW.swift
+++ b/Sources/FFFoundation/Containers/CoW.swift
@@ -86,13 +86,13 @@ extension CoW: Comparable where Value: Comparable {
}
extension CoW: Encodable where Value: Encodable {
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
try wrappedValue.encode(to: encoder)
}
}
extension CoW: Decodable where Value: Decodable, Value: Copyable {
- public init(from decoder: Decoder) throws {
+ public init(from decoder: any Decoder) throws {
try self.init(wrappedValue: Value(from: decoder))
}
}
diff --git a/Sources/FFFoundation/Containers/Lazy.swift b/Sources/FFFoundation/Containers/Lazy.swift
index 20a122f0..40137a73 100644
--- a/Sources/FFFoundation/Containers/Lazy.swift
+++ b/Sources/FFFoundation/Containers/Lazy.swift
@@ -80,13 +80,13 @@ extension Lazy: Comparable where Deferred: Comparable {
}
extension Lazy: Encodable where Deferred: Encodable {
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
try wrappedValue.encode(to: encoder)
}
}
extension Lazy: Decodable where Deferred: Decodable {
- public init(from decoder: Decoder) throws {
+ public init(from decoder: any Decoder) throws {
let value = try Deferred(from: decoder)
self.init(wrappedValue: value)
}
diff --git a/Sources/FFFoundation/Containers/Ref.swift b/Sources/FFFoundation/Containers/Ref.swift
index f269d559..acbc0b11 100644
--- a/Sources/FFFoundation/Containers/Ref.swift
+++ b/Sources/FFFoundation/Containers/Ref.swift
@@ -62,13 +62,13 @@ extension Ref: Comparable where Referenced: Comparable {
}
extension Ref: Encodable where Referenced: Encodable {
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
try wrappedValue.encode(to: encoder)
}
}
extension Ref: Decodable where Referenced: Decodable {
- public convenience init(from decoder: Decoder) throws {
+ public convenience init(from decoder: any Decoder) throws {
let value = try Referenced(from: decoder)
self.init(wrappedValue: value)
}
diff --git a/Sources/FFFoundation/Containers/Synchronized.swift b/Sources/FFFoundation/Containers/Synchronized.swift
index 94a40c9f..978c3b64 100644
--- a/Sources/FFFoundation/Containers/Synchronized.swift
+++ b/Sources/FFFoundation/Containers/Synchronized.swift
@@ -116,13 +116,13 @@ extension Synchronized: Comparable where Guarded: Comparable {
}
extension Synchronized: Encodable where Guarded: Encodable {
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
try wrappedValue.encode(to: encoder)
}
}
extension Synchronized: Decodable where Guarded: Decodable {
- public convenience init(from decoder: Decoder) throws {
+ public convenience init(from decoder: any Decoder) throws {
try self.init(wrappedValue: Guarded(from: decoder))
}
}
diff --git a/Sources/FFFoundation/Containers/Weak.swift b/Sources/FFFoundation/Containers/Weak.swift
index 77e8ea81..fd04fcee 100644
--- a/Sources/FFFoundation/Containers/Weak.swift
+++ b/Sources/FFFoundation/Containers/Weak.swift
@@ -79,13 +79,13 @@ extension Weak: Hashable where Object: Hashable {
//}
extension Weak: Encodable where Object: Encodable {
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
try wrappedValue.encode(to: encoder)
}
}
extension Weak: Decodable where Object: Decodable {
- public init(from decoder: Decoder) throws {
+ public init(from decoder: any Decoder) throws {
try self.init(object: Object(from: decoder))
}
}
diff --git a/Sources/FFFoundation/Diff.swift b/Sources/FFFoundation/Diff.swift
index b2d2ea8c..6904a6d1 100644
--- a/Sources/FFFoundation/Diff.swift
+++ b/Sources/FFFoundation/Diff.swift
@@ -83,7 +83,7 @@ fileprivate extension Diff {
}
extension Diff: Encodable where Subject: Encodable, Element: Encodable {
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(base, forKey: .base)
try container.encode(head, forKey: .head)
@@ -97,7 +97,7 @@ extension Diff: Encodable where Subject: Encodable, Element: Encodable {
}
extension Diff: Decodable where Subject: Decodable, Element: Decodable {
- public init(from decoder: Decoder) throws {
+ public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
base = try container.decode(Subject.self, forKey: .base)
head = try container.decode(Subject.self, forKey: .head)
@@ -139,7 +139,7 @@ extension Diff {
"\(lineSign)\(element)\n"
}
- public init(from decoder: Decoder) throws {
+ public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
switch try container.decode(String.self) {
case "unchanged": self = .unchanged
@@ -151,7 +151,7 @@ extension Diff {
}
}
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .unchanged: try container.encode("unchanged")
diff --git a/Sources/FFFoundation/GCDFuture.swift b/Sources/FFFoundation/GCDFuture.swift
index d79844e0..ef032113 100644
--- a/Sources/FFFoundation/GCDFuture.swift
+++ b/Sources/FFFoundation/GCDFuture.swift
@@ -101,7 +101,7 @@ public final class GCDFuture: @unchecked Sendable {
}
@inlinable
- public func map(_ transformer: @escaping (Value) throws -> T) -> GCDFutureResult {
+ public func map(_ transformer: @escaping (Value) throws -> T) -> GCDFutureResult {
map { val in Result { try transformer(val) } }
}
@@ -111,10 +111,10 @@ public final class GCDFuture: @unchecked Sendable {
return future
}
- public func flatMap(_ transformer: @escaping (Value) throws -> GCDFuture) -> GCDFutureResult {
+ public func flatMap(_ transformer: @escaping (Value) throws -> GCDFuture) -> GCDFutureResult {
flatMap { [workerQueue] in
do { return try transformer($0).map { .success($0) } }
- catch { return GCDFutureResult(queue: workerQueue, value: .failure(error)) }
+ catch { return GCDFutureResult(queue: workerQueue, value: .failure(error)) }
}
}
@@ -167,7 +167,7 @@ extension GCDFutureResult {
@discardableResult
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
public func complete(with task: @escaping @Sendable () async throws -> Success) -> Task
- where Value == Result
+ where Value == Result
{
Task {
do {
@@ -202,16 +202,16 @@ extension GCDFutureResult {
}
@inlinable
- public func map(_ transformer: @escaping (Success) throws -> T) -> GCDFutureResult
+ public func map(_ transformer: @escaping (Success) throws -> T) -> GCDFutureResult
where Value == Result
{
map { val in try transformer(val.get()) }
}
- public func flatMap(_ transformer: @escaping (Success) throws -> GCDFutureResult) -> GCDFutureResult
- where Value == Result
+ public func flatMap(_ transformer: @escaping (Success) throws -> GCDFutureResult) -> GCDFutureResult
+ where Value == Result
{
- let future = GCDFutureResult(queue: workerQueue)
+ let future = GCDFutureResult(queue: workerQueue)
whenDone {
do {
try transformer($0.get()).cascade(other: future)
@@ -245,8 +245,8 @@ extension DispatchQueue {
return future
}
- public final func asFuture(do work: @escaping () throws -> T) -> GCDFutureResult {
- let future = GCDFutureResult(queue: self)
+ public final func asFuture(do work: @escaping () throws -> T) -> GCDFutureResult {
+ let future = GCDFutureResult(queue: self)
self.async { future.complete(with: Result { try work() }) }
return future
}
diff --git a/Sources/FFFoundation/Geometry/Angle.swift b/Sources/FFFoundation/Geometry/Angle.swift
index 46a82671..c19679f0 100644
--- a/Sources/FFFoundation/Geometry/Angle.swift
+++ b/Sources/FFFoundation/Geometry/Angle.swift
@@ -238,7 +238,7 @@ fileprivate extension Angle {
extension Angle: Sendable where Value: Sendable {}
extension Angle: Encodable where Value: Encodable {
- public func encode(to encoder: Encoder) throws {
+ public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch kind {
case .degrees: try container.encode("degrees", forKey: .kind)
@@ -249,7 +249,7 @@ extension Angle: Encodable where Value: Encodable {
}
extension Angle: Decodable where Value: Decodable {
- public init(from decoder: Decoder) throws {
+ public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
switch try container.decode(String.self, forKey: .kind) {
case "degrees":
diff --git a/Tests/FFFoundationTests/TypeDescriptionTests.swift b/Tests/FFFoundationTests/TypeDescriptionTests.swift
index 844f2fde..732ce6ba 100644
--- a/Tests/FFFoundationTests/TypeDescriptionTests.swift
+++ b/Tests/FFFoundationTests/TypeDescriptionTests.swift
@@ -3,7 +3,7 @@ import XCTest
protocol GenericTestType {
static var typeName: String { get }
- static var genericParams: [GenericTestType.Type] { get }
+ static var genericParams: Array { get }
}
fileprivate extension GenericTestType {
@@ -11,13 +11,13 @@ fileprivate extension GenericTestType {
return typeName.firstIndex(of: ".").map { String(typeName[typeName.index(after: $0)...]) } ?? typeName
}
- static func fullTypeName(basedOn namePath: (GenericTestType.Type) -> String) -> String {
+ static func fullTypeName(basedOn namePath: (any GenericTestType.Type) -> String) -> String {
return namePath(self) + (genericParams.isEmpty ? "" : "<" + genericParams.map { $0.fullTypeName(basedOn: namePath) }.joined(separator: ", ") + ">")
}
}
private func _XCTAssertEqual(_ desc: TypeDescription, _ testType: TestType.Type, _ message: @autoclosure () -> String, file: StaticString, line: UInt) {
- func assertEqual(_ desc: TypeDescription, _ testType: GenericTestType.Type, _ message: @autoclosure () -> String, recursionIndexPath: IndexPath) {
+ func assertEqual(_ desc: TypeDescription, _ testType: any GenericTestType.Type, _ message: @autoclosure () -> String, recursionIndexPath: IndexPath) {
func extendedMessage(for message: @autoclosure () -> String) -> String {
return recursionIndexPath.isEmpty
? message()
@@ -34,19 +34,13 @@ private func _XCTAssertEqual(_ desc: TypeDescription,
assertEqual(desc, testType, message(), recursionIndexPath: [])
}
-#if swift(>=5.3)
func XCTAssertEqual(_ desc: TypeDescription, _ testType: TestType.Type, _ message: @autoclosure () -> String = "", file: StaticString = #filePath, line: UInt = #line) {
_XCTAssertEqual(desc, testType, message(), file: file, line: line)
}
-#else
-func XCTAssertEqual(_ desc: TypeDescription, _ testType: TestType.Type, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
- _XCTAssertEqual(desc, testType, message(), file: file, line: line)
-}
-#endif
extension String: GenericTestType {
static let typeName = "Swift.String"
- static let genericParams: [GenericTestType.Type] = []
+ static let genericParams: Array = []
}
final class TypeDescriptionTests: XCTestCase {
@@ -56,19 +50,19 @@ final class TypeDescriptionTests: XCTestCase {
struct NonGeneric: GenericTestType {
static let typeName = "\(TypeDescriptionTests.typePrefix).NonGeneric"
- static let genericParams: [GenericTestType.Type] = []
+ static let genericParams: Array = []
}
struct OneGeneric: GenericTestType {
static var typeName: String { return "\(TypeDescriptionTests.typePrefix).OneGeneric" }
- static var genericParams: [GenericTestType.Type] { return [T.self] }
+ static var genericParams: Array { return [T.self] }
}
struct TwoGeneric: GenericTestType {
static var typeName: String { return "\(TypeDescriptionTests.typePrefix).TwoGeneric" }
- static var genericParams: [GenericTestType.Type] { return [T.self, U.self] }
+ static var genericParams: Array { return [T.self, U.self] }
}
struct ThreeGeneric: GenericTestType {
static var typeName: String { return "\(TypeDescriptionTests.typePrefix).ThreeGeneric" }
- static var genericParams: [GenericTestType.Type] { return [T.self, U.self, V.self] }
+ static var genericParams: Array { return [T.self, U.self, V.self] }
}
override func setUp() {