Last active
April 10, 2019 12:11
-
-
Save st-small/866d701c988158b976c7409ceebd31b0 to your computer and use it in GitHub Desktop.
Phantom types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
protocol Currency { | |
static var code: String { get } | |
static var factor: NSDecimalNumber { get } | |
} | |
enum USD: Currency { | |
static let code = "USD" | |
static let factor: NSDecimalNumber = 1.0 | |
} | |
enum RUB: Currency { | |
static let code = "RUB" | |
static let factor: NSDecimalNumber = 65.74 | |
} | |
enum UAH: Currency { | |
static let code = "UAH" | |
static let factor: NSDecimalNumber = 26.95 | |
} | |
struct Money<Cur: Currency>: CustomStringConvertible, ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral { | |
let amount: NSDecimalNumber | |
var description: String { | |
let f = NumberFormatter() | |
f.numberStyle = .currency | |
f.currencyCode = Cur.code | |
return f.string(from: self.amount)! | |
} | |
init(floatLiteral value: Double) { | |
self.amount = NSDecimalNumber(value: value) | |
} | |
init(integerLiteral value: Int) { | |
self.amount = NSDecimalNumber(value: value) | |
} | |
init(_ amount: NSDecimalNumber) { | |
self.amount = amount | |
} | |
func convertTo<C: Currency>() -> Money<C> { | |
let baseAmount = amount.multiplying(by: Cur.factor) | |
let convertedAmount = baseAmount.multiplying(by: C.factor) | |
return Money<C>(convertedAmount) | |
} | |
} | |
extension Money { | |
var usd: Money<USD> { return convertTo() } | |
var rub: Money<RUB> { return convertTo() } | |
var uah: Money<UAH> { return convertTo() } | |
} | |
// Usage | |
let cocaCola: Money<USD> = 2.44 | |
print(cocaCola.usd) | |
print(cocaCola.rub) | |
print(cocaCola.uah) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment