@@ -18,8 +18,6 @@ import FoundationEssentials
1818public struct IntegerParseStrategy < Format> : Codable , Hashable where Format : FormatStyle , Format. FormatInput : BinaryInteger {
1919 public var formatStyle : Format
2020 public var lenient : Bool
21- var numberFormatType : ICULegacyNumberFormatter . NumberFormatType
22- var locale : Locale
2321}
2422
2523@available ( macOS 12 . 0 , iOS 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
@@ -28,51 +26,63 @@ extension IntegerParseStrategy : Sendable where Format : Sendable {}
2826@available ( macOS 12 . 0 , iOS 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
2927extension IntegerParseStrategy : ParseStrategy {
3028 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- }
3529 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 {
5331 let exampleString = formatStyle. format ( 123 )
5432 throw CocoaError ( CocoaError . formatting, userInfo: [
5533 NSDebugDescriptionErrorKey: " Cannot parse \( value) . String should adhere to the specified format, such as \( exampleString) " ] )
5634 }
35+ return result. 1
5736 }
5837
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 ) ? {
6039 guard index < range. upperBound else {
6140 return nil
6241 }
6342
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+
6461 guard let parser = ICULegacyNumberFormatter . formatter ( for: numberFormatType, locale: locale, lenient: lenient) else {
6562 return nil
6663 }
6764 let substr = value [ index..< range. upperBound]
6865 var upperBound = 0
6966 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+ }
7071 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+ }
7382 let upperBoundInSubstr = String . Index ( utf16Offset: upperBound, in: substr)
74- return ( upperBoundInSubstr, Format . FormatInput ( clamping : Int64 ( value ) ) )
83+ return ( upperBoundInSubstr, exact )
7584 }
85+
7686 return nil
7787 }
7888}
@@ -82,8 +92,6 @@ public extension IntegerParseStrategy {
8292 init < Value> ( format: Format , lenient: Bool = true ) where Format == IntegerFormatStyle < Value > {
8393 self . formatStyle = format
8494 self . lenient = lenient
85- self . locale = format. locale
86- self . numberFormatType = . number( format. collection)
8795 }
8896}
8997
@@ -92,8 +100,6 @@ public extension IntegerParseStrategy {
92100 init < Value> ( format: Format , lenient: Bool = true ) where Format == IntegerFormatStyle < Value > . Percent {
93101 self . formatStyle = format
94102 self . lenient = lenient
95- self . locale = format. locale
96- self . numberFormatType = . percent( format. collection)
97103 }
98104}
99105
@@ -102,7 +108,5 @@ public extension IntegerParseStrategy {
102108 init < Value> ( format: Format , lenient: Bool = true ) where Format == IntegerFormatStyle < Value > . Currency {
103109 self . formatStyle = format
104110 self . lenient = lenient
105- self . locale = format. locale
106- self . numberFormatType = . currency( format. collection)
107111 }
108112}
0 commit comments