@@ -18,8 +18,6 @@ import FoundationEssentials
18
18
public struct IntegerParseStrategy < Format> : Codable , Hashable where Format : FormatStyle , Format. FormatInput : BinaryInteger {
19
19
public var formatStyle : Format
20
20
public var lenient : Bool
21
- var numberFormatType : ICULegacyNumberFormatter . NumberFormatType
22
- var locale : Locale
23
21
}
24
22
25
23
@available ( macOS 12 . 0 , iOS 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
@@ -28,51 +26,63 @@ extension IntegerParseStrategy : Sendable where Format : Sendable {}
28
26
@available ( macOS 12 . 0 , iOS 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
29
27
extension IntegerParseStrategy : ParseStrategy {
30
28
public func parse( _ value: String ) throws -> Format . FormatInput {
31
- guard let parser = ICULegacyNumberFormatter . formatter ( for: numberFormatType, locale: locale, lenient: lenient) else {
32
- throw CocoaError ( CocoaError . formatting, userInfo: [
33
- NSDebugDescriptionErrorKey: " Cannot parse \( value) . Could not create parser. " ] )
34
- }
35
29
let trimmedString = value. _trimmingWhitespace ( )
36
- if let v = parser. parseAsInt ( trimmedString) {
37
- guard let exact = Format . FormatInput ( exactly: v) else {
38
- throw CocoaError ( CocoaError . formatting, userInfo: [
39
- NSDebugDescriptionErrorKey: " Cannot parse \( value) . The number does not fall within the valid bounds of the specified output type " ] )
40
- }
41
- return exact
42
- } else if let v = parser. parseAsDouble ( trimmedString) {
43
- guard v. magnitude < Double ( sign: . plus, exponent: Double . significandBitCount + 1 , significand: 1 ) else {
44
- throw CocoaError ( CocoaError . formatting, userInfo: [
45
- NSDebugDescriptionErrorKey: " Cannot parse \( value) . The number does not fall within the lossless floating-point range " ] )
46
- }
47
- guard let exact = Format . FormatInput ( exactly: v) else {
48
- throw CocoaError ( CocoaError . formatting, userInfo: [
49
- NSDebugDescriptionErrorKey: " Cannot parse \( value) . The number does not fall within the valid bounds of the specified output type " ] )
50
- }
51
- return exact
52
- } else {
30
+ guard let result = try parse ( trimmedString, startingAt: trimmedString. startIndex, in: trimmedString. startIndex..< trimmedString. endIndex) else {
53
31
let exampleString = formatStyle. format ( 123 )
54
32
throw CocoaError ( CocoaError . formatting, userInfo: [
55
33
NSDebugDescriptionErrorKey: " Cannot parse \( value) . String should adhere to the specified format, such as \( exampleString) " ] )
56
34
}
35
+ return result. 1
57
36
}
58
37
59
- internal func parse( _ value: String , startingAt index: String . Index , in range: Range < String . Index > ) -> ( String . Index , Format . FormatInput ) ? {
38
+ internal func parse( _ value: String , startingAt index: String . Index , in range: Range < String . Index > ) throws -> ( String . Index , Format . FormatInput ) ? {
60
39
guard index < range. upperBound else {
61
40
return nil
62
41
}
63
42
43
+ let numberFormatType : ICULegacyNumberFormatter . NumberFormatType
44
+ let locale : Locale
45
+
46
+ if let format = formatStyle as? IntegerFormatStyle < Format . FormatInput > {
47
+ numberFormatType = . number( format. collection)
48
+ locale = format. locale
49
+ } else if let format = formatStyle as? IntegerFormatStyle < Format . FormatInput > . Percent {
50
+ numberFormatType = . percent( format. collection)
51
+ locale = format. locale
52
+ } else if let format = formatStyle as? IntegerFormatStyle < Format . FormatInput > . Currency {
53
+ numberFormatType = . currency( format. collection, currencyCode: format. currencyCode)
54
+ locale = format. locale
55
+ } else {
56
+ // For some reason we've managed to accept a format style of a type that we don't own, which shouldn't happen. Fallback to the default decimal style and try anyways.
57
+ numberFormatType = . number( . init( ) )
58
+ locale = . autoupdatingCurrent
59
+ }
60
+
64
61
guard let parser = ICULegacyNumberFormatter . formatter ( for: numberFormatType, locale: locale, lenient: lenient) else {
65
62
return nil
66
63
}
67
64
let substr = value [ index..< range. upperBound]
68
65
var upperBound = 0
69
66
if let value = parser. parseAsInt ( substr, upperBound: & upperBound) {
67
+ guard let exact = Format . FormatInput ( exactly: value) else {
68
+ throw CocoaError ( CocoaError . formatting, userInfo: [
69
+ NSDebugDescriptionErrorKey: " Cannot parse \( value) . The number does not fall within the valid bounds of the specified output type " ] )
70
+ }
70
71
let upperBoundInSubstr = String . Index ( utf16Offset: upperBound, in: substr)
71
- return ( upperBoundInSubstr, Format . FormatInput ( value) )
72
- } else if let value = parser. parseAsInt ( substr, upperBound: & upperBound) {
72
+ return ( upperBoundInSubstr, exact)
73
+ } else if let value = parser. parseAsDouble ( substr, upperBound: & upperBound) {
74
+ guard value. magnitude < Double ( sign: . plus, exponent: Double . significandBitCount + 1 , significand: 1 ) else {
75
+ throw CocoaError ( CocoaError . formatting, userInfo: [
76
+ NSDebugDescriptionErrorKey: " Cannot parse \( value) . The number does not fall within the lossless floating-point range " ] )
77
+ }
78
+ guard let exact = Format . FormatInput ( exactly: value) else {
79
+ throw CocoaError ( CocoaError . formatting, userInfo: [
80
+ NSDebugDescriptionErrorKey: " Cannot parse \( value) . The number does not fall within the valid bounds of the specified output type " ] )
81
+ }
73
82
let upperBoundInSubstr = String . Index ( utf16Offset: upperBound, in: substr)
74
- return ( upperBoundInSubstr, Format . FormatInput ( clamping : Int64 ( value ) ) )
83
+ return ( upperBoundInSubstr, exact )
75
84
}
85
+
76
86
return nil
77
87
}
78
88
}
@@ -82,8 +92,6 @@ public extension IntegerParseStrategy {
82
92
init < Value> ( format: Format , lenient: Bool = true ) where Format == IntegerFormatStyle < Value > {
83
93
self . formatStyle = format
84
94
self . lenient = lenient
85
- self . locale = format. locale
86
- self . numberFormatType = . number( format. collection)
87
95
}
88
96
}
89
97
@@ -92,8 +100,6 @@ public extension IntegerParseStrategy {
92
100
init < Value> ( format: Format , lenient: Bool = true ) where Format == IntegerFormatStyle < Value > . Percent {
93
101
self . formatStyle = format
94
102
self . lenient = lenient
95
- self . locale = format. locale
96
- self . numberFormatType = . percent( format. collection)
97
103
}
98
104
}
99
105
@@ -102,7 +108,5 @@ public extension IntegerParseStrategy {
102
108
init < Value> ( format: Format , lenient: Bool = true ) where Format == IntegerFormatStyle < Value > . Currency {
103
109
self . formatStyle = format
104
110
self . lenient = lenient
105
- self . locale = format. locale
106
- self . numberFormatType = . currency( format. collection)
107
111
}
108
112
}
0 commit comments