diff --git a/Package.swift b/Package.swift index 748ab63..5b9615c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.7 +// swift-tools-version: 5.8 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Package@swift-5.7.swift b/Package@swift-5.7.swift new file mode 100644 index 0000000..748ab63 --- /dev/null +++ b/Package@swift-5.7.swift @@ -0,0 +1,59 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription +import Foundation + +let package = Package( + name: "simple-formatting", + products: [ + .library(name: "DurationFormatting", + targets: ["DurationFormatting"]), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .systemLibrary( + name: "CICUCommon", + pkgConfig: "icu-uc", + providers: [ + .apt(["libicu-dev"]), + .brew(["icu4c"]), + ]), + .systemLibrary( + name: "CICUI18N", + pkgConfig: "icu-i18n", + providers: [ + .apt(["libicu-dev"]), + .brew(["icu4c"]), + ]), + .systemLibrary( + name: "CICUIO", + pkgConfig: "icu-io", + providers: [ + .apt(["libicu-dev"]), + .brew(["icu4c"]), + ]), + .target( + name: "CICUShims", + dependencies: [ + "CICUCommon", + "CICUI18N", +// "CICUIO", + ]), + .target( + name: "DurationFormatting", + dependencies: ["CICUShims"]), + .testTarget( + name: "DurationFormattingTests", + dependencies: [ + "CICUShims", + "DurationFormatting", + ]), + ], + cxxLanguageStandard: .cxx14 +) + +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/DurationFormatting/DurationFormatter.swift b/Sources/DurationFormatting/DurationFormatter.swift index 3d90b61..fb2c1e2 100644 --- a/Sources/DurationFormatting/DurationFormatter.swift +++ b/Sources/DurationFormatting/DurationFormatter.swift @@ -1,41 +1,12 @@ +#if swift(>=5.7) && canImport(Darwin) import Foundation +#else +@preconcurrency import Foundation +#endif @_implementationOnly import CICUShims -public struct TimeComponents: Sendable { - public var hour: Int? - public var minute: Int? - public var second: Int? - - @inlinable - public var dateComponents: DateComponents { - .init(hour: hour, minute: minute, second: second) - } - - public init(hour: Int? = nil, minute: Int? = nil, second: Int? = nil) { - self.hour = hour - self.minute = minute - self.second = second - } - - @inlinable - public init(dateComponents: DateComponents) { - self.init(hour: dateComponents.hour, - minute: dateComponents.minute, - second: dateComponents.second) - } - - fileprivate func _cicuTimeComponents(nullingZeros: Bool) -> CICUTimeComponents { - func _component(for value: Int?) -> CICUTimeComponent { - value.map(numericCast).map(nullingZeros ? CICUTimeComponent.init(nullingZeroOf:) : CICUTimeComponent.init(_:)) ?? .null - } - return .init(hours: _component(for: hour), - minutes: _component(for: minute), - seconds: _component(for: second)) - } -} - -public struct DurationFormatter { - public enum Width: Sendable { +public struct DurationFormatter: Sendable { + public enum Width: Sendable, Hashable { case numeric, short, narrow fileprivate var _cicuFormatWidth: CICUDurationFormatWidth { diff --git a/Sources/DurationFormatting/TimeComponents.swift b/Sources/DurationFormatting/TimeComponents.swift new file mode 100644 index 0000000..4e44204 --- /dev/null +++ b/Sources/DurationFormatting/TimeComponents.swift @@ -0,0 +1,56 @@ +import Foundation +@_implementationOnly import CICUShims + +fileprivate extension CICUTimeComponent { + func value(droppingZero dropZero: Bool) -> Int? { + isNull || (dropZero && value == .zero) ? nil : numericCast(value) + } +} + +public struct TimeComponents: Hashable, Comparable, Sendable { + public var hour: Int? + public var minute: Int? + public var second: Int? + + @inlinable + public var dateComponents: DateComponents { + .init(hour: hour, minute: minute, second: second) + } + + public init(hour: Int? = nil, + minute: Int? = nil, + second: Int? = nil) { + self.hour = hour + self.minute = minute + self.second = second + } + + @inlinable + public init(dateComponents: DateComponents) { + self.init(hour: dateComponents.hour, + minute: dateComponents.minute, + second: dateComponents.second) + } + + init(_cicuTimeComponents timeComponents: CICUTimeComponents, dropZeros: Bool) { + self.init(hour: timeComponents.hours.value(droppingZero: dropZeros), + minute: timeComponents.minutes.value(droppingZero: dropZeros), + second: timeComponents.seconds.value(droppingZero: dropZeros)) + } + + func _cicuTimeComponents(nullingZeros: Bool) -> CICUTimeComponents { + func _component(for value: Int?) -> CICUTimeComponent { + value.map(numericCast).map(nullingZeros ? CICUTimeComponent.init(nullingZeroOf:) : CICUTimeComponent.init(_:)) ?? .null + } + return .init(hours: _component(for: hour), + minutes: _component(for: minute), + seconds: _component(for: second)) + } + + public static func <(lhs: Self, rhs: Self) -> Bool { + guard lhs != rhs else { return false } + return (lhs.hour ?? 0, lhs.minute ?? 0, lhs.second ?? 0) + < + (rhs.hour ?? 0, rhs.minute ?? 0, rhs.second ?? 0) + } +}