1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if canImport(FoundationEssentials)
import FoundationEssentials
#endif
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public struct FloatingPointParseStrategy<Format> : Codable, Hashable where Format : FormatStyle, Format.FormatInput : BinaryFloatingPoint {
public var formatStyle: Format
public var lenient: Bool
var numberFormatType: ICULegacyNumberFormatter.NumberFormatType
var locale: Locale
}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension FloatingPointParseStrategy : Sendable where Format : Sendable {}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension FloatingPointParseStrategy: ParseStrategy {
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public func parse(_ value: String) throws -> Format.FormatInput {
guard let parser = ICULegacyNumberFormatter.formatter(for: numberFormatType, locale: locale, lenient: lenient) else {
throw CocoaError(CocoaError.formatting, userInfo: [
NSDebugDescriptionErrorKey: "Cannot parse \(value), unable to create formatter" ])
}
if let v = parser.parseAsDouble(value._trimmingWhitespace()) {
return Format.FormatInput(v)
} else {
let exampleString = formatStyle.format(3.14)
throw CocoaError(CocoaError.formatting, userInfo: [
NSDebugDescriptionErrorKey: "Cannot parse \(value). String should adhere to the specified format, such as \(exampleString)" ])
}
}
// Regex component utility
internal func parse(_ value: String, startingAt index: String.Index, in range: Range<String.Index>) -> (String.Index, Format.FormatInput)? {
guard index < range.upperBound else {
return nil
}
guard let parser = ICULegacyNumberFormatter.formatter(for: numberFormatType, locale: locale, lenient: lenient) else {
return nil
}
let substr = value[index..<range.upperBound]
var upperBound = 0
if let value = parser.parseAsDouble(substr, upperBound: &upperBound) {
let upperBoundInSubstr = String.Index(utf16Offset: upperBound, in: substr)
return (upperBoundInSubstr, Format.FormatInput(value))
} else {
return nil
}
}
}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public extension FloatingPointParseStrategy {
init<Value>(format: Format, lenient: Bool = true) where Format == FloatingPointFormatStyle<Value> {
self.formatStyle = format
self.lenient = lenient
self.locale = format.locale
self.numberFormatType = .number(format.collection)
}
}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public extension FloatingPointParseStrategy {
init<Value>(format: Format, lenient: Bool = true) where Format == FloatingPointFormatStyle<Value>.Currency {
self.formatStyle = format
self.lenient = lenient
self.locale = format.locale
self.numberFormatType = .currency(format.collection)
}
}
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public extension FloatingPointParseStrategy {
init<Value>(format: Format, lenient: Bool = true) where Format == FloatingPointFormatStyle<Value>.Percent {
self.formatStyle = format
self.lenient = lenient
self.locale = format.locale
self.numberFormatType = .percent(format.collection)
}
}
|