2
2
//
3
3
// This source file is part of the Swift.org open source project
4
4
//
5
- // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
5
+ // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6
6
// Licensed under Apache License v2.0 with Runtime Library Exception
7
7
//
8
- // See http ://swift.org/LICENSE.txt for license information
9
- // See http ://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8
+ // See https ://swift.org/LICENSE.txt for license information
9
+ // See https ://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
+ #if DEPLOYMENT_RUNTIME_SWIFT
13
14
import CoreFoundation
15
+ #else
16
+ @_exported import Foundation // Clang module
17
+ import _SwiftCoreFoundationOverlayShims
18
+ #endif
14
19
15
20
/// A `Measurement` is a model type that holds a `Double` value associated with a `Unit`.
16
21
///
17
22
/// Measurements support a large set of operators, including `+`, `-`, `*`, `/`, and a full set of comparison operators.
18
- public struct Measurement < UnitType : Unit > : ReferenceConvertible , Comparable , Equatable , CustomStringConvertible {
23
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
24
+ public struct Measurement < UnitType : Unit > : ReferenceConvertible , Comparable , Equatable {
19
25
public typealias ReferenceType = NSMeasurement
20
-
26
+
21
27
/// The unit component of the `Measurement`.
22
28
public let unit : UnitType
23
-
29
+
24
30
/// The value component of the `Measurement`.
25
31
public var value : Double
26
-
32
+
27
33
/// Create a `Measurement` given a specified value and unit.
28
34
public init ( value: Double , unit: UnitType ) {
29
35
self . value = value
30
36
self . unit = unit
31
37
}
32
-
38
+
33
39
public var hashValue : Int {
34
- return Int ( bitPattern: _CFHashDouble ( value) )
40
+ return Int ( bitPattern: __CFHashDouble ( value) )
35
41
}
36
-
42
+ }
43
+
44
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
45
+ extension Measurement : CustomStringConvertible , CustomDebugStringConvertible , CustomReflectable {
37
46
public var description : String {
38
47
return " \( value) \( unit. symbol) "
39
48
}
40
-
49
+
41
50
public var debugDescription : String {
42
51
return " \( value) \( unit. symbol) "
43
52
}
53
+
54
+ public var customMirror : Mirror {
55
+ var c : [ ( label: String ? , value: Any ) ] = [ ]
56
+ c. append ( ( label: " value " , value: value) )
57
+ c. append ( ( label: " unit " , value: unit. symbol) )
58
+ return Mirror ( self , children: c, displayStyle: Mirror . DisplayStyle. struct)
59
+ }
44
60
}
45
61
62
+
46
63
/// When a `Measurement` contains a `Dimension` unit, it gains the ability to convert between the kinds of units in that dimension.
64
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
47
65
extension Measurement where UnitType : Dimension {
48
66
/// Returns a new measurement created by converting to the specified unit.
49
67
///
@@ -62,7 +80,7 @@ extension Measurement where UnitType : Dimension {
62
80
}
63
81
}
64
82
}
65
-
83
+
66
84
/// Converts the measurement to the specified unit.
67
85
///
68
86
/// - parameter otherUnit: A unit of the same `Dimension`.
@@ -97,73 +115,9 @@ extension Measurement where UnitType : Dimension {
97
115
return Measurement ( value: lhsValueInTermsOfBase - rhsValueInTermsOfBase, unit: type ( of: lhs. unit) . baseUnit ( ) )
98
116
}
99
117
}
100
-
101
- /// Compare two measurements of the same `Dimension`.
102
- ///
103
- /// If `lhs.unit == rhs.unit`, returns `lhs.value == rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
104
- /// - returns: `true` if the measurements are equal.
105
- public static func == ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
106
- if lhs. unit == rhs. unit {
107
- return lhs. value == rhs. value
108
- } else {
109
- let rhsInLhs = rhs. converted ( to: lhs. unit)
110
- return lhs. value == rhsInLhs. value
111
- }
112
- }
113
-
114
- /// Compare two measurements of the same `Dimension`.
115
- ///
116
- /// If `lhs.unit == rhs.unit`, returns `lhs.value < rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
117
- /// - returns: `true` if `lhs` is less than `rhs`.
118
- public static func < ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
119
- if lhs. unit == rhs. unit {
120
- return lhs. value < rhs. value
121
- } else {
122
- let rhsInLhs = rhs. converted ( to: lhs. unit)
123
- return lhs. value < rhsInLhs. value
124
- }
125
- }
126
-
127
- /// Compare two measurements of the same `Dimension`.
128
- ///
129
- /// If `lhs.unit == rhs.unit`, returns `lhs.value > rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
130
- /// - returns: `true` if `lhs` is greater than `rhs`.
131
- public static func > ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
132
- if lhs. unit == rhs. unit {
133
- return lhs. value > rhs. value
134
- } else {
135
- let rhsInLhs = rhs. converted ( to: lhs. unit)
136
- return lhs. value > rhsInLhs. value
137
- }
138
- }
139
-
140
- /// Compare two measurements of the same `Dimension`.
141
- ///
142
- /// If `lhs.unit == rhs.unit`, returns `lhs.value < rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
143
- /// - returns: `true` if `lhs` is less than or equal to `rhs`.
144
- public static func <= ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
145
- if lhs. unit == rhs. unit {
146
- return lhs. value <= rhs. value
147
- } else {
148
- let rhsInLhs = rhs. converted ( to: lhs. unit)
149
- return lhs. value <= rhsInLhs. value
150
- }
151
- }
152
-
153
- /// Compare two measurements of the same `Dimension`.
154
- ///
155
- /// If `lhs.unit == rhs.unit`, returns `lhs.value >= rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
156
- /// - returns: `true` if `lhs` is greater or equal to `rhs`.
157
- public static func >= ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
158
- if lhs. unit == rhs. unit {
159
- return lhs. value >= rhs. value
160
- } else {
161
- let rhsInLhs = rhs. converted ( to: lhs. unit)
162
- return lhs. value >= rhsInLhs. value
163
- }
164
- }
165
118
}
166
119
120
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
167
121
extension Measurement {
168
122
/// Add two measurements of the same Unit.
169
123
/// - precondition: The `unit` of `lhs` and `rhs` must be `isEqual`.
@@ -187,6 +141,8 @@ extension Measurement {
187
141
}
188
142
}
189
143
144
+ /// Multiply a measurement by a scalar value.
145
+ /// - returns: A measurement of value `lhs.value * rhs` with the same unit as `lhs`.
190
146
public static func * ( lhs: Measurement < UnitType > , rhs: Double ) -> Measurement < UnitType > {
191
147
return Measurement ( value: lhs. value * rhs, unit: lhs. unit)
192
148
}
@@ -209,57 +165,64 @@ extension Measurement {
209
165
return Measurement ( value: lhs / rhs. value, unit: rhs. unit)
210
166
}
211
167
212
- /// Compare two measurements of the same `Unit`.
213
- /// - returns: `true` if `lhs.value == rhs.value && lhs.unit == rhs.unit`.
214
- public static func == ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
215
- return lhs. value == rhs. value && lhs. unit == rhs. unit
216
- }
217
-
218
- /// Compare two measurements of the same `Unit`.
219
- /// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
220
- /// - returns: `lhs.value < rhs.value`
221
- public static func < ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
222
- return lhs. value < rhs. value
223
- }
224
-
225
- /// Compare two measurements of the same `Unit`.
226
- /// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
227
- /// - returns: `lhs.value > rhs.value`
228
- public static func > ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
229
- return lhs. value > rhs. value
230
- }
231
-
232
- /// Compare two measurements of the same `Unit`.
233
- /// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
234
- /// - returns: `lhs.value <= rhs.value`
235
- public static func <= ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
236
- return lhs. value <= rhs. value
168
+ /// Compare two measurements of the same `Dimension`.
169
+ ///
170
+ /// If `lhs.unit == rhs.unit`, returns `lhs.value == rhs.value`. Otherwise, converts `rhs` to the same unit as `lhs` and then compares the resulting values.
171
+ /// - returns: `true` if the measurements are equal.
172
+ public static func == < LeftHandSideType, RightHandSideType> ( _ lhs: Measurement < LeftHandSideType > , _ rhs: Measurement < RightHandSideType > ) -> Bool {
173
+ if lhs. unit == rhs. unit {
174
+ return lhs. value == rhs. value
175
+ } else {
176
+ if let lhsDimensionalUnit = lhs. unit as? Dimension ,
177
+ let rhsDimensionalUnit = rhs. unit as? Dimension {
178
+ if type ( of: lhsDimensionalUnit) . baseUnit ( ) == type ( of: rhsDimensionalUnit) . baseUnit ( ) {
179
+ let lhsValueInTermsOfBase = lhsDimensionalUnit. converter. baseUnitValue ( fromValue: lhs. value)
180
+ let rhsValueInTermsOfBase = rhsDimensionalUnit. converter. baseUnitValue ( fromValue: rhs. value)
181
+ return lhsValueInTermsOfBase == rhsValueInTermsOfBase
182
+ }
183
+ }
184
+ return false
185
+ }
237
186
}
238
187
239
188
/// Compare two measurements of the same `Unit`.
240
- /// - note: This function does not check `==` for the `unit` property of `lhs` and `rhs`.
241
- /// - returns: `lhs.value >= rhs.value`
242
- public static func >= ( lhs: Measurement < UnitType > , rhs: Measurement < UnitType > ) -> Bool {
243
- return lhs. value >= rhs. value
189
+ /// - returns: `true` if the measurements can be compared and the `lhs` is less than the `rhs` converted value.
190
+ public static func <<LeftHandSideType, RightHandSideType> ( lhs: Measurement < LeftHandSideType > , rhs: Measurement < RightHandSideType > ) -> Bool {
191
+ if lhs. unit == rhs. unit {
192
+ return lhs. value < rhs. value
193
+ } else {
194
+ if let lhsDimensionalUnit = lhs. unit as? Dimension ,
195
+ let rhsDimensionalUnit = rhs. unit as? Dimension {
196
+ if type ( of: lhsDimensionalUnit) . baseUnit ( ) == type ( of: rhsDimensionalUnit) . baseUnit ( ) {
197
+ let lhsValueInTermsOfBase = lhsDimensionalUnit. converter. baseUnitValue ( fromValue: lhs. value)
198
+ let rhsValueInTermsOfBase = rhsDimensionalUnit. converter. baseUnitValue ( fromValue: rhs. value)
199
+ return lhsValueInTermsOfBase < rhsValueInTermsOfBase
200
+ }
201
+ }
202
+ fatalError ( " Attempt to compare measurements with non-equal dimensions " )
203
+ }
244
204
}
245
205
}
246
206
247
207
// Implementation note: similar to NSArray, NSDictionary, etc., NSMeasurement's import as an ObjC generic type is suppressed by the importer. Eventually we will need a more general purpose mechanism to correctly import generic types.
248
208
249
- extension Measurement : _ObjectTypeBridgeable {
250
- public static func _isBridgedToObjectiveC( ) -> Bool {
251
- return true
252
- }
253
-
209
+ #if DEPLOYMENT_RUNTIME_SWIFT
210
+ internal typealias MeasurementBridgeType = _ObjectTypeBridgeable
211
+ #else
212
+ internal typealias MeasurementBridgeType = _ObjectiveCBridgeable
213
+ #endif
214
+
215
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
216
+ extension Measurement : MeasurementBridgeType {
254
217
@_semantics ( " convertToObjectiveC " )
255
218
public func _bridgeToObjectiveC( ) -> NSMeasurement {
256
219
return NSMeasurement ( doubleValue: value, unit: unit)
257
220
}
258
-
221
+
259
222
public static func _forceBridgeFromObjectiveC( _ source: NSMeasurement , result: inout Measurement ? ) {
260
223
result = Measurement ( value: source. doubleValue, unit: source. unit as! UnitType )
261
224
}
262
-
225
+
263
226
public static func _conditionallyBridgeFromObjectiveC( _ source: NSMeasurement , result: inout Measurement ? ) -> Bool {
264
227
if let u = source. unit as? UnitType {
265
228
result = Measurement ( value: source. doubleValue, unit: u)
@@ -268,13 +231,53 @@ extension Measurement : _ObjectTypeBridgeable {
268
231
return false
269
232
}
270
233
}
271
-
234
+
272
235
public static func _unconditionallyBridgeFromObjectiveC( _ source: NSMeasurement ? ) -> Measurement {
273
236
let u = source!. unit as! UnitType
274
237
return Measurement ( value: source!. doubleValue, unit: u)
275
238
}
276
239
}
277
240
241
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
242
+ extension NSMeasurement : _HasCustomAnyHashableRepresentation {
243
+ // Must be @nonobjc to avoid infinite recursion during bridging.
244
+ @nonobjc
245
+ public func _toCustomAnyHashable( ) -> AnyHashable ? {
246
+ #if DEPLOYMENT_RUNTIME_SWIFT
247
+ return AnyHashable ( Measurement . _unconditionallyBridgeFromObjectiveC ( self ) )
248
+ #else
249
+ return AnyHashable ( self as Measurement )
250
+ #endif
251
+ }
252
+ }
253
+
254
+ // This workaround is required for the time being, because Swift doesn't support covariance for Measurement (26607639)
255
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
256
+ extension MeasurementFormatter {
257
+ public func string< UnitType> ( from measurement: Measurement < UnitType > ) -> String {
258
+ if let result = string ( for: measurement) {
259
+ return result
260
+ } else {
261
+ return " "
262
+ }
263
+ }
264
+ }
265
+
266
+ // @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)
267
+ // extension Unit : Codable {
268
+ // public convenience init(from decoder: Decoder) throws {
269
+ // let container = try decoder.singleValueContainer()
270
+ // let symbol = try container.decode(String.self)
271
+ // self.init(symbol: symbol)
272
+ // }
273
+
274
+ // public func encode(to encoder: Encoder) throws {
275
+ // var container = encoder.singleValueContainer()
276
+ // try container.encode(self.symbol)
277
+ // }
278
+ // }
279
+
280
+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
278
281
extension Measurement : Codable {
279
282
private enum CodingKeys : Int , CodingKey {
280
283
case value
0 commit comments