22//
33// This source file is part of the Swift.org open source project
44//
5- // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
5+ // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
66// Licensed under Apache License v2.0 with Runtime Library Exception
77//
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
1010//
1111//===----------------------------------------------------------------------===//
1212
13+ #if DEPLOYMENT_RUNTIME_SWIFT
1314import CoreFoundation
15+ #else
16+ @_exported import Foundation // Clang module
17+ import _SwiftCoreFoundationOverlayShims
18+ #endif
1419
1520/// A `Measurement` is a model type that holds a `Double` value associated with a `Unit`.
1621///
1722/// 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 {
1925 public typealias ReferenceType = NSMeasurement
20-
26+
2127 /// The unit component of the `Measurement`.
2228 public let unit : UnitType
23-
29+
2430 /// The value component of the `Measurement`.
2531 public var value : Double
26-
32+
2733 /// Create a `Measurement` given a specified value and unit.
2834 public init ( value: Double , unit: UnitType ) {
2935 self . value = value
3036 self . unit = unit
3137 }
32-
38+
3339 public var hashValue : Int {
34- return Int ( bitPattern: _CFHashDouble ( value) )
40+ return Int ( bitPattern: __CFHashDouble ( value) )
3541 }
36-
42+ }
43+
44+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
45+ extension Measurement : CustomStringConvertible , CustomDebugStringConvertible , CustomReflectable {
3746 public var description : String {
3847 return " \( value) \( unit. symbol) "
3948 }
40-
49+
4150 public var debugDescription : String {
4251 return " \( value) \( unit. symbol) "
4352 }
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+ }
4460}
4561
62+
4663/// 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 , * )
4765extension Measurement where UnitType : Dimension {
4866 /// Returns a new measurement created by converting to the specified unit.
4967 ///
@@ -62,7 +80,7 @@ extension Measurement where UnitType : Dimension {
6280 }
6381 }
6482 }
65-
83+
6684 /// Converts the measurement to the specified unit.
6785 ///
6886 /// - parameter otherUnit: A unit of the same `Dimension`.
@@ -97,73 +115,9 @@ extension Measurement where UnitType : Dimension {
97115 return Measurement ( value: lhsValueInTermsOfBase - rhsValueInTermsOfBase, unit: type ( of: lhs. unit) . baseUnit ( ) )
98116 }
99117 }
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- }
165118}
166119
120+ @available ( OSX 10 . 12 , iOS 10 . 0 , watchOS 3 . 0 , tvOS 10 . 0 , * )
167121extension Measurement {
168122 /// Add two measurements of the same Unit.
169123 /// - precondition: The `unit` of `lhs` and `rhs` must be `isEqual`.
@@ -187,6 +141,8 @@ extension Measurement {
187141 }
188142 }
189143
144+ /// Multiply a measurement by a scalar value.
145+ /// - returns: A measurement of value `lhs.value * rhs` with the same unit as `lhs`.
190146 public static func * ( lhs: Measurement < UnitType > , rhs: Double ) -> Measurement < UnitType > {
191147 return Measurement ( value: lhs. value * rhs, unit: lhs. unit)
192148 }
@@ -209,57 +165,64 @@ extension Measurement {
209165 return Measurement ( value: lhs / rhs. value, unit: rhs. unit)
210166 }
211167
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+ }
237186 }
238187
239188 /// 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+ }
244204 }
245205}
246206
247207// 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.
248208
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 {
254217 @_semantics ( " convertToObjectiveC " )
255218 public func _bridgeToObjectiveC( ) -> NSMeasurement {
256219 return NSMeasurement ( doubleValue: value, unit: unit)
257220 }
258-
221+
259222 public static func _forceBridgeFromObjectiveC( _ source: NSMeasurement , result: inout Measurement ? ) {
260223 result = Measurement ( value: source. doubleValue, unit: source. unit as! UnitType )
261224 }
262-
225+
263226 public static func _conditionallyBridgeFromObjectiveC( _ source: NSMeasurement , result: inout Measurement ? ) -> Bool {
264227 if let u = source. unit as? UnitType {
265228 result = Measurement ( value: source. doubleValue, unit: u)
@@ -268,13 +231,53 @@ extension Measurement : _ObjectTypeBridgeable {
268231 return false
269232 }
270233 }
271-
234+
272235 public static func _unconditionallyBridgeFromObjectiveC( _ source: NSMeasurement ? ) -> Measurement {
273236 let u = source!. unit as! UnitType
274237 return Measurement ( value: source!. doubleValue, unit: u)
275238 }
276239}
277240
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 , * )
278281extension Measurement : Codable {
279282 private enum CodingKeys : Int , CodingKey {
280283 case value
0 commit comments